2010-01-03 9 views
27

Estoy tratando de incrustar un elemento de audio HTML5 apuntando a datos MP3 o OG 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.HTML5 <audio> transmisión en vivo de Safari vs no

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 forma diferente que las URL que no las tienen? ¿Alguien tiene algo de suerte para que esto funcione?

Mi página de ejemplo sencillo es:

<!DOCTYPE html> 
<html> 
    <head></head> 
    <body> 
    <audio controls autobuffer> 
     <source src="say.php?text=this%20is%20a%20test&format=.ogg" /> 
     <source src="say.php?text=this%20is%20a%20test&format=.mp3" /> 
    </audio> 
    </body> 
</html> 

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 de 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é codificante El encabezado Aceptar-Rangos en el script también, pero no hubo suerte.

+0

No estoy seguro de que te notifiquen acerca de ediciones, pero he editado mi respuesta para incluir un caso de prueba que me funcione y parezca coincidir con lo que estás haciendo. ¿Puedes verificar si mi caso de prueba también funciona para ti? –

Respuesta

31

¿Se puede 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 diferente que los archivos normalmente.

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

No puedo reproducir su problema. Intenté recrear el problema en Safari 4.0.4 y el WebKit actual cada noche, con el following test page. 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.

<!DOCTYPE html> 
<title>Auido test</title> 
<audio controls autobuffer> 
    <source src="gnossienne-no-1?foo=bar&format=.mp4"> 
    <source src="gnossienne-no-1?foo=bar&format=.ogg"> 
</audio> 

¿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 <audio> en Safari se comporta al intentar determinar el tamaño del contenido.

Aquí hay un fragmento de una captura de paquetes de Safari al encontrar un elemento <audio> 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 
Host: ephemera.continuation.org 
Range: bytes=0-1 
Connection: close 
User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 
Accept: */* 
Accept-Encoding: identity 
Cookie: [redacted] 

HTTP/1.1 206 Partial Content 
Date: Tue, 05 Jan 2010 02:12:48 GMT 
Server: Apache 
Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT 
ETag: "b2a80ad-11f6-47c6139aaa800" 
Accept-Ranges: bytes 
Content-Length: 2 
Content-Range: bytes 0-1/4598 
Connection: close 
Content-Type: audio/mpeg 

# 2 bytes of data 

GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 
Host: ephemera.continuation.org 
Range: bytes=0-4597 
Connection: close 
User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 
Accept: */* 
Accept-Encoding: identity 
Cookie: [redacted] 

HTTP/1.1 206 Partial Content 
Date: Tue, 05 Jan 2010 02:12:48 GMT 
Server: Apache 
Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT 
ETag: "b2a80ad-11f6-47c6139aaa800" 
Accept-Ranges: bytes 
Content-Length: 4598 
Content-Range: bytes 0-4597/4598 
Connection: close 
Content-Type: audio/mpeg 

# 4598 bytes of data 

GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 
Host: ephemera.continuation.org 
Range: bytes=0-1 
Connection: close 
User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 
Accept: */* 
Accept-Encoding: identity 
Cookie: [redacted] 
If-None-Match: "b2a80ad-11f6-47c6139aaa800" 
If-Modified-Since: Tue, 05 Jan 2010 02:02:08 GMT 

HTTP/1.1 304 Not Modified 
Date: Tue, 05 Jan 2010 02:12:49 GMT 
Server: Apache 
Connection: close 
ETag: "b2a80ad-11f6-47c6139aaa800" 

# no data 

GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP/1.1 
Host: ephemera.continuation.org 
Range: bytes=1158-4597 
Connection: close 
User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 
Accept: */* 
Accept-Encoding: identity 
Cookie: [redacted] 

HTTP/1.1 206 Partial Content 
Date: Tue, 05 Jan 2010 02:12:49 GMT 
Server: Apache 
Last-Modified: Tue, 05 Jan 2010 02:02:08 GMT 
ETag: "b2a80ad-11f6-47c6139aaa800" 
Accept-Ranges: bytes 
Content-Length: 3440 
Content-Range: bytes 1158-4597/4598 
Connection: close 
Content-Type: audio/mpeg 

# 3440 bytes of data 

De todos modos, en cómo se trata de la salida de su script PHP. Aquí, Safari nuevamente intenta descargar los primeros dos bytes, pero su script ignora la solicitud Range y lo devuelve todo. Aparentemente, a WebKit no le gusta eso, y lo intenta de nuevo, sin la solicitud 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 la salida de eso, y el elemento <audio> puede jugar.

 
GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 
Host: tts.mindtrove.info 
Range: bytes=0-1 
Connection: close 
User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 
Accept: */* 
Accept-Encoding: identity 

HTTP/1.1 200 OK 
Date: Tue, 05 Jan 2010 02:14:28 GMT 
Server: Apache 
X-Powered-By: PHP/5.2.10 
Content-Length: 4598 
Connection: close 
Content-Type: audio/mpeg 

# 4598 bytes of data 

GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP/1.1 
Host: tts.mindtrove.info 
Connection: close 
User-Agent: Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540 
Accept: */* 

HTTP/1.1 200 OK 
Date: Tue, 05 Jan 2010 02:14:28 GMT 
Server: Apache 
X-Powered-By: PHP/5.2.10 
Content-Length: 4598 
Connection: close 
Content-Type: audio/mpeg 

# 4598 bytes of data 

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

HTTP/1.1 200 OK 
Date: Tue, 05 Jan 2010 02:14:28 GMT 
Server: Apache 
X-Powered-By: PHP/5.2.10 
Content-Length: 4598 
Connection: close 
Content-Type: audio/mpeg 

# 4598 bytes of data 

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

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

+1

Agregó los encabezados a la pregunta original ya que no caben en un comentario. Originalmente tenía el tipo especificado, pero lo saqué en caso de que estuviera causando un problema. Agregándolos de nuevo para una buena medida, pero sin cambios en el comportamiento roto en Safari. –

+0

Tu ejemplo funciona para mí.Entonces, el único factor parece ser el script PHP. Interesante. Publiqué una demostración de mi código en http://tts.mindtrove.info/test.html. La fuente del archivo PHP es visible en http://tts.mindtrove.info/say.php.txt. Los archivos de audio estáticos están en http://tts.mindtrove.info/cache. Lo único que veo en el script PHP que podría ser problemático ahora es el uso de passthru ("cat $ fn"). Pero con Content-Length y forzada exit() al final del script, no estoy seguro de por qué Safari/WebKit trataría el audio como una transmisión interminable. –

+1

Excelente ayuda. Gracias por tomarse el tiempo para trabajar en esto conmigo. Sus hallazgos pueden estar listos para un informe de error, aunque estoy seguro de que Apple simplemente dirá que el script PHP necesita manejo de rango. Aunque sería bueno si lo documentaron en algún lado. –

2

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

2

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 la cabecera es:

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

¿Cuáles son las variables aquí exactamente? ¿Es $ data su archivo de música ? ¿De dónde viene $ length? – Roozbeh15

3

Para el registro, mientras que tanto Pochang y Chris son correctas que necesita la cabecera Content-Range para solucionar este problema en Safari, Chrome requiere una cabecera adicional que deben incluirse para establecer horaActual funcione correctamente:

header('Accept-Ranges: bytes'); 

tenga en cuenta que en realidad no tiene que responder correctamente a la cabecera de la gama de la solicitud, sólo hay que incluir esto en la respuesta.

+0

¡Gracias, Brendan, eso ayudó mucho! – Hbf

Cuestiones relacionadas