Web Audio API resume from pause
Solution 1
Without spending any time checking the source of your example, I'd say you'll want to use the noteGrainOn method of the AudioBufferSourceNode (https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#methodsandparams-AudioBufferSourceNode)
Just keep track of how far into the buffer you were when you called noteOff, and then do noteGrainOn from there when resuming on a new AudioBufferSourceNode.
Did that make sense?
EDIT:
See comments below for updated API calls.
EDIT 2, 2019: See MDN for updated API calls; https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/start
Solution 2
Oskar's answer and ayke's comment are very helpful, but I was missing a code example. So I wrote one: http://jsfiddle.net/v3syS/2/ I hope it helps.
var url = 'http://thelab.thingsinjars.com/web-audio-tutorial/hello.mp3';
var ctx = new webkitAudioContext();
var buffer;
var sourceNode;
var startedAt;
var pausedAt;
var paused;
function load(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function() {
ctx.decodeAudioData(request.response, onBufferLoad, onBufferError);
};
request.send();
};
function play() {
sourceNode = ctx.createBufferSource();
sourceNode.connect(ctx.destination);
sourceNode.buffer = buffer;
paused = false;
if (pausedAt) {
startedAt = Date.now() - pausedAt;
sourceNode.start(0, pausedAt / 1000);
}
else {
startedAt = Date.now();
sourceNode.start(0);
}
};
function stop() {
sourceNode.stop(0);
pausedAt = Date.now() - startedAt;
paused = true;
};
function onBufferLoad(b) {
buffer = b;
play();
};
function onBufferError(e) {
console.log('onBufferError', e);
};
document.getElementById("toggle").onclick = function() {
if (paused) play();
else stop();
};
load(url);
Solution 3
In current browsers (Chrome 43, Firefox 40) there are now 'suspend' and 'resume' methods available for AudioContext:
var audioCtx = new AudioContext();
susresBtn.onclick = function() {
if(audioCtx.state === 'running') {
audioCtx.suspend().then(function() {
susresBtn.textContent = 'Resume context';
});
} else if(audioCtx.state === 'suspended') {
audioCtx.resume().then(function() {
susresBtn.textContent = 'Suspend context';
});
}
}
(modified example code from https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/suspend)
Solution 4
Actually the web-audio API can do the pause and play task for you. It knows the current state of the audio context (running or suspended), so you can do this in this easy way:
susresBtn.onclick = function() {
if(audioCtx.state === 'running') {
audioCtx.suspend()
} else if(audioCtx.state === 'suspended') {
audioCtx.resume()
}
}
I hope this can help.
Solution 5
For chrome fix, every time you want to play sound, set it like:
if(audioCtx.state === 'suspended') {
audioCtx.resume().then(function() {
audio.play();
});
}else{
audio.play();
}
dan-lee
Updated on May 23, 2020Comments
-
dan-lee about 4 years
I often read that it's not possible to pause/resume audio files with the Web Audio API.
But now I saw a example where they actually made it possible to pause and resume it. I tried to figure out what how they did it. I thought maybesource.looping = false
is the key, but it wasn't.
For now my audio is always re-playing from the start.This is my current code
var context = new (window.AudioContext || window.webkitAudioContext)(); function AudioPlayer() { this.source = context.createBufferSource(); this.analyser = context.createAnalyser(); this.stopped = true; } AudioPlayer.prototype.setBuffer = function(buffer) { this.source.buffer = buffer; this.source.looping = false; }; AudioPlayer.prototype.play = function() { this.source.connect(this.analyser); this.analyser.connect(context.destination); this.source.noteOn(0); this.stopped = false; }; AudioPlayer.prototype.stop = function() { this.analyser.disconnect(); this.source.disconnect(); this.stopped = true; };
Does anybody know what to do, to get it work?
-
dan-lee almost 12 yearsWell he doesn't use
noteGrainOn()
in the example (still can't figure out how he does it, though). But anyway, this works like a charm, so I will take this as an accepted answer. Thank you :) -
Lee Goddard over 11 yearsnoteGrainOn() has now been renamed in the spec, as has noteOn() -- both are now play(), with or without a grain offset argument. Haven't seen this supported yet, though.
-
Misha Reyzlin over 11 yearsit's actually
start
(with or without argumentsstart(howSoonRelativeToCurrentTime, fromSecondInBuffer, forDuration)
) and it seems to work in Chrome Canary -
ayke over 11 years
start
andstop
can only be used only once: w3.org/TR/webaudio/#methodsandparams-AudioBufferSourceNode, but it is possible to make a newAudioBufferSourceNode
from the sameAudioBuffer
and start it at the position where the last was stopped (with anoffset
). -
Chris Lowis about 10 yearsThis isn't a great idea, as you'll prevent the browser from cleaning up any unused audio buffers. It's a little clunky to work with the API as it is, but it's designed that way for reasons of performance and memory efficiency. A small wrapper library like in the OPs question is a better approach.
-
bryc about 5 yearsAll of this is deprecated now, so this answer is useless. No
noteGrainOn
, nonoteOn
, noplay
, nothing. -
Oskar Eriksson about 5 yearsAs the comments above mentions - this is now contained in the start method.
-
Jespertheend over 3 yearsYou're better off using
ctx.currentTime
instead ofDate.now()
. That way the time gets preserved when suspending and resuming the context. And I think it might even be more accurate as well. -
B''H Bi'ezras -- Boruch Hashem over 2 yearsbut how do u pause it without stopping it?
-
B''H Bi'ezras -- Boruch Hashem over 2 yearsis there a way to change the current time, like for making custom audio players?
-
B''H Bi'ezras -- Boruch Hashem over 2 yearshow do u get the buffer data to a mediaelement?
-
B''H Bi'ezras -- Boruch Hashem over 2 yearshow do u pause it?