Passed
Push — develop ( 02fd56...ed0c1f )
by Портнов
05:18
created

WorkerCallEvents::cleanTimeOutChannel()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 14
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 10
c 1
b 0
f 0
dl 0
loc 14
rs 9.9332
cc 3
nc 2
nop 1
1
<?php
2
/*
3
 * MikoPBX - free phone system for small business
4
 * Copyright (C) 2017-2020 Alexey Portnov and Nikolay Beketov
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with this program.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
namespace MikoPBX\Core\Workers;
21
require_once 'Globals.php';
22
23
use MikoPBX\Core\System\{BeanstalkClient, MikoPBXConfig, Storage, Util};
24
use MikoPBX\Core\Workers\Libs\WorkerCallEvents\SelectCDR;
25
use MikoPBX\Core\Workers\Libs\WorkerCallEvents\UpdateDataInDB;
26
use Phalcon\Text;
27
28
class WorkerCallEvents extends WorkerBase
29
{
30
    public    array $mixMonitorChannels = [];
31
    protected bool  $record_calls       = true;
32
    protected bool  $split_audio_thread = false;
33
    public    array $checkChanHangupTransfer = [];
34
    public const TIMOUT_CHANNEL_TUBE = 'CleanChannelTimout';
35
36
37
    /**
38
     * Инициирует запись разговора на канале.
39
     *
40
     * @param string    $channel
41
     * @param ?string   $file_name
42
     * @param ?string   $sub_dir
43
     * @param ?string   $full_name
44
     *
45
     * @return string
46
     */
47
    public function MixMonitor($channel, $file_name = null, $sub_dir = null, $full_name = null): string
48
    {
49
        $resFile = $this->mixMonitorChannels[$channel]??'';
50
        if($resFile !== ''){
51
            return $resFile;
52
        }
53
        $resFile           = '';
54
        $file_name = str_replace('/', '_', $file_name);
55
        if ($this->record_calls) {
56
            [$f, $options] = $this->setMonitorFilenameOptions($full_name, $sub_dir, $file_name);
57
            $arr = $this->am->GetChannels(false);
58
            if(!in_array($channel, $arr, true)){
59
                return '';
60
            }
61
            $srcFile = "{$f}.wav";
62
            $resFile = "{$f}.mp3";
63
            $this->am->MixMonitor($channel, $srcFile, $options);
64
            $this->mixMonitorChannels[$channel] = $resFile;
65
            $this->am->UserEvent('StartRecording', ['recordingfile' => $resFile, 'recchan' => $channel]);
66
        }
67
        return $resFile;
68
    }
69
70
    /**
71
     * @param string|null $full_name
72
     * @param string|null $sub_dir
73
     * @param string|null $file_name
74
     * @return array
75
     */
76
    public function setMonitorFilenameOptions(?string $full_name, ?string $sub_dir, ?string $file_name): array{
77
        if (!file_exists((string)$full_name)) {
78
            $monitor_dir = Storage::getMonitorDir();
79
            if ($sub_dir === null) {
80
                $sub_dir = date('Y/m/d/H/');
81
            }
82
            $f = "{$monitor_dir}/{$sub_dir}{$file_name}";
83
        } else {
84
            $f = Util::trimExtensionForFile($full_name);
85
        }
86
        if ($this->split_audio_thread) {
87
            $options = "abSr({$f}_in.wav)t({$f}_out.wav)";
88
        } else {
89
            $options = 'ab';
90
        }
91
        return array($f, $options);
92
    }
93
94
    /**
95
     * Останавливает запись разговора на канале.
96
     * @param string $channel
97
     */
98
    public function StopMixMonitor($channel): void
99
    {
100
        if(isset($this->mixMonitorChannels[$channel])){
101
            unset($this->mixMonitorChannels[$channel]);
102
        }else{
103
            return;
104
        }
105
        if ($this->record_calls) {
106
            $this->am->StopMixMonitor($channel);
107
        }
108
    }
109
110
    /**
111
     *
112
     * @param $params
113
     */
114
    public function start($params): void
