我正在尝试嵌入指向PHP文件提供的MP3或OGG数据的HTML5音频元素。当我在Safari中查看页面时,会显示控件,但UI会显示“实时广播”。当我单击播放时,音频将按预期方式启动。但是,一旦结束,我将无法通过单击播放再次开始播放。即使在音频元素上使用JS API并将currentTime设置为0也会失败,并出现索引错误异常。
我怀疑PHP脚本的标题是问题所在,尤其是缺少内容长度。但是事实并非如此。响应头包括适当的Content-Length,以指示音频大小有限。此外,一切都可以在Firefox 3.5+中正常运行。我可以多次单击音频元素上的“播放”以收听声音重放。
如果我从等式中删除PHP脚本并提供MP3文件的静态副本,则在Safari中一切正常。
这是否意味着Safari对带有查询参数的音频src URL的处理方式与不包含它们的URL的处理方式不同?任何人都有运气可以工作吗?
我的简单示例页面是:
<!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>
PHP脚本中的HTTP标头:
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标头硬编码到脚本中,但是没有运气。
您是否可以使用和不使用PHP脚本发布服务器发送的标头?我想知道PHP脚本发送的Content-Type
是否不同于正常提供的文件。
在type
元素上指定source
属性也是一个好主意,因此浏览器不必下载两个剪辑即可确定是否可以播放它们。
我无法重现您的问题。我试图用following test page在Safari 4.0.4和当前的WebKit中重新创建该问题。我只是使用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>
您可以尝试我的示例并让我知道它是否对您有用吗?
edit嗯。经过一番摸索之后,问题似乎出在Safari中<audio>
元素试图确定内容大小的奇怪方式所致。
这里是遇到<audio>
元素的Safari数据包捕获摘录,该元素指向直接从Apache提供的文件。如您所见,它首先尝试获取媒体的前两个字节,大概是这样它可以获取Content-Length,以及其他报头。然后,它尝试获取整个内容。然后,莫名其妙地,它尝试再次获取前两个字节,但传递适当的缓存头以获取“ 304 Not Modified”响应。最后,仍然令人费解的是,它再次重新获取文件的最后3440字节。它在单独的TCP连接中完成所有这些操作,这不仅增加了几次获取数据的开销,还增加了相当大的开销。
GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1主持人:ephemera.continuation.org范围:字节= 0-1连接:关闭用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540接受:* / *接受编码:身份Cookie:[已删除]HTTP / 1.1 206部分内容日期:2010年1月5日,星期二02:12:48 GMT服务器:Apache上次修改时间:2010年1月5日,星期二,格林尼治标准时间ETag:“ b2a80ad-11f6-47c6139aaa800”接受范围:字节内容长度:2内容范围:字节0-1 / 4598连接:关闭内容类型:音频/ mpeg#2个字节的数据GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1主持人:ephemera.continuation.org范围:字节= 0-4597连接:关闭用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540接受:* / *接受编码:身份Cookie:[已删除]HTTP / 1.1 206部分内容日期:2010年1月5日,星期二02:12:48 GMT服务器:Apache上次修改时间:2010年1月5日,星期二,格林尼治标准时间ETag:“ b2a80ad-11f6-47c6139aaa800”接受范围:字节内容长度:4598内容范围:字节0-4597 / 4598连接:关闭内容类型:音频/ mpeg#4598字节数据GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1主持人:ephemera.continuation.org范围:字节= 0-1连接:关闭用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540接受:* / *接受编码:身份Cookie:[已删除]如果不匹配:“ b2a80ad-11f6-47c6139aaa800”如果自修改以来:星期二,2010年1月5日格林尼治标准时间HTTP / 1.1 304未修改日期:2010年1月5日,星期二02:12:49 GMT服务器:Apache连接:关闭ETag:“ b2a80ad-11f6-47c6139aaa800”# 没有数据GET /stackoverflow/audio-test/say-noid3?foo=bar&format=.mp3 HTTP / 1.1主持人:ephemera.continuation.org范围:字节= 1158-4597连接:关闭用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540接受:* / *接受编码:身份Cookie:[已删除]HTTP / 1.1 206部分内容日期:2010年1月5日,星期二02:12:49 GMT服务器:Apache上次修改时间:2010年1月5日,星期二,格林尼治标准时间ETag:“ b2a80ad-11f6-47c6139aaa800”接受范围:字节内容长度:3440内容范围:字节1158-4597 / 4598连接:关闭内容类型:音频/ mpeg#3440字节数据
无论如何,如何处理PHP脚本的输出。在这里,Safari再次尝试下载前两个字节,但是您的脚本会忽略Range
请求并返回整个内容。显然,WebKit不喜欢这样,因此它再次尝试,没有Range
请求。同样,您的脚本将发送全部内容。 Safari现在再次尝试,添加Icy-Metadata
标头,表明它认为自己正在下载流,并希望发送流元数据。它最终接受该输出,并且<audio>
元素可以播放。
GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP / 1.1主持人:tts.mindtrove.info范围:字节= 0-1连接:关闭用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540接受:* / *接受编码:身份HTTP / 1.1 200 OK日期:2010年1月5日,星期二02:14:28 GMT服务器:ApacheX-Powered-By:PHP / 5.2.10内容长度:4598连接:关闭内容类型:音频/ mpeg#4598字节数据GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP / 1.1主持人:tts.mindtrove.info连接:关闭用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540接受:* / *HTTP / 1.1 200 OK日期:2010年1月5日,星期二02:14:28 GMT服务器:ApacheX-Powered-By:PHP / 5.2.10内容长度:4598连接:关闭内容类型:音频/ mpeg#4598字节数据GET /say.php?text=this%20is%20a%20test&format=.mp3 HTTP / 1.1主持人:tts.mindtrove.info接受:* / *用户代理:Apple Mac OS X v10.6.2 CoreMedia v1.0.0.10C540冰封元数据:1连接:关闭HTTP / 1.1 200 OK日期:2010年1月5日,星期二02:14:28 GMT服务器:ApacheX-Powered-By:PHP / 5.2.10内容长度:4598连接:关闭内容类型:音频/ mpeg#4598字节数据
总之,似乎Safari(或更准确地说,是Safari用于处理所有媒体和媒体下载的QuickTime)对下载媒体具有完全破坏性的方法。回传数据的某种方式(可能是您没有响应Range
请求的事实)使其认为您正在发送流媒体,从而导致其反复下载内容(即使面对服务器)确实会响应Range
请求,但仍然比实际需要多几个请求)。
我的建议是尝试适当响应Range
请求;在提供媒体内容时,浏览器可能会通过仅缓冲需要播放的内容来使用它们来尝试最小化带宽(尽管具有autobuffer
属性,该属性指示您希望它们缓冲整个内容,浏览器可能会忽略它)。我建议使用X-Sendfile
来让Apache处理文件,缓存和范围请求的服务,但是您似乎位于Dreamhost上,该服务器没有安装mod_xsendfile
,因此您将不得不滚动自己的Range
处理。
header( 'Accept-Ranges: bytes');
请注意,您实际上不必正确响应请求的Range标头,只需将其包含在响应中。
Content-Range