php - El audio HTML5 dice "transmisión en vivo" en iOS cuando es un archivo estático




laravel (2)

Los archivos MP3 no tienen marcas de tiempo y, por lo tanto, ninguna longitud inherente que se pueda conocer de antemano. Chrome solo está adivinando, según la tasa de bits al principio del archivo y el tamaño de byte del archivo. Realmente no lo sabe.

Algunos jugadores no se molestan en adivinar.

Además, todos los navegadores en iOS son Safari bajo el capó, gracias a algunas políticas increíblemente restrictivas de Apple. Por lo tanto, Chrome en iOS es realmente un contenedor para una vista web de Safari.

Para Windows Chrome (y probablemente muchos otros navegadores), este código funciona para servir un mp3 en un elemento de 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;
}

Pero cuando uso un iPhone para navegar a la misma página, el archivo mp3 no muestra la duración total, y cuando lo reproduzco, dice "Transmisión en vivo".

He intentado seguir las sugerencias de varias respuestas de esta pregunta ( HTML5 <audio> Safari live broadcast vs no ) y otros artículos que he leído, pero ninguno parece tener un efecto.

No importa cómo cambie los encabezados, el mp3 parece funcionar como se desea en Windows y no funciona en iOS.

¿Cómo puedo depurar lo que estoy haciendo mal?

Aquí está el 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>

Whoa, ese era un problema muy difícil de resolver. (Me tomó días.)

Y me enteré de que no era solo iOS lo que estaba teniendo problemas: Safari en Mac tampoco había funcionado.

Ahora creo que todo funciona en todos los navegadores que he probado.

Estoy muy contento de haber encontrado este ejemplo a seguir.

Aquí está mi respuesta:

/**
 * 
 * @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://.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://.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;
}






audio