115
    {
116
        $this->mixMonitorChannels       = [];
117
        $this->checkChanHangupTransfer  = [];
118
        $mikoPBXConfig            = new MikoPBXConfig();
119
        $this->record_calls       = $mikoPBXConfig->getGeneralSettings('PBXRecordCalls') === '1';
120
        $this->split_audio_thread = $mikoPBXConfig->getGeneralSettings('PBXSplitAudioThread') === '1';
121
        $this->am                 = Util::getAstManager('off');
122
123
        // PID сохраняем при начале работы Worker.
124
        $client = new BeanstalkClient(self::class);
125
        $client->subscribe(self::class, [$this, 'callEventsWorker']);
126
        $client->subscribe(WorkerCdr::SELECT_CDR_TUBE, [$this, 'selectCDRWorker']);
127
        $client->subscribe(WorkerCdr::UPDATE_CDR_TUBE, [$this, 'updateCDRWorker']);
128
        $client->subscribe(self::TIMOUT_CHANNEL_TUBE,  [$this, 'cleanTimeOutChannel']);
129
        $client->subscribe($this->makePingTubeName(self::class), [$this, 'pingCallBack']);
130
        $client->setErrorHandler([$this, 'errorHandler']);
131
132
        while ($this->needRestart === false) {
133
            $client->wait();
134
        }
135
    }
136
137
    /**
138
     * Обработчик событий изменения состояния звонка.
139
     *
140
     * @param array | BeanstalkClient $tube
141
     */
142
    public function callEventsWorker($tube): void
143
    {
144
        $data      = json_decode($tube->getBody(), true);
145
        $funcName = "Action_".$data['action']??'';
146
        if ( method_exists($this, $funcName) ) {
147
            $this->$funcName($data);
148
        }
149
        $className = __NAMESPACE__.'\Libs\WorkerCallEvents\\'.Text::camelize($funcName, '_');
150
        if( method_exists($className, 'execute') ){
151
            $className::execute($this, $data);
152
        }
153
154
        $tube->reply(json_encode(true));
155
    }
156
157
    /**
158
     * Получения CDR к обработке.
159
     *
160
     * @param array | BeanstalkClient $tube
161
     */
162
    public function updateCDRWorker($tube): void
163
    {
164
        $task    = $tube->getBody();
165
        $data = json_decode($task, true);
166
        UpdateDataInDB::execute($data);
167
        $tube->reply(json_encode(true));
168
    }
169
170
    /**
171
     * Получения CDR к обработке.
172
     *
173
     * @param array | BeanstalkClient $tube
174
     */
175
    public function cleanTimeOutChannel($tube): void
176
    {
177
        $task        = $tube->getBody();
178
        $taskData    = json_decode($task, true);
179
        $channel     = $taskData['channel']??'';
180
        $srcChannel  = $taskData['srcChannel']??'';
181
        $this->am->SetVar($channel, 'TIMEOUT(absolute)', '0');
182
        $this->am->SetVar($srcChannel, "MASTER_CHANNEL(M_DIALSTATUS)", 'ANSWER');
183
        // Перестрахова на случай с перехватом звонка через *8.
184
        $timeoutChannel = $this->am->GetVar($srcChannel, 'MASTER_CHANNEL(M_TIMEOUT_CHANNEL)', null, false);
185
        if(is_string($timeoutChannel) && !empty($timeoutChannel)){
186
            $this->am->SetVar($timeoutChannel, "TIMEOUT(absolute)", '0');
187
        }
188
        $tube->reply(json_encode(true));
189
    }
190
    /**
191
     * @param array | BeanstalkClient $tube
192
     */
193
    public function selectCDRWorker($tube): void
194
    {
195
        $filter   = json_decode($tube->getBody(), true);
196
        $res_data = SelectCDR::execute($filter);
197
        $tube->reply($res_data);
198
    }
199
200
    public function errorHandler($m): void
201
    {
202
        Util::sysLogMsg(self::class . '_ERROR', $m, LOG_ERR);
203
    }
204
}
205
206
207
// Start worker process
208
WorkerCallEvents::startWorker($argv??null);