【发布时间】:2020-08-19 20:20:57
【问题描述】:
作为这篇文章的后续:How to rapidly play multiple copies of a soundfile in javascript 我创建了一个小型演示页面来说明我的问题的核心。
我的目标是在用户按住按钮时一遍又一遍地快速播放相同的音频文件,而不会使浏览器崩溃;-)(小提琴中的第二行)
我的初始方法使用克隆节点在 DOM 中创建多个音频对象。这在 chrome 和 edge 中实际上工作得很好,但是 safari 和 firefox 会在一段时间后遇到问题。这会导致音频不同步,并且在用户释放按钮后音频继续播放。
所以 Codebreaker007 建议使用音频上下文,这导致了几个不同的问题。 Chrome 回复:
AudioContext 不允许启动。它必须在页面上的用户手势之后恢复(或创建)。
Chrome 和 firefox 不播放音频文件。然后我按照谷歌指南,至少得到了错误消息,但仍然没有音频。使用 chrome 的网络音频插件,我可以在某一时刻看到音频节点正在正确创建。我怎样才能让他们听到?如何让音频上下文启动?
我想我已经很接近解决方案了,所以让我们一起解决这个问题。
<!doctype html>
<html class="h-100" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Test</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
AudioContext:true;
var clickingBuffer = null;
var timer
var inStart = 0
var inStop = 0
var timer = null
var type = ""
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
// =========== Variant 1: Clone Node ========== //
var sound = new Audio("https://sounds4email.com/wav/hellobaby.mp3");
sound.preload = 'auto';
sound.load();
function triggersound(){
console.log("triggerSound")
var click=sound.cloneNode();
click.volume=1;
click.play();
}
// =========== Variant 2: AudioContext ========== //
function loadClickSound(url) {
console.log("loading sound")
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
if (!buffer) {
console.log('Error decoding file data: ' + url);
return;
}
clickingBuffer = buffer;
});
request.onerror = function() {
console.log('BufferLoader: XHR error');
};
console.og("sound buffered")
request.send();
};
}
function playSound(buffer, time, volume) {
console.log("playSound")
context.resume().then(() => {
var source = context.createBufferSource(); // creates a sound source
source.buffer = buffer; // tell the source which sound to play
source.connect(context.destination); // connect the source to the context's destination (the speakers)
var gainNode = context.createGain(); // Create a gain node
source.connect(gainNode); // Connect the source to the gain node
gainNode.connect(context.destination); // Connect the gain node to the destination
gainNode.gain.value = volume; // Set the volume
source.start(time); // play the source at the deisred time 0=now
console.log('Playback resumed successfully');
});
}
// =========== RAPID FIRE ========== //
function stop() {
console.log("stop")
inStop = 1
}
// Initializing the spinning sequence. Blocking other user interaction
function start(tp) {
type = tp
console.log("active")
context.resume().then(() => {
console.log('Playback resumed successfully');
if (null === timer) {
timer = setInterval(timerCallback, 200)
inStart = 1
}
});
}
/**
* Timer callback
*/
function timerCallback() {
console.log(type + " " + inStart + " " + inStop)
if (inStart) {
if(type==="node"){
triggersound()
} else if(type==="context"){
playSound(clickingBuffer, 0, 1)
}
}
if (inStop) {
inStop = 0
clearTimeout(timer)
timer = null
console.log("stopped")
}
}
// =========== DOC READY ========== //
$( document ).ready(function() {
console.log( "ready!" );
// You call with in your document ready
loadClickSound("https://sounds4email.com/wav/hellobaby.mp3");
// Fix up prefixi
});
// =================================================================================//
</script>
</head>
<body class="d-flex flex-column align-content-center align-items-center justify-content-center w-100 h-100" >
<div class="row p-1 w-100">
<div class="col">
Click once:
</div>
<button id="clickNode" style="width: 100px; height: 100px;" class="col m-1" onclick="triggersound()">
Clone Node
</button>
<button id="clickContext" style="width: 100px; height: 100px;" class="col m-1" onclick="playSound(clickingBuffer, 0, 1)">
Audio Context
</button>
</div>
<div class="row p-1 w-100">
<div class="col">
Press and hold:
</div>
<button id="autoNode" style="width: 100px; height: 100px;" class="col m-1" onmousedown="start('node')" onmouseup="stop()">
Auto Clone Node
</button>
<button id="autoContext" style="width: 100px; height: 100px;" class="col m-1" onmousedown="start('context')" onmouseup="stop()">
Auto Audio Context
</button>
</div>
</body>
</html>
【问题讨论】:
标签: javascript