Pet*_*nte 33 safari audio html5 webkit
我正在尝试嵌入一个HTML5音频元素,指向由PHP文件提供的MP3或OGG数据.当我在Safari中查看页面时,会显示控件,但UI会显示"直播".单击播放时,音频将按预期启动.但是,一旦结束,我就无法通过点击播放再次开始播放.即使在audio元素上使用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>
Run Code Online (Sandbox Code Playgroud)
来自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
Run Code Online (Sandbox Code Playgroud)
来自直接文件访问的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
Run Code Online (Sandbox Code Playgroud)
我尝试将Accept-Ranges标头硬编码到脚本中,但没有运气.
Bri*_*ell 34
您是否可以使用和不使用PHP脚本发布服务器发送的标头?我想知道PHP脚本是否发送不同于Content-Type
正常提供文件.
type
在source
元素上指定属性也是一个好主意,因此浏览器不必下载两个剪辑来确定它是否可以播放它们.
我无法重现你的问题.我尝试使用以下测试页面在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>
Run Code Online (Sandbox Code Playgroud)
你可以尝试我的例子,让我知道它是否适合你?
编辑啊.在稍微探讨一下之后,问题似乎是由于<audio>
Safari 中的元素在尝试确定内容大小时表现出奇怪的方式.
以下是Safari遇到<audio>
指向直接从Apache提供的文件的元素捕获时的摘录.正如您所看到的,它首先尝试获取媒体的前两个字节,可能是因为它可以返回Content-Length,可能还有其他标头.然后它试图获取整个事物.然后,莫名其妙地,它尝试再次获取前两个字节,但传递适当的缓存头以获得"304 Not Modified"响应.最后,仍然莫名其妙地,它再次获取文件的最后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: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
无论如何,关于如何处理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(或者更确切地说,Safari用于处理所有媒体和媒体下载的QuickTime)似乎有一种完全受到严重影响的下载媒体方法.您发送数据的方式可能是您没有响应Range
请求的事实,这使得它认为您正在发送流媒体,导致它重复下载内容(尽管即使遇到响应的服务器也是如此)对于一个Range
请求,它仍然会发出比实际需要更多的请求.
我的建议是尽量适应Range
要求; 在提供媒体时,浏览器可能会使用它们来尝试最小化带宽,只需缓冲它们需要能够播放的内容(尽管具有autobuffer
表明您希望它们缓冲整个事物的属性,浏览器可能忽略那个).我建议使用X-Sendfile
让Apache处理文件,缓存和范围请求的服务,但是你似乎是在没有mod_xsendfile
安装的Dreamhost上,所以你将不得不自己Range
处理.
小智 5
老话题,但在 2019 年仍然有效。我们终于找到了解决方案...下面的 PHP 脚本示例将考虑 Safari 的“Range”标头请求。
$bytes_total = strlen($data);
if (isset($_SERVER['HTTP_RANGE'])) {
$byte_range = explode('-',trim(str_ireplace('bytes=','',$_SERVER['HTTP_RANGE'])));
$byte_from = $byte_range[0];
$byte_to = ($byte_range[1]+1);
$data = substr($data,$byte_from,$byte_to);
header('HTTP/1.1 206 Partial Content');
}
else {
$byte_from = 0;
$byte_to = $bytes_total;
}
$length = strlen($data);
header('Content-type: '.$content_type);
header('Accept-Ranges: bytes');
header('Content-length: ' . $length);
header('Content-Range: bytes '.$byte_from.'-'.$byte_to.'/'.$bytes_total);
header('Content-Transfer-Encoding: binary');
print($data);
Run Code Online (Sandbox Code Playgroud)