【问题标题】:HTML 5 / QuickTime audio caching in Safari on iOSiOS 上 Safari 中的 HTML 5 / QuickTime 音频缓存
【发布时间】:2011-10-12 12:25:31
【问题描述】:

我正在拼命地尝试为必须在 iOS-Safari 上运行的网络应用程序(例如在 iPad、iPad2 和 iPhone 4 上)寻找解决方案:

这是我前段时间编写的一个网络应用程序,它可以让用户搜索和收听短音乐样本(MP3,全部从 ~100 kB 到 ~1.5 MB)。音频播放器是基于 Flash 的,因此它目前不适用于 iOS 设备,我必须在 HTML 5 或“直接”QuickTime 对象中实现替代方案。

到目前为止,我的适用于 iOS 设备的 HTML 5 和 QuickTime 替代方案都可以正常工作,但有一个主要问题我找不到解决方案:

与 Flash 和我 iPad 2 上 Windows Safari 上大多数支持 HTML 5 的浏览器不同,加载和播放音频文件后,它们不会在浏览器缓存中存储 - 无论是使用 HTML 5 音频标签还是使用 QuickTime-Object。每次我从服务器加载要播放的音频文件(使用 JavaScript-Commands,因此无需更改或重新加载整个页面),它都会再次完全下载。

如果用户先听样本 A,然后再听样本 B,Safari 会忘记播放样本 A,如果我想再听一遍,则重新下载整个 MP3。在带宽可能较窄的移动设备上,这种行为是不可能的。

有没有办法将下载的由 HTML 5 或 QuickTime 打开的音频文件存储在 Safari 的缓存中,以便它记住已经下载它们 - 就像它缓存通常的“网络文件”,如 HTML、CSS 或 JPEG 图像,或者像 Flash 商店此类对象在其本地缓存中?

我的第一次尝试是尝试将应用程序缓存与清单文件一起使用 - 尽管这并不是我的应用程序的真正预期目的......我没有想要缓存的静态文件集或“离线可用” - 我只想缓存用户播放过的 MP3。

应该可以使用“动态清单”:由 Apache PHP 模块解析并列出到目前为止从 PHP 会话播放的文件 - 类似这样:

session_start();

header("Content-Type: text/cache-manifest, charset=UTF-8");
echo "CACHE MANIFEST\n";
foreach($_SESSION['playedSongs'] as $song)
{
        echo $song."\n";
}

因此,每当加载/播放歌曲时,我都可以使用 AJAX 访问 PHP 会话,插入播放文件的文件名并通过调用 window.applicationCache.update() 或 .swapCache() 手动更新清单。

这样做有两个问题:

首先:它不起作用。而且我什至没有尝试使用动态清单:

<!DOCTYPE html>
<html manifest="cache.manifest">
    <head>
        <title>Test</title>
        <script type="text/javascript">

        function playStuff(id)
        {
            if(id == 1)
            {
                window.document.getElementById("audio").innerHTML = '<audio controls preload="automatic" autobuffer><source src="song01.mp3" type="audio/mp3" /></audio>';
            }

            else if(id == 2)
            {
                window.document.getElementById("audio").innerHTML = '<audio controls preload="automatic" autobuffer><source src="song02.mp3" type="audio/mp3" /></audio>';
            }
        }
        </script>
    </head>

    <body>
        <div id="audio"></div><br />
        <br />
        <input type="button" value="playStuff(1)" onclick="playStuff(1)" />
        <input type="button" value="playStuff(2)" onclick="playStuff(2)" />
    </body>

</html>

cache.manifest 如下所示:

CACHE MANIFEST

song01.mp3
song02.mp3

并通过添加从 Apache 正确返回为“text/cache-manifest”

AddType text/cache-manifest manifest

到这个目录的.htaccess。

Apache 日志清楚地表明 Safari(分别称为“AppleCoreMedia”)在涉及音频文件时并不关心应用程序缓存:

Safari 本身似乎承认清单并确实预加载了文件:

192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/index2.html HTTP/1.1" 200 2619 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"

192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/cache.manifest HTTP/1.1" 200 79 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"

192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/cache.manifest?%3E HTTP/1.1" 200 79 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"

