我怀疑从PHP脚本的头是问题,特别是缺少一个内容长度。但事实并非如此。响应头包括适当的Content-Length以指示音频具有有限的大小。此外,一切工作正如预期在Firefox 3.5。我可以多次点击音频元素上的播放来听到声音重放。
如果我从等式中删除PHP脚本并提供MP3文件的静态副本,一切在Safari中正常工作。
这是否意味着Safari正在使用查询参数来处理音频src网址,而不是没有网址的网址?任何人都有运气得到这个工作?
我的简单示例页是:
<!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/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头:
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
我试着硬编码Accept-Ranges头到脚本中,但没有运气。
解决方法
在源元素上指定type属性也是一个好主意,因此浏览器不必下载两个剪辑以确定是否可以播放它们。
我不能重现你的问题。我试图在Safari 4.0.4中重现问题,并且当前的WebKit每晚,与following test page.我只是使用mod_rewrite分发到不同的格式,基于一个参数,而不是PHP,但我不认为应该一个区别,除非不知何故PHP正在修改文件。
<!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>
你能试试我的例子,让我知道它是否适合你?
编辑啊。在稍微戳一遍它之后,似乎问题是由于< audio>的奇怪方式引起的。元素在尝试确定内容的大小时会起作用。
下面是Safari遇到< audio>时捕获的数据包的摘录。元素指向直接从Apache提供的文件。正如你可以看到,它首先尝试获取媒体的前两个字节,大概是因为它可以获得一个Content-Length,以及可能的其他头。然后它尝试获取整个事情。然后,不可能的是,它尝试再次获取前两个字节,但传递适当的缓存头以获取“304未修改”响应。最后,仍然莫名其妙地,它再次获取文件的最后3440字节。它在单独的TCP连接中执行所有这些操作,这增加了相当大的开销,以及获取数据的开销。
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: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
无论如何,关于它如何处理您的PHP脚本的输出。这里,Safari再次尝试下载前两个字节,但是您的脚本忽略Range请求并返回整个内容。显然,WebKit不喜欢,所以它再次尝试,没有Range请求。同样,您的脚本发送完整的内容。 Safari现在再次尝试,添加一个Icy-Metadata头,这表明它认为它正在下载一个流,并且想要发送流元数据。它最终接受其输出,并且< audio>元素可以玩。
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
总而言之,Safari(或更准确地说,QuickTime,Safari使用它来处理所有媒体和媒体下载)有一个完全困难的方法来下载媒体。在你发送数据的方式,可能是你没有响应Range请求的事实,使它认为你发送流媒体,导致它重复下载内容(虽然即使面对的服务器响应Range请求,它仍然会执行几个更多的请求,而不是它真正需要的)。
我的建议是尽量适当响应Range请求;当提供媒体时,浏览器可能会使用它们尝试最小化带宽,通过只缓冲尽可能多的,他们需要能够播放(虽然有autobuffer属性,表明你希望他们缓冲整个事情,浏览器可以忽略)。我建议使用X-Sendfile让Apache处理文件,缓存和范围请求,但你似乎是在没有安装mod_xsendfile的Dreamhost,所以你必须滚动自己的范围处理。