Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
audio.php
1<?php
10
16
21class Audio
22{
23 const AUDIO_TYPE_PRESET = 'preset';
24 const AUDIO_TYPE_FILE = 'file';
25
27 private $fileId = '';
28
30 private $presetName = '';
31
33 private $messageCode = '';
34
35 private $duration;
41 public static function create()
42 {
43 return new static();
44 }
45
49 public function __construct()
50 {
51 }
52
59 public function withValue($value)
60 {
61 if ($value)
62 {
63 if (intval($value) > 0)
64 {
65 $this->withFile($value);
66 }
67 else
68 {
69 $this->withPreset($value);
70 }
71 }
72 return $this;
73 }
74
81 public function withJsonString($json)
82 {
83 if($json <> '')
84 {
85 try
86 {
87 $params = Json::decode($json);
88 if($params['type'] == self::AUDIO_TYPE_PRESET)
89 {
90 $this->withPreset($params['preset']);
91 }
92 if($params['type'] == self::AUDIO_TYPE_FILE)
93 {
94 $this->withFile($params['fileId']);
95 }
96 if($params['duration'])
97 {
98 $this->duration = $params['duration'];
99 }
100 }
101 catch(ArgumentException $e)
102 {
103 }
104 }
105 return $this;
106 }
107
114 public function withMessageCode($messageCode = null)
115 {
116
117 $this->messageCode = $messageCode;
118 return $this;
119 }
120
127 public function withFile($fileId = null)
128 {
129
130 $this->fileId = $fileId;
131 return $this;
132 }
133
140 public function withPreset($presetName = null)
141 {
142 $this->presetName = $presetName;
143 return $this;
144 }
145
151 public function createdFromPreset()
152 {
153 return !!$this->presetName;
154 }
155
163 public function getFileUrl($useAbsoluteUrl = false)
164 {
165 if ($this->createdFromPreset())
166 {
167 $url = AudioCall::getAudioFileUrlByCode($this->getPresetCode());
168 }
169 else
170 {
171 $url = \CFile::GetPath($this->getFileId());
172 if ($url && $useAbsoluteUrl && !$this->isRemoteFile($url))
173 {
174 $urlManager = \Bitrix\Main\Engine\UrlManager::getInstance();
175 $url = $urlManager->getHostUrl() . $url;
176 }
177 }
178
179 return $url;
180 }
181
187 public function getDbValue()
188 {
189 if (!$this->getFileId() && !$this->getPreset())
190 {
191 return false;
192 }
193 $result = [
195 'duration' => $this->getDuration()
196 ];
197 if ($this->createdFromPreset())
198 {
199 $result['preset'] = $this->getPreset();
200 }
201 else
202 {
203 $result['fileId'] = $this->getFileId();
204 }
205 return Json::encode($result);
206 }
207
212 public function getDefaultFileUrl()
213 {
216 }
217
222 public function getFileId()
223 {
224 return $this->fileId;
225 }
226
231 public function getPreset()
232 {
233 return $this->presetName;
234 }
235
240 public function getMessageCode()
241 {
242 return $this->messageCode;
243 }
244
249 public function getDuration()
250 {
251 if (!$this->duration)
252 {
253 if ($this->createdFromPreset())
254 {
255 $this->duration = $this->getPresetFileDuration($this->getPresetCode());
256 }
257 else
258 {
259 $this->duration = $this->getMp3fileDuration($this->getFileId());
260 }
261 }
262 return $this->duration;
263 }
264
270 protected function getPresetFileDuration($presetCode)
271 {
272 return AudioCall::getDurationByCode($presetCode);
273 }
274
279 private function getPresetCode()
280 {
281 return mb_strpos($this->getPreset(), $this->getMessageCode()) === 0?
282 mb_substr($this->getPreset(), mb_strlen($this->getMessageCode()) + 1) : $this->getPreset();
283 }
284
290 protected function getMp3fileDuration($fileId)
291 {
292 if (!$fileId)
293 return false;
294
295 $fileName = \CFile::GetPath($fileId);
296
297 if ($this->isRemoteFile($fileName))
298 {
299 $tmpFileName = \CFile::GetTempName('', 'tmpfile.mp3');
300 $request = new HttpClient([
301 "socketTimeout" => 5,
302 "streamTimeout" => 5
303 ]);
304 $request->download($fileName, $tmpFileName);
305 $fileName = $tmpFileName;
306 }
307 else
308 {
309 $fileName = Application::getDocumentRoot() . $fileName;
310 }
311
312 $file = fopen($fileName, "rb");
313
314 $duration = 0;
315 $header = fread($file, 100);
316 $offset = $this->getId3v2TagLength($header);
317 fseek($file, $offset, SEEK_SET);
318 while (!feof($file))
319 {
320 $frame = fread($file, 10);
321 if (mb_strlen($frame, 'latin1') < 10)
322 {
323 break;
324 }
325 else
326 {
327 if ("\xff" == $frame[0] && (ord($frame[1]) & 0xe0)) // if 1111 1111 111x xxxx bits (header sequence) was found
328 {
329 list($frameLength, $frameDuration) = $this->getFrameInfo(mb_substr($frame, 0, 4, 'latin1'));
330 if (!$frameLength)
331 {
332 return $duration;
333 }
334 $offset = $frameLength - 10;
335 $duration += $frameDuration;
336 }
337 else
338 {
339 $offset = ('TAG' == mb_substr($frame, 0, 3, 'latin1')) ? 118 : -9;
340 }
341 fseek($file, $offset, SEEK_CUR);
342 }
343 }
344 return round($duration);
345 }
346
352 private function getId3v2TagLength($header)
353 {
354 if ("ID3" == mb_substr($header, 0, 3, 'latin1'))
355 {
356 $hasExtendedHeader = (ord($header[5]) & 0x10) ? 1 : 0;
357 $lengthByte1 = ord($header[6]);
358 $lengthByte2 = ord($header[7]);
359 $lengthByte3 = ord($header[8]);
360 $lengthByte4 = ord($header[9]);
361 if (!($lengthByte1 & 0x80) && !($lengthByte2 & 0x80) && !($lengthByte3 & 0x80) && !($lengthByte4 & 0x80))
362 {
363 $tagHeaderLength = 10 + ($hasExtendedHeader ? 10 : 0);
364 $tagContentLength =
365 (($lengthByte1 & 0x7f) << 21) +
366 (($lengthByte2 & 0x7f) << 14) +
367 (($lengthByte3 & 0x7f) << 7) +
368 ($lengthByte4 & 0x7f);
369
370 return $tagHeaderLength + $tagContentLength;
371 }
372 }
373 return 0;
374 }
375
381 private function getFrameInfo($frame)
382 {
383 $versions = [0 => '2.5', 2 => '2', 3 => '1'];
384 $layers = [1 => '3', 2 => '2', 3 => '1'];
385 $bitrates = [
386 1 => [
387 1 => [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448],
388 2 => [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384],
389 3 => [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]
390 ],
391 2 => [
392 1 => [0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256],
393 2 => [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160],
394 3 => [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160],
395 ]
396 ];
397 $sampleRates = [
398 '1' => [44100, 48000, 32000],
399 '2' => [22050, 24000, 16000],
400 '2.5' => [11025, 12000, 8000]
401 ];
402 $samples = [
403 1 => [1 => 384, 2 => 1152, 3 => 1152],
404 2 => [1 => 384, 2 => 1152, 3 => 576]
405 ];
406
407 $layerData = ord($frame[1]);
408 $rateData = ord($frame[2]);
409
410 $version = $versions[($layerData & 0x18) >> 3];
411 $bitrateVersion = ($version == '2.5' ? 2 : $version);
412
413 $layer = $layers[($layerData & 0x06) >> 1];
414
415 $bitrateIndex = ($rateData & 0xf0) >> 4;
416 $bitrate = $bitrates[$bitrateVersion][$layer][$bitrateIndex] ?: 0;
417
418 $sampleRateIndex = ($rateData & 0x0c) >> 2;//0xc => b1100
419 $sampleRate = $sampleRates[$version][$sampleRateIndex] ?: 0;
420 $padding = ($rateData & 0x02) >> 1;
421
422 if ($sampleRate <> 0)
423 {
424 $duration = $samples[$bitrateVersion][$layer] / $sampleRate;
425 }
426
427 if ($layer == 1)
428 {
429 $frameLength = intval(((12 * $bitrate * 1000 / $sampleRate) + $padding) * 4);
430 }
431 else
432 {
433 $frameLength = intval(((144 * $bitrate * 1000) / $sampleRate) + $padding);
434 }
435
436 return [$frameLength, $duration ?? 0];
437 }
438
444 private function isRemoteFile($fileName)
445 {
446 return preg_match('/^(https?):\/\/.*/', $fileName) === 1;
447 }
448}
getFileUrl($useAbsoluteUrl=false)
Definition audio.php:163