192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/song02.mp3 HTTP/1.1" 200 120525 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"

192.168.0.40 - - [23/Jul/2011:12:45:46 +0200] "GET /websql/song01.mp3 HTTP/1.1" 200 120525 "-" "Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; de-de) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5"

到目前为止,我什么也没做,只是在 Safari 中打开我的测试应用程序。

播放歌曲01.mp3:

192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 2 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:47:25 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:47:29 +0200] "GET /websql/song01.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:47:29 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

播放歌曲2.mp3:

192.168.0.40 - - [23/Jul/2011:12:48:04 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 2 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:04 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:04 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:04 +0200] "GET /websql/song02.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:04 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:05 +0200] "GET /websql/song02.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:05 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

再次播放 song1.mp3:

192.168.0.40 - - [23/Jul/2011:12:48:38 +0200] "GET /websql/song01.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:38 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:38 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:38 +0200] "GET /websql/song01.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:38 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:40 +0200] "GET /websql/song01.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:48:40 +0200] "GET /websql/song01.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

再次播放 song2.mp3:

192.168.0.40 - - [23/Jul/2011:12:49:12 +0200] "GET /websql/song02.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:49:12 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:49:12 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:49:12 +0200] "GET /websql/song02.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:49:12 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:49:13 +0200] "GET /websql/song02.mp3 HTTP/1.1" 304 - "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

192.168.0.40 - - [23/Jul/2011:12:49:13 +0200] "GET /websql/song02.mp3 HTTP/1.1" 206 120525 "-" "AppleCoreMedia/1.0.0.8J2 (iPad; U; CPU OS 4_3_3 like Mac OS X; de_de)"

每个文件在播放时都会再次完全下载。所以“AppleCoreMedia”(无论这可能是什么,我想是由 HTML 5 音频元素触发的 QuickTime 插件?)要么无法访问应用程序缓存,要么只是没有意识到其中的文件.因此,如果我现在将 iPad 切换到“飞行模式”,Safari 将无法访问/加载/播放文件。

我还尝试使用 QuickTime 对象而不是 HTML 5 音频标签(据我所知,Safari 中的 HTML 5 音频和视频总是使用 QuickTime?)并通过以下方式控制它:

document.movie1.SetURL('song02.mp3');

没有任何变化,就像使用 HTML 5 音频一样,加载/播放时所有内容都会重新下载。

即使这样可行,仍然会有问题:

为了正确实现这一点,我必须在播放前将 MP3 文件加载到应用程序缓存中。执行此操作时似乎不可能显示“真实”进度:更新后从应用程序缓存触发的 ProgressEvent 似乎没有提供有关到目前为止加载的数据和文件的完整大小的任何信息。这只是“从 2 开始的文件 1”等等,而不是一个“真正的”进展,我可以确定类似:“100 kB 的 1.2 MB 已加载”,就像我可以对音频元素做的那样。

Web SQL / Web 数据库或本地存储等所有其他存储方法也无济于事:

我看不到任何将 MP3 数据导入本地存储或 Web 数据库和/或再次将其取出来播放的方法。 HTML 5 Canvas 元素有一个 toDataURL() 函数来生成 Base64 编码的表示并将其用于存储 - 音频元素似乎没有这样的东西。

我最后一个真正“肮脏”的方法是尝试使用 AJAX 和 PHP 的组合“手动”加载 Base64 编码的 MP3:PHP 脚本输出 MP3 文件的 Base64 表示并由 AJAX 加载,所以我可以存储 Base64 表示,例如作为本地存储或在 Web 数据库中:

$infile = 'song01.mp3';
$contents = file_get_contents($infile);
$base64 = base64_encode($contents);
$audio = 'data:audio/mp3;base64,'.$base64;
echo $audio;

我尝试使用生成的 AJAX responseText 作为音频源标签中的源参数。惊喜:它在我的 iPad 2 上的 Safari 中不起作用,播放器只是无法加载“文件”,尽管这在 Windows 上的 Chrome 中可以正常工作。可能是 Safari / iOS 上 Base64-URI 的大小限制?

再说一遍:即使这在 iOS/Safari 中有效,我也不知道如何确定 AJAX 查询的实际进度...

