HTML5 <音频>Safari 直播 vs 不直播 [英] HTML5 <audio> Safari live broadcast vs not

查看:23
本文介绍了HTML5 <音频>Safari 直播 vs 不直播的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试嵌入一个 HTML5 音频元素,指向由 PHP 文件提供的 MP3 或 OGG 数据.当我在 Safari 中查看页面时,控件出现,但 UI 显示直播".当我单击播放时,音频按预期开始.但是,一旦它结束,我就无法通过单击播放来重新开始播放.即使在音频元素上使用 JS API 并将 currentTime 设置为 0 也会因索引错误异常而失败.

我怀疑来自 PHP 脚本的标题是问题所在,尤其是缺少内容长度.但事实并非如此.响应头包含一个适当的 Content-Length 来指示音频的大小是有限的.此外,在 Firefox 3.5+ 中一切正常.我可以多次点击音频元素上的播放来听到声音重播.

如果我从等式中删除 PHP 脚本并提供 MP3 文件的静态副本,则在 Safari 中一切正常.

这是否意味着 Safari 将带有查询参数的音频 src URL 与没有它们的 URL 区别对待?有没有人有幸让这个工作?

我的简单示例页面是:

<头></头><身体><音频控制自动缓冲><source src="say.php?text=this%20is%20a%20test&format=.ogg"/><source src="say.php?text=this%20is%20a%20test&format=.mp3"/>

来自 PHP 脚本的 HTTP 标头:

HTTP/1.x 200 OK日期:2010 年 1 月 3 日星期日 15:39:34 GMT服务器:阿帕奇X-Powered-By:PHP/5.2.10内容长度:8993保持活动:超时=2,最大值=98连接:保持活动内容类型:音频/mpeg

来自直接文件访问的 HTTP 标头:

HTTP/1.x 200 OK日期:2010 年 1 月 3 日星期日 20:06:59 GMT服务器:阿帕奇上次修改时间: 2010 年 1 月 3 日星期日 03:20:02 GMTEtag:a404b-c3f-47c3a14937c80"接受范围:字节内容长度:8993保持活动:超时=2,最大值=100连接:保持活动内容类型:音频/mpeg

我也尝试将 Accept-Ranges 标头硬编码到脚本中,但没有成功.

解决方案

你能把服务器发过来的头信息,无论有没有 PHP 脚本都贴出来吗?我想知道 PHP 脚本发送的 Content-Type 是否与正常提供文件不同.

source 元素上指定 type 属性也是一个好主意,这样浏览器就不必下载两个剪辑来确定它是否可以播放

我无法重现您的问题.我试图在 Safari 4.0.4 和当前的 WebKit 每晚重现这个问题,使用 以下测试页.我只是使用 mod_rewrite 基于参数而不是 PHP 分派到不同的格式,但我认为这不会有什么不同,除非 PHP 以某种方式修改了文件.

<title>Auido test</title><音频控制自动缓冲><source src="gnossienne-no-1?foo=bar&format=.mp4"><source src="gnossienne-no-1?foo=bar&format=.ogg">

你能试试我的例子,让我知道它是否适合你吗?

编辑 啊.在仔细研究之后,问题似乎是由于 Safari 中的 <audio> 元素在尝试确定内容大小时的行为方式很奇怪.

这是 Safari 在遇到 <audio> 元素时捕获数据包的摘录,该元素指向直接从 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接受: */*接受编码:身份饼干:[已编辑]HTTP/1.1 206 部分内容日期:2010 年 1 月 5 日,星期二 02:12:48 GMT服务器:阿帕奇上次修改时间:2010 年 1 月 5 日,星期二 02:02:08 GMTETag: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接受: */*接受编码:身份饼干:[已编辑]HTTP/1.1 206 部分内容日期:2010 年 1 月 5 日,星期二 02:12:48 GMT服务器:阿帕奇上次修改时间:2010 年 1 月 5 日,星期二 02:02:08 GMTETag: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接受: */*接受编码:身份饼干:[已编辑]如果-无-匹配:b2a80ad-11f6-47c6139aaa800"If-Modified-Since: 2010 年 1 月 5 日星期二 02:02:08 GMTHTTP/1.1 304 未修改日期:2010 年 1 月 5 日,星期二 02:12:49 GMT服务器:阿帕奇连接:关闭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接受: */*接受编码:身份饼干:[已编辑]HTTP/1.1 206 部分内容日期:2010 年 1 月 5 日,星期二 02:12:49 GMT服务器:阿帕奇上次修改时间:2010 年 1 月 5 日,星期二 02:02:08 GMTETag:b2a80ad-11f6-47c6139aaa800"接受范围:字节内容长度:3440内容范围:字节 1158-4597/4598连接:关闭内容类型:音频/mpeg# 3440 字节的数据

无论如何,关于它如何处理您的 PHP 脚本的输出.在这里,Safari 再次尝试下载前两个字节,但您的脚本会忽略 Range 请求并返回整个内容.显然,WebKit 不喜欢那样,所以它再次尝试,没有 Range 请求.同样,您的脚本会发送完整内容.Safari 现在再次尝试,添加一个 Icy-Metadata 标头,这表明它认为它正在下载流并希望发送流元数据.它最终接受了它的输出,并且 元素可以播放.

