HTML5 Safari transmisión en vivo vs no

Intento incrustar un elemento de audio HTML5 que apunta a datos MP3 o OGG servidos por un archivo PHP. Cuando veo la página en Safari, aparecen los controles, pero la interfaz de usuario dice “Transmisión en vivo”. Cuando hago clic en reproducir, el audio comienza como se esperaba. Sin embargo, una vez que termina, no puedo comenzar a reproducir de nuevo haciendo clic en reproducir. Incluso el uso de la API JS en el elemento de audio y la configuración de currentTime en 0 falla con una excepción de error de índice.

Sospeché que los encabezados del script PHP eran el problema, especialmente faltando una longitud de contenido. Pero ese no es el caso. Los encabezados de respuesta incluyen una longitud de contenido adecuada para indicar que el audio tiene un tamaño finito. Además, todo funciona como se espera en Firefox 3.5+. Puedo hacer clic en reproducir en el elemento de audio varias veces para escuchar la reproducción del sonido.

Si elimino el script PHP de la ecuación y presento una copia estática del archivo MP3, todo funciona bien en Safari.

¿Significa esto que Safari está tratando URLs de audio src con parámetros de consulta de manera diferente que las URL que no las tienen? ¿Alguien tiene algo de suerte para que esto funcione?

Mi página de ejemplo simple es:

       

Encabezados HTTP de script PHP:

 HTTP/1.x 200 OK Date: Sun, 03 Jan 2010 15:39:34 GMT Server: Apache X-Powered-By: PHP/5.2.10 Content-Length: 8993 Keep-Alive: timeout=2, max=98 Connection: Keep-Alive Content-Type: audio/mpeg 

Encabezados HTTP del acceso directo a archivos:

 HTTP/1.x 200 OK Date: Sun, 03 Jan 2010 20:06:59 GMT Server: Apache Last-Modified: Sun, 03 Jan 2010 03:20:02 GMT Etag: "a404b-c3f-47c3a14937c80" Accept-Ranges: bytes Content-Length: 8993 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: audio/mpeg 

Traté de codificar el encabezado Aceptar rangos en el guión también, pero no tuve suerte.

¿Puedes publicar los encabezados enviados por el servidor con y sin el script PHP? Me pregunto si la secuencia de comandos PHP está enviando un Content-Type de Content-Type diferente Content-Type que se usa normalmente.

También sería una buena idea especificar el atributo de type en los elementos source , por lo que el navegador no tiene que descargar ambos clips para determinar si puede reproducirlos.

No puedo reproducir tu problema. Intenté recrear el problema en Safari 4.0.4 y el WebKit actual cada noche, con la siguiente página de prueba . Simplemente estoy usando mod_rewrite para enviar a diferentes formatos basados ​​en un parámetro en lugar de PHP, pero no creo que eso haga la diferencia, a menos que de alguna manera PHP esté modificando el archivo.

  Auido test  

¿Puedes probar mi ejemplo y decirme si funciona para ti?

editar Ah. Después de hurgar un poco más, parece que el problema se debe a una forma extraña en que el elemento en Safari se comporta al intentar determinar el tamaño del contenido.

Aquí hay un extracto de una captura de paquetes de Safari al encontrar un elemento que apunta a un archivo servido directamente desde Apache. Como puede ver, primero intenta buscar los primeros dos bytes del medio, presumiblemente para que pueda recuperar una longitud de contenido, y posiblemente otros encabezados. Luego intenta buscar todo. Luego, de forma inexplicable, intenta recuperar los dos primeros bytes nuevamente, pero pasa los encabezados de almacenamiento en caché correspondientes para obtener una respuesta “304 no modificada”. Y finalmente, aún inexplicablemente, recupera los últimos 3440 bytes del archivo de nuevo. Hace todo esto en conexiones TCP separadas, lo que agrega una sobrecarga considerable, además de la sobrecarga de recuperar los datos un par de veces.

 GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1
 Anfitrión: ephemera.continuation.org
 Rango: bytes = 0-1
 Conexión: cerrar
 User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
 Aceptar: * / *
 Aceptar-Codificar: identidad
 Cookie: [redactado]

 HTTP / 1.1 206 Parcial Content
 Fecha: martes, 05 de enero de 2010 02:12:48 GMT
 Servidor: Apache
 Última modificación: mar, 05 ene 2010 02:02:08 GMT
 ETag: "b2a80ad-11f6-47c6139aaa800"
 Rangos de aceptación: bytes
 Longitud del contenido: 2
 Rango de contenido: bytes 0-1 / 4598
 Conexión: cerrar
 Tipo de contenido: audio / mpeg

 # 2 bytes de datos

 GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1
 Anfitrión: ephemera.continuation.org
 Rango: bytes = 0-4597
 Conexión: cerrar
 User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
 Aceptar: * / *
 Aceptar-Codificar: identidad
 Cookie: [redactado]

 HTTP / 1.1 206 Parcial Content
 Fecha: martes, 05 de enero de 2010 02:12:48 GMT
 Servidor: Apache
 Última modificación: mar, 05 ene 2010 02:02:08 GMT
 ETag: "b2a80ad-11f6-47c6139aaa800"
 Rangos de aceptación: bytes
 Longitud del contenido: 4598
 Rango de contenido: bytes 0-4597 / 4598
 Conexión: cerrar
 Tipo de contenido: audio / mpeg

 # 4598 bytes de datos

 GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1
 Anfitrión: ephemera.continuation.org
 Rango: bytes = 0-1
 Conexión: cerrar
 User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
 Aceptar: * / *
 Aceptar-Codificar: identidad
 Cookie: [redactado]
 If-None-Match: "b2a80ad-11f6-47c6139aaa800"
 Si-Modificado-Desde: martes, 05 de enero de 2010 02:02:08 GMT

 HTTP / 1.1 304 no modificado
 Fecha: martes, 05 de enero de 2010 02:12:49 GMT
 Servidor: Apache
 Conexión: cerrar
 ETag: "b2a80ad-11f6-47c6139aaa800"

 # sin datos

 GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1
 Anfitrión: ephemera.continuation.org
 Rango: bytes = 1158-4597
 Conexión: cerrar
 User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
 Aceptar: * / *
 Aceptar-Codificar: identidad
 Cookie: [redactado]

 HTTP / 1.1 206 Parcial Content
 Fecha: martes, 05 de enero de 2010 02:12:49 GMT
 Servidor: Apache
 Última modificación: mar, 05 ene 2010 02:02:08 GMT
 ETag: "b2a80ad-11f6-47c6139aaa800"
 Rangos de aceptación: bytes
 Longitud del contenido: 3440
 Rango de contenido: bytes 1158-4597 / 4598
 Conexión: cerrar
 Tipo de contenido: audio / mpeg

 # 3440 bytes de datos