我想到的最后一件事是在加载歌曲时不替换音频或源标签,而是将它们留在 DOM 结构中,在加载歌曲时检查它是否已经存在并添加新的音频 -如果尚未加载歌曲,请标记。不工作... 如果您动态添加多个播放器实例(同样无论是 HTML 5 标记还是 QuickTime 对象)而不是“覆盖”它们,Safari 甚至会在您插入新的音频或 QuickTime 时忘记加载第一个 MP3 -元素到 DOM 树中——你甚至不必在新实例中加载/播放一些东西!只要您不播放或插入任何其他与音频/媒体相关的东西,重复播放而不完全重新加载文件就可以工作。顺便说一句:仅在 JavaScript 中使用音频对象并将它们“保存”到数组中也不起作用/不会使 Safari 缓存任何内容。

如果您处于带宽较低的蜂窝网络中,这会产生大量不必要的流量并花费不必要的长时间!

我已经为这个问题工作了三天,甚至没有接近解决方案......

有什么想法吗?

【问题讨论】:

  • +1 用于演示 :) 我在 iphone 上重新标记了它,因为它不是 iPad 专用的,而且 iphone 标签被更多人订阅。
  • 可能这里包含一些有趣的链接和信息stackoverflow.com/questions/1612116/…
  • 在那个 Kay 中肯定有一些有趣的花絮,但 IOS 问题没有答案。
  • 我认为您采取了错误的方法。本地存储和应用程序缓存不适用于大型音频文件。我认为我们仍然可以找到具有正常缓存的解决方案。提供音频文件时服务器发送的标头是什么?你能做curl -v URL 并在这里发布标题吗?
  • 同意@Matej - 您确定您的服务器正在发送正确的 HTTP 标头来告诉 Safari 缓存数据吗?如果没有,这种重复下载正是我希望看到的行为。

标签: iphone ios caching audio safari


【解决方案1】:

我几乎可以肯定这是设计使然,不能被覆盖; CoreMedia 的东西有目的地根据需要流式传输文件,并在播放器关闭时将其丢弃而不缓存。这是由于存储空间、电池寿命等原因造成的,因为在大多数情况下,您加载一个媒体文件,播放它多次,然后将其删除。只要内容类型是媒体类型,就会发生这种情况。

另一篇文章提到了将数据编码为 PNG 以使浏览器缓存它的想法,但我没有尝试过。

您可以尝试将各种音频样本合并到一个文件中,然后传输每个样本的开始/停止时间(基本上是一个索引);然后您可以在单个音频播放器中加载文件并跳转到必要的位置并播放指定的时间。如果该位置尚未下载,我相信 Safari 将使用范围标头在文件中向前跳转(但这可能取决于容器的类型以及容器是否具有索引)。

另一种选择是使用可以动态播放音频的流媒体服务器。只需在播放器参与但流式静默时继续流式传输(在这种情况下,正确的协议应使用最小带宽),然后对样本的请求触发流式服务器播放该样本。不幸的是,不理想或非常有效。

【讨论】:

    【解决方案2】:

    如果有人还在为这些东西而烦恼(我最近失去了一个周末),iOS 6 上的 Safari 有一个 Web Audio API。

    https://developer.apple.com/technologies/ios6/

    【讨论】:

    • 您不应公开讨论 iOS 的 beta 版本功能。
    • 为什么不呢?这是 Apple.com 上的公开信息:“iOS 6 上 Safari 的新功能允许您使用 Web Audio API 为交互式 Web 应用程序创建音频”。这是个好消息,我实际上正在为 iPad 使用 HTML 5 构建儿童游戏,但我遇到了声音滞后的问题。
    【解决方案3】:

    试试我几周前在推特上看到的这个技巧,但实际上从来没有时间尝试:附加一个 iframe,并将源设置为媒体文件 URL。听起来很奇怪,但它来自一个非常受欢迎的 JS 家伙推文......

    哦,我在这里看到了:How can I autoplay media in iOS >= 4.2.1 Mobile Safari?

    Def值得一试

    【讨论】:

      猜你喜欢
      • 2011-12-27
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      • 2020-02-21
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      相关资源
      最近更新 更多