【发布时间】:2014-04-07 18:56:41
【问题描述】:
当使用没有controls 属性的<audio> 元素(或<video> 元素)时,移动设备(Android 和iOS)通常需要用户点击某些东西才能获得@ 987654325@致电实际工作。例如,这个 jQuery 代码将不在大多数移动设备上工作:
$(window).load(function() {
$('#an_audio_element_without_controls')[0].play();
});
但这将适用于大多数移动设备:
$(window).load(function() {
$('#some_link').click(function() {
$('#an_audio_element_without_controls')[0].play();
return false;
});
});
在特定的<audio> 元素被play()'d 一次后,它可以再次play()'d,而无需用户先点击某些东西。因此,如果您处于需要在用户工作流程的某些点播放某些音频文件但不希望他们总是必须点击某些东西才能播放音频的情况,您可以让他们点击某些东西在一开始并具有初始点击会导致播放空的<audio> 元素。然后,当您真正需要播放音频时,您可以更新该特定 <audio> 元素的源,然后播放它,它就可以工作了。
我刚刚描述的这个技巧在 iOS 设备上运行良好,但在某些 Android 设备上并不总是有效。例如,看看这段代码(jsFiddle demo):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Android Audio Test</title>
<style>
.column {
float: left;
width: 18em;
}
.log {
width: 16em;
height: 10em;
padding: 0.5em;
overflow-y: auto;
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
border: 1px solid #000;
}
</style>
</head>
<body>
<div class="column">
<h1>Dynamic</h1>
<p>
This <code><audio></code> tag starts out having no
<code><source></code> tags. Those tags get added when the
user taps on the "Play Audio" link below. Each subsequent tap
removes the <code><source></code> tags and re-adds them
again. The audio isn't played until the amount of time
specified in the "Timeout" dropdown menu has passed.
</p>
<p>
Timeout:
<select id="timeout">
<option value="0">None</option>
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
<option value="50">50</option>
<option value="60">60</option>
<option value="70">70</option>
<option value="80">80</option>
<option value="90">90</option>
<option value="100">100</option>
<option value="150">150</option>
<option value="200">200</option>
<option value="250">250</option>
<option value="300">300</option>
<option value="350">350</option>
<option value="400">400</option>
<option value="450">450</option>
<option value="500">500</option>
</select>
</p>
<audio id="audio_test_dynamic" data-log-id="audio_test_dynamic_log"></audio>
<p><a href="javascript:click_handler_dynamic();">Play Audio</a></p>
<div class="log" id="audio_test_dynamic_log"></div>
</div>
<div class="column">
<h1>Static</h1>
<p>
This <code><audio></code> tag's
<code><source></code> tags are hard-coded.
</p>
<audio id="audio_test_static" data-log-id="audio_test_static_log">
<source src="http://www.html5tutorial.info/media/vincent.mp3" type="audio/mpeg">
<source src="http://www.html5tutorial.info/media/vincent.ogg" type="audio/ogg">
</audio>
<p><a href="javascript:click_handler_static();">Play Audio</a></p>
<div class="log" id="audio_test_static_log"></div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
var events = [
'abort',
'addsourcebuffer',
'canplay',
'canplaythrough',
'cuechange',
'durationchange',
'emptied',
'ended',
'error',
'loadeddata',
'loadedmetadata',
'loadstart',
'mskeyadded',
'mskeyerror',
'mskeymessage',
'onaddtrack',
'onchange',
'onmsneedkey',
'onremovetrack',
'pause',
'play',
'playing',
'progress',
'ratechange',
'removesourcebuffer',
'seeked',
'seeking',
'sourceclose',
'sourceended',
'sourceopen',
'stalled',
'suspend',
'timeupdate',
'update',
'updateend',
'updatestart',
'volumechange',
'waiting'
];
$.each(events, function(index, event) {
$('audio').on(event, function() {
$('#' + $(this).data('log-id')).prepend(event + '<br>');
});
});
function click_handler_dynamic() {
var timeout = parseInt($('#timeout').val(), 10);
$('#audio_test_dynamic_log').prepend('---timeout set to ' + timeout + '---<hr>');
$('#audio_test_dynamic').empty().html(
'<source src="http://www.html5tutorial.info/media/vincent.mp3" type="audio/mpeg">' +
'<source src="http://www.html5tutorial.info/media/vincent.ogg" type="audio/ogg">'
);
$('#audio_test_dynamic')[0].load();
if (timeout) {
setTimeout(function() {
$('#audio_test_dynamic')[0].play();
}, timeout);
}
else {
$('#audio_test_dynamic')[0].play();
}
}
function click_handler_static() {
$('#audio_test_static_log').prepend('<hr>');
$('#audio_test_static')[0].play();
}
</script>
</body>
</html>
我在运行 Android 4.1.2 的股票浏览器的摩托罗拉 Xoom 上尝试了上述代码。我发现如果我加载(或刷新)页面,将“超时”下拉菜单设置为“无”,然后点击“动态”部分的“播放音频”链接,通常无法播放。我使用各种超时选项尝试了同样的事情,发现它在 200 左右开始变得相当可靠。它在 400 左右变得非常可靠。我认为我没有看到 400 失败。问题是,我不想在这个摩托罗拉 Xoom 上找到一个永远不会失败的数字,然后假设它在任何其他设备上都不会失败。我也不想在音频播放之前有这么高的延迟。如果我能以某种方式检测到它什么时候没有播放,然后强制它再次尝试播放,限制为五或十次尝试,那就太好了。不过,我不知道我能做些什么来检测失败的游戏。成功播放的输出看起来与失败播放的输出非常相似,至少在摩托罗拉 Xoom 上是如此。这是一场成功的比赛的输出(按时间倒序排列):
- 暂停
- 结束
- timeupdate(连续多次)
- 持续时间变化
- 时间更新
- 正在播放
- 可以通关
- 可以玩
- 加载数据
- 加载元数据
- 持续时间变化
- 进展
- 等待中
- 播放
- 加载开始
- 清空
成功播放的输出和失败播放的输出之间的唯一区别是上面列表中的第 3 项和第 4 项不存在(之前发生的多个 timeupdates 和 durationchange) .如果我在播放失败后再次点击“播放音频”链接并再次失败,这就是输出的样子(同样,它是按时间倒序排列的):
- 暂停
- 正在播放
- 可以通关
- 可以玩
- 加载数据
- 加载元数据
- 持续时间变化
- 进展
- 等待中
- 播放
- 加载开始
- 清空
- 中止
如果我点击链接足够多次,它最终会播放。
我可以做些什么来检测播放失败并让它再次尝试播放?
【问题讨论】:
标签: javascript android html5-audio