De todos modos, sobre cómo se trata con el resultado de su script PHP. Aquí, Safari nuevamente intenta descargar los dos primeros bytes, pero su script ignora la solicitud de Range y lo devuelve todo. Aparentemente, a WebKit no le gusta eso, y lo intenta de nuevo, sin la solicitud de Range . Nuevamente, su secuencia de comandos envía el contenido completo. Safari ahora intenta una vez más, agregando un encabezado Icy-Metadata , que indica que cree que está descargando una transmisión y quiere que se envíen los metadatos. Finalmente acepta el resultado de eso, y el elemento puede reproducirse.

 GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP / 1.1
 Anfitrión: tts.mindtrove.info
 Rango: bytes = 0-1
 Conexión: cerrar
 User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
 Aceptar: * / *
 Aceptar-Codificar: identidad

 HTTP / 1.1 200 OK
 Fecha: martes, 05 de enero de 2010, 02:14:28 GMT
 Servidor: Apache
 X-Powered-By: PHP / 5.2.10
 Longitud del contenido: 4598
 Conexión: cerrar
 Tipo de contenido: audio / mpeg

 # 4598 bytes de datos

 GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP / 1.1
 Anfitrión: tts.mindtrove.info
 Conexión: cerrar
 User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
 Aceptar: * / *

 HTTP / 1.1 200 OK
 Fecha: martes, 05 de enero de 2010, 02:14:28 GMT
 Servidor: Apache
 X-Powered-By: PHP / 5.2.10
 Longitud del contenido: 4598
 Conexión: cerrar
 Tipo de contenido: audio / mpeg

 # 4598 bytes de datos

 GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP / 1.1
 Anfitrión: tts.mindtrove.info
 Aceptar: * / *
 User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540
 Icy-Metadata: 1
 Conexión: cerrar

 HTTP / 1.1 200 OK
 Fecha: martes, 05 de enero de 2010, 02:14:28 GMT
 Servidor: Apache
 X-Powered-By: PHP / 5.2.10
 Longitud del contenido: 4598
 Conexión: cerrar
 Tipo de contenido: audio / mpeg

 # 4598 bytes de datos

En resumen, parece que Safari (o más exactamente, QuickTime, que Safari usa para manejar todos los medios y la descarga de medios) tiene un enfoque completamente dañado para la descarga de medios. Algo en la forma en que envía sus datos, probablemente el hecho de que no responda a las solicitudes de Range , hace pensar que está enviando medios de transmisión, lo que hace que descargue el contenido repetidamente (aunque incluso cuando se enfrenta con un servidor que lo hace) responder a una solicitud de Range , aún hace varias solicitudes más de las que realmente necesita).

Mi consejo sería tratar de responder adecuadamente a las solicitudes de Range ; cuando se publican medios, es probable que los navegadores los usen para tratar de minimizar el ancho de banda, almacenando en el búfer todo lo que necesitan para jugar (aunque tienen el atributo de autobuffer que indica que les gustaría almacenar todo, navegadores) puede ignorar eso). Recomendaría usar X-Sendfile para permitir que Apache se X-Sendfile de servir el archivo, el caché y las solicitudes de rango, pero parece que está en Dreamhost, que no tiene instalado el mod_xsendfile , por lo que mod_xsendfile instalar su propio Range manejo.

Para el registro, aunque tanto Pochang como Chris tienen razón en que necesita el encabezado Content-Range para solucionar este problema en Safari, Chrome requiere un encabezado adicional que debe incluirse para configurar el modo actual para que funcione correctamente:

 header( 'Accept-Ranges: bytes'); 

Tenga en cuenta que en realidad no tiene que responder correctamente al encabezado Rango de la solicitud, solo tiene que incluir esto en la respuesta.

Tengo el mismo problema. El punto clave es el encabezado Content-Range . Todo funciona bien después de que lo agregue a la salida php mp3.

Pochang es correcto. Incluir un encabezado Content-Range en la respuesta de PHP hará que Safari se comporte correctamente. También permite buscar (media.currentTime = 0;) sin el temido INDEX_SIZE_ERR en Safari, aunque no en Chrome.

El código PHP para el encabezado es:

 $len = strlen( $data ); $shortlen = $length - 1; header( 'Content-Range: bytes 0-'.$shortlen.'/'.$len);