2010-01-03 9 views
27

Ich versuche, ein HTML5-Audio-Element, das auf MP3-oder OGG-Daten von einer PHP-Datei serviert verweist. Wenn ich die Seite in Safari anzeigen, werden die Steuerelemente angezeigt, aber die Benutzeroberfläche sagt "Live Broadcast". Wenn ich auf Wiedergabe klicke, startet das Audio wie erwartet. Sobald es jedoch beendet ist, kann ich es nicht erneut starten, indem ich auf "Play" klicke. Selbst wenn die JS-API für das Audioelement verwendet wird und currentTime auf 0 gesetzt wird, schlägt der Befehl mit einer Indexfehlerausnahme fehl.HTML5 <audio> Safari Live-Übertragung vs nicht

Ich vermutete die Header aus dem PHP-Skript waren das Problem, insbesondere fehlt eine Inhaltslänge. Aber das ist nicht der Fall. Die Antwortheader enthalten eine geeignete Inhaltslänge, um anzuzeigen, dass das Audio eine begrenzte Größe hat. Außerdem funktioniert alles wie erwartet in Firefox 3.5+. Ich kann mehrmals auf das Audioelement klicken, um die Tonwiedergabe zu hören.

Wenn ich das PHP-Skript aus der Gleichung entfernen und eine statische Kopie der MP3-Datei bereitstellen, funktioniert alles in Safari.

Bedeutet dies, dass Safari Audio-URLs mit Abfrageparametern anders behandelt als URLs ohne diese? Hat jemand Glück dabei?

Mein einfaches Beispiel Seite lautet:

<!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> 

HTTP-Header von PHP-Skript:

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 

HTTP-Header aus den direkten Dateizugriff:

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 

ich die Hartcodierung versucht Accept-Ranges-Header in das Skript auch, aber kein Glück.

+0

Ich bin mir nicht sicher, ob Sie über Bearbeitungen benachrichtigt werden, aber ich habe meine Antwort so bearbeitet, dass sie einen Testfall enthält, der für mich funktioniert und scheinbar mit dem übereinstimmt, was Sie tun. Können Sie überprüfen, ob mein Testfall auch für Sie funktioniert? –

Antwort

31

Können Sie die vom Server gesendeten Header sowohl mit als auch ohne PHP-Skript posten? Ich frage mich, ob das PHP-Skript eine andere Content-Type sendet, als die Dateien normal zu bedienen.

Es wäre auch eine gute Idee, das type Attribut auf den source Elementen anzugeben, so dass der Browser nicht beide Clips herunterladen muss, um festzustellen, ob sie sie abspielen können.

Ich kann Ihr Problem nicht reproduzieren. Ich habe versucht, das Problem in Safari 4.0.4 und das aktuelle WebKit allabendlich mit dem following test page neu zu erstellen. Ich verwende einfach mod_rewrite, um auf der Grundlage eines Parameters anstelle von PHP in andere Formate zu exportieren, aber ich denke nicht, dass das einen Unterschied machen sollte, es sei denn, irgendwie modifiziert PHP die Datei.

Können Sie mein Beispiel ausprobieren und lassen Sie mich wissen, ob es für Sie funktioniert?

bearbeiten Ah. Nachdem Sie etwas mehr herumgestöbert haben, scheint es, dass das Problem auf eine seltsame Weise zurückzuführen ist, dass sich das Element <audio> in Safari verhält, wenn es versucht, die Größe des Inhalts zu bestimmen.

Hier ist ein Auszug aus einer Paketerfassung von Safari bei einem <audio> Element, das auf eine Datei zeigt, die direkt von Apache geliefert wird. Wie Sie sehen können, versucht es zuerst, die ersten zwei Bytes des Mediums zu holen, vermutlich damit es eine Inhaltslänge zurückbekommt, und möglicherweise andere Überschriften. Es versucht dann, das Ganze zu holen. Dann versucht es aus unerklärlichen Gründen, die ersten zwei Bytes erneut zu holen, übergibt jedoch entsprechende Caching-Header, um eine "304 Not Modified" -Antwort zu erhalten.Und schließlich, immer noch unerklärlich, holt es die letzten 3440 Bytes der Datei noch einmal. All dies geschieht in getrennten TCP-Verbindungen, was zusätzlich zu dem Aufwand, die Daten ein paar Mal abzurufen, einen beträchtlichen Overhead mit sich bringt.

 
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 