<前>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 正常日期:2010 年 1 月 5 日,星期二 02:14:28 GMT服务器:阿帕奇X-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 正常日期:2010 年 1 月 5 日,星期二 02:14:28 GMT服务器:阿帕奇X-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 正常日期:2010 年 1 月 5 日,星期二 02:14:28 GMT服务器:阿帕奇X-Powered-By:PHP/5.2.10内容长度:4598连接:关闭内容类型:音频/mpeg# 4598 字节的数据

总而言之,Safari(或更准确地说,Safari 用来处理所有媒体和媒体下载的 QuickTime)似乎有一种完全脑残的下载媒体方法.你发回数据的方式,可能是你不响应 Range 请求的事实,使它认为你正在发送流媒体,导致它重复下载内容(尽管即使当遇到响应 Range 请求的服务器时,它仍然会执行比实际需要多的请求).

我的建议是尝试对 Range 请求做出适当的响应;在提供媒体服务时,浏览器可能会使用它们来尝试最小化带宽,只缓冲它们能够播放所需的量(尽管具有 autobuffer 属性,表明您想要它们缓冲整个事情,浏览器可能会忽略它).我建议使用 X-Sendfile 让 Apache 处理文件、缓存和范围请求的服务,但您似乎在 Dreamhost 上,它没有 mod_xsendfile安装,所以你将不得不推出自己的 Range 处理.

I'm attempting to embed an HTML5 audio element pointing to MP3 or OGG data served by a PHP file . When I view the page in Safari, the controls appear, but the UI says "Live Broadcast." When I click play, the audio starts as expected. Once it ends, however, I can't start it playing again by clicking play. Even using the JS API on the audio element and setting currentTime to 0 fails with an index error exception.

I suspected the headers from the PHP script were the problem, particularly missing a content length. But that's not the case. The response headers include a proper Content- Length to indicate the audio has finite size. Furthermore, everything works as expected in Firefox 3.5+. I can click play on the audio element multiple times to hear the sound replay.

If I remove the PHP script from the equation and serve up a static copy of the MP3 file, everything works fine in Safari.

Does this mean Safari is treating audio src URLs with query parameters differently than URLs that don't have them? Anyone have any luck getting this to work?

My simple example page is:

<!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 Headers from PHP script:

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 Headers from direct file access:

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

I tried hard-coding the Accept-Ranges header into the script too, but no luck.

解决方案

Can you post the headers sent by the server both with and without the PHP script? I'm wondering if the PHP script is sending a different Content-Type than serving the files normally.

It would also be a good idea to specify the type attribute on the source elements, so the browser does not have to download both clips to determine if it can play them.

I cannot reproduce your problem. I have tried to recreate the problem in Safari 4.0.4, and the current WebKit nightly, with the following test page. I am simply using mod_rewrite to dispatch to different formats based on a parameter instead of PHP, but I don't think that should make a difference, unless somehow PHP is modifying the file.

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

Can you try my example out and let me know if it works for you?

edit Ah. After poking around at it a bit more, it appears that the problem is due to an odd way that the <audio> element in Safari behaves in attempting to determine the size of the content.

Here's an excerpt from a packet capture of Safari upon encountering an <audio> element pointing to a file served directly from Apache. As you can see, it first tries to fetch the first two bytes of the media, presumably so it can get a Content-Length back, and possibly other headers. It then tries to fetch the whole thing. Then, inexplicably, it tries to fetch the first two bytes again, but passes appropriate caching headers to get a "304 Not Modified" response. And finally, still inexplicably, it fetches the last 3440 bytes of the file all over again. It does all of these in separate TCP connections, which adds considerable overhead, in addition to the overhead of fetching the data a couple of times.

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

Anyhow, on to how it deals with the output of your PHP script. Here, Safari again tries to download the first two bytes, but your script ignores the Range request and returns the whole thing. Apparently, WebKit doesn't like that, and so it tries again, without the Range request. Again, your script sends the full contents. Safari now tries once more, adding an Icy-Metadata header, which indicates it thinks that it's downloading a stream and wants streaming metadata to be sent. It finally accepts the output of that, and the <audio> element can play.

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

In summary, it appears that Safari (or more accurately, QuickTime, which Safari uses to handle all media and media downloading) has a completely braindamaged approach to downloading media. Something in the way you send your data back, probably the fact that you don't respond to Range requests, makes it think that you are sending streaming media, causing it to download the content repeatedly (though even when confronted with a server that does respond to a Range request, it still does several more requests than it really needs to).

My advice would be to try to respond appropriately to Range requests; when serving up media, browsers will likely use them to try to minimize bandwidth, by only buffering as much as they need to be able to play through (although have the autobuffer attribute which indicates that you would like them to buffer the whole thing, browsers may ignore that). I would recommend using X-Sendfile to let Apache deal with serving the file, caching, and range requests, but you appear to be on Dreamhost, which doesn't have mod_xsendfile installed, so you're going to have to roll your own Range handling.

这篇关于HTML5 &lt;音频&gt;Safari 直播 vs 不直播的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