Аудио HTML5 говорит, что «прямая трансляция» в iOS, когда это статический файл - PullRequest
0 голосов
/ 18 февраля 2019

Для Windows Chrome (и, возможно, многих других браузеров) этот код работает для обслуживания mp3 в элементе audio:

/**
 * 
 * @param string $filename
 * @return \Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory
 */
public function getMp3($filename) {
    $fileContents = Storage::disk(\App\Helpers\CoachingCallsHelper::DISK)->get($filename);
    $fileSize = Storage::disk(\App\Helpers\CoachingCallsHelper::DISK)->size($filename);
    $shortlen = $fileSize - 1;
    $headers = [
        'Accept-Ranges' => 'bytes',
        'Content-Range' => 'bytes 0-' . $shortlen . '/' . $fileSize,
        'Content-Type' => "audio/mpeg"
    ];
    Log::debug('$headers=' . json_encode($headers));
    $response = response($fileContents, 200, $headers);
    return $response;
}

Но когда я использую iPhone для перехода на ту же страницу,mp3-файл не показывает общую продолжительность, и когда я его воспроизводю, он говорит «Прямая трансляция».

Я пытался следовать предложениям из различных ответов на этот вопрос ( HTML5 Прямая трансляция Safari против ) и других статей, которые я читал, но, похоже, ни одна из них не дает никакого эффекта.

Независимо от того, как я изменяю заголовки, кажется, что mp3 работает в Windows должным образом и работает не работает на iOS.

Как мне отладить то, что я делаю неправильно?

Вот HTML:

<audio controls preload="auto">
    <source src="{{$coachingCall->getMp3Url()}}" type="audio/mpeg"/>
    <p>Your browser doesnt support embedded HTML5 audio. Here is a <a href="{{$coachingCall->getMp3Url()}}">link to the audio</a> instead.</p>
</audio>

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Ого, это была очень сложная проблема.(Это заняло у меня несколько дней.)

И я узнал, что проблемы были не только с iOS: Safari на Mac тоже не работал.

Теперь я думаю, что все работает на каждом браузере, который я тестировал.

Я действительно рад, что нашел этот пример для подражания.

Здесьмой ответ:

/**
 * 
 * @param string $disk
 * @param string $filename
 * @return \Illuminate\Http\Response|\Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\StreamedResponse
 */
public static function getMediaFile($disk, $filename) {
    $rangeHeader = request()->header('Range');
    $fileContents = Storage::disk($disk)->get($filename);
    $fullFilePath = Storage::disk($disk)->path($filename); //https://stackoverflow.com/a/49532280/470749
    $headers = ['Content-Type' => Storage::disk($disk)->mimeType($fullFilePath)];
    if ($rangeHeader) {
        return self::getResponseStream($disk, $fullFilePath, $fileContents, $rangeHeader, $headers);
    } else {
        $httpStatusCode = 200;
        return response($fileContents, $httpStatusCode, $headers);
    }
}

/**
 * 
 * @param string $disk
 * @param string $fullFilePath
 * @param string $fileContents
 * @param string $rangeRequestHeader
 * @param array  $responseHeaders
 * @return \Symfony\Component\HttpFoundation\StreamedResponse
 */
public static function getResponseStream($disk, $fullFilePath, $fileContents, $rangeRequestHeader, $responseHeaders) {
    $stream = Storage::disk($disk)->readStream($fullFilePath);
    $fileSize = strlen($fileContents);
    $fileSizeMinusOneByte = $fileSize - 1; //because it is 0-indexed. https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16
    list($param, $rangeHeader) = explode('=', $rangeRequestHeader);
    if (strtolower(trim($param)) !== 'bytes') {
        abort(400, "Invalid byte range request"); //Note, this is not how https://stackoverflow.com/a/29997555/470749 did it
    }
    list($from, $to) = explode('-', $rangeHeader);
    if ($from === '') {
        $end = $fileSizeMinusOneByte;
        $start = $end - intval($from);
    } elseif ($to === '') {
        $start = intval($from);
        $end = $fileSizeMinusOneByte;
    } else {
        $start = intval($from);
        $end = intval($to);
    }
    $length = $end - $start + 1;
    $httpStatusCode = 206;
    $responseHeaders['Content-Range'] = sprintf('bytes %d-%d/%d', $start, $end, $fileSize);
    $responseStream = response()->stream(function() use ($stream, $start, $length) {
        fseek($stream, $start, SEEK_SET);
        echo fread($stream, $length);
        fclose($stream);
    }, $httpStatusCode, $responseHeaders);
    return $responseStream;
}
0 голосов
/ 18 февраля 2019

MP3-файлы не имеют временных меток и, следовательно, не имеют внутренней длины, которую можно узнать заранее.Chrome просто догадывается, основываясь на битрейте в начале файла и его байтовом размере.На самом деле он не знает.

Некоторые игроки не гадают.

Кроме того, все браузеры на iOS - это Safari, благодаря некоторым невероятно ограничительным политикам Apple.Поэтому Chrome на iOS - это просто оболочка для веб-представления Safari.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...