Wie auch immer, wie es mit der Ausgabe Ihres PHP-Skripts umgeht. Hier versucht Safari erneut, die ersten beiden Bytes herunterzuladen, aber Ihr Skript ignoriert die Anforderung Range und gibt das Ganze zurück. Offensichtlich mag WebKit das nicht, und so versucht es erneut, ohne die Range Anfrage. Auch hier sendet Ihr Skript den vollständigen Inhalt. Safari versucht es jetzt noch einmal und fügt einen Header Icy-Metadata hinzu, der anzeigt, dass er denkt, dass er einen Stream herunterlädt und Streaming-Metadaten senden möchte. Es akzeptiert schließlich die Ausgabe von diesem, und das <audio> Element kann spielen.

 
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 

Zusammenfassend scheint es, dass Safari (oder genauer gesagt, Quicktime, die Safari alle Medien und Medien-Download behandeln verwendet) zum Herunterladen von Medien einen völlig braindamaged Ansatz hat. Etwas in der Art und Weise, wie Sie Ihre Daten zurücksenden, wahrscheinlich die Tatsache, dass Sie nicht auf Range Anfragen reagieren, lässt vermuten, dass Sie Streaming-Medien senden, was dazu führt, dass der Inhalt wiederholt heruntergeladen wird (auch wenn er mit einem Server konfrontiert wird antworten Sie auf eine Range Anfrage, es tut immer noch mehrere Anfragen, als es wirklich braucht).

Mein Rat wäre zu versuchen, auf Range Anfragen angemessen zu reagieren; wenn Medien bedient werden, verwenden Browser wahrscheinlich sie, um zu versuchen, die Bandbreite zu minimieren, indem sie nur so viel puffern, wie sie brauchen, um durchzuspielen (obwohl das autobuffer Attribut anzeigt, dass sie möchten, dass sie das ganze Ding, Browser buffst könnte das ignorieren). Ich würde empfehlen, zu verwenden, damit Apache mit dem Dienen der Datei-, Caching- und Bereichsanforderungen fertig wird, aber Sie scheinen auf Dreamhost zu sein, das nicht mod_xsendfile installiert hat, so dass Sie Ihre eigene Range Behandlung rollen müssen.

+1

Die Header wurden der ursprünglichen Frage hinzugefügt, da sie nicht in einen Kommentar passen würden. Ich hatte Typ ursprünglich angegeben, aber es nahm heraus, falls es ein Problem verursachte. Hinzufügen von ihnen für ein gutes Maß, aber ohne das gebrochene Verhalten in Safari zu ändern. –

+0

Ihr Beispiel funktioniert für mich.Der einzige Faktor scheint also das PHP-Skript zu sein. Interessant. Ich habe eine Demo meines Codes unter http://tts.mindtrove.info/test.html veröffentlicht. Die Quelle der PHP-Datei ist unter http://tts.mindtrove.info/say.php.txt sichtbar. Die statischen Audiodateien finden Sie unter http://tts.mindtrove.info/cache. Das einzige, was ich im PHP-Skript sehen kann, das jetzt mühsam sein kann, ist die Verwendung von passthru ("cat $ fn"). Aber mit einer Inhaltslänge und erzwungenem Beenden() am Ende des Skripts bin ich mir nicht sicher, warum Safari/WebKit das Audio als endlosen Stream behandeln würde. –

+1

Ausgezeichnete Hilfe. Danke, dass du dir die Zeit genommen hast, das mit mir durchzuarbeiten. Ihre Ergebnisse sind möglicherweise reif für einen Fehlerbericht, aber ich bin mir sicher, dass Apple einfach sagen wird, dass das PHP-Skript eine Bereichsbehandlung benötigt. Es wäre nett, wenn sie es irgendwo dokumentieren würden. –

2

Ich habe das gleiche Problem. Der entscheidende Punkt ist der Inhalt-Bereich Header. Alles funktioniert gut, nachdem ich es dem mp3-output php hinzugefügt habe.

2

Pochang ist korrekt. Wenn Sie einen Content-Range-Header in die PHP-Antwort einfügen, verhält sich Safari ordnungsgemäß. Es erlaubt auch das Suchen (media.currentTime = 0;) ohne die gefürchtete INDEX_SIZE_ERR in Safari, aber nicht in Chrome.

Der PHP-Code für den Header ist:

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

Was sind die Variablen hier genau? Ist $ Daten Ihre Musikdatei Woher kommt $ length? – Roozbeh15

3

Für die Aufzeichnung, während beide Pochang und Chris korrekt sind, dass Sie die Content-Range-Header müssen dieses Problem in Safari zu beheben, erfordert Chrome ein Extra-Header das muss für die Einstellung current einbezogen werden richtig funktioniert:

header('Accept-Ranges: bytes'); 

Beachten Sie, dass Sie eigentlich gar nicht richtig auf die Anforderung des Range-Header zu reagieren haben, müssen Sie nur diese sind in der Antwort.

+0

Danke, Brendan, das hat sehr geholfen! – Hbf