Web Audio API возобновление из паузы
Я часто читал, что невозможно приостановить/возобновить аудиофайлы с помощью Web Audio API.
Но теперь я увидел ... --8-->пример, где они фактически сделали возможным приостановить и возобновить его. Я пытался понять, как они это сделали. Я подумал, может быть ... --1--> - это ключ, но это не так.
На данный момент мой звук всегда воспроизводится заново с самого начала.
Это мой текущий код
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;
};
кто-нибудь знаешь, ЧТО ДЕЛАТЬ, чтобы заставить его работать?
8 ответов
не тратя времени на проверку источника вашего примера, я бы сказал, что вы захотите использовать метод noteGrainOn AudioBufferSourceNode (https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#methodsandparams-AudioBufferSourceNode)
просто следите за тем, как далеко в буфер вы были, когда вы вызвали noteOff, а затем do noteGrainOn оттуда при возобновлении на новом AudioBufferSourceNode.
Это смысл?
изменить: См. комментарии ниже для обновленных вызовов API.
ответ Оскара и комментарий Айка очень полезны, но мне не хватало примера кода. Поэтому я написал одно:2-->http://jsfiddle.net/v3syS/2/ я надеюсь, что это поможет.
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);
в текущих браузерах (Chrome 43, Firefox 40) теперь доступны методы "приостановить" и "возобновить" для 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';
});
}
}
(измененный пример кода изhttps://developer.mozilla.org/en-US/docs/Web/API/AudioContext/suspend)
на самом деле Web-audio API может выполнить задачу паузы и воспроизведения для вас. Он знает текущее состояние аудио контекста (работает или приостановлено), поэтому вы можете сделать это таким простым способом:
susresBtn.onclick = function() {
if(audioCtx.state === 'running') {
audioCtx.suspend()
} else if(audioCtx.state === 'suspended') {
audioCtx.resume()
}
}
Я надеюсь, что это может помочь.
отсутствие встроенной функции паузы в API WebAudio кажется мне серьезным упущением. Возможно, в будущем это можно будет сделать с помощью запланированного MediaElementSource, который позволит вам подключить элемент (который поддерживает паузу) к веб-аудио. На данный момент большинство обходных путей, похоже, основаны на запоминании времени воспроизведения (например, как описано в ответе имбризи). У такого обходного пути есть проблемы при циклическом звучании (делает ли цикл реализации gapless или нет?), и когда вы динамически разрешить изменить playbackRate звуков (как влияет на сроки). Другой, одинаково хакерский и технически некорректный, но гораздо более простой обходной путь, который вы можете использовать:
source.playbackRate = paused?0.0000001:1;
к сожалению, 0 не является допустимым значением для playbackRate (что фактически приостановит звук). Однако для многих практических целей некоторое очень низкое значение, например 0.000001, достаточно близко, и оно не будет производить никакого звукового выхода.
UPDATE: это действительно только для Chrome. Firefox (v29) еще не реализует MediaElementAudioSourceNode.mediaElement
собственность.
предполагая, что у вас уже есть ссылка AudioContext и ваш источник мультимедиа (например, через AudioContext.createMediaElementSource()
вызов метода), вы можете позвонить MediaElement.play()
и MediaElement.pause()
на вашем источнике, например
source.mediaElement.pause();
source.mediaElement.play();
нет необходимости в хаки и обходные пути, он поддерживается.
Если вы работаете с <audio>
тег в качестве источника, вы не должны вызывать паузу непосредственно на аудио элемент в вашем JavaScript, который остановит воспроизведение.
в 2017 году с помощью ctx.currentTime хорошо работает для отслеживания точки в песне. Приведенный ниже код использует одну кнопку (songStartPause), которая переключает кнопку воспроизведения. Я использовал глобальные переменные для простоты. Переменная musicStartPoint отслеживает, в какое время вы находитесь в песне. Музыкальный api отслеживает время в секундах.
установите начальную точку musicStartPoint в 0 (начало песни)
var ctx = new webkitAudioContext();
var buff, src;
var musicLoaded = false;
var musicStartPoint = 0;
var songOnTime, songEndTime;
var songOn = false;
songStartPause.onclick = function() {
if(!songOn) {
if(!musicLoaded) {
loadAndPlay();
musicLoaded = true;
} else {
play();
}
songOn = true;
songStartPause.innerHTML = "||" //a fancy Pause symbol
} else {
songOn = false;
src.stop();
setPausePoint();
songStartPause.innerHTML = ">" //a fancy Play symbol
}
}
используйте ctx.currentTime, чтобы вычесть время окончания песни с момента ее начала и добавьте это время к тому, как далеко вы были в песне изначально.
function setPausePoint() {
songEndTime = ctx.currentTime;
musicStartPoint += (songEndTime - songOnTime);
}
функции загрузки / воспроизведения.
function loadAndPlay() {
var req = new XMLHttpRequest();
req.open("GET", "//mymusic.com/unity.mp3")
req.responseType = "arraybuffer";
req.onload = function() {
ctx.decodeAudioData(req.response, function(buffer) {
buff = buffer;
play();
})
}
req.send();
}
function createBuffer() {
src = ctx.createBufferSource();
src.buffer = buff;
}
function connectNodes() {
src.connect(ctx.destination);
}
наконец, функция воспроизведения сообщает, что песня начинается с указанной musicStartPoint (и воспроизводится немедленно), а также устанавливает переменную songOnTime.
function play(){
createBuffer()
connectNodes();
songOnTime = ctx.currentTime;
src.start(0, musicStartPoint);
}
*Sidenote: я знаю, что это может выглядеть чище, чтобы установить songOnTime в функции click, но я считаю, что имеет смысл захватить код времени как можно ближе к src.начните, так же, как мы хватаем время паузы как можно ближе к src.остановка.
Я не следил за полным обсуждением, но скоро буду. Я просто направился к Хэлу демо, чтобы понять. Для тех, кто сейчас любит меня, я хотел бы сказать 1-Как заставить этот код работать сейчас. 2 - трюк, чтобы сделать паузу/воспроизведение, из этого кода.
1: Замените noteOn (xx) на start(xx) и поместите любой допустимый url в звук.нагрузка.)( Думаю, это все, что я сделал. Вы получите несколько ошибок в консоли, что довольно директивы. Следовать за ними. Или нет : иногда вы можете игнорировать их, это работает теперь : это связано с префиксом-webkit в некоторой функции. Даются новые. 2: в какой-то момент, когда он работает, вы можете приостановить звук. Это сработает. Но, как всем известно, новое давление на игру вызовет ошибку. В результате код в этом.play () после неисправного источника.start (0) не выполняется. Я просто заключил эти строки в try / catch:
this.play = function() {
analyser_ = context_.createAnalyser();
// Connect the processing graph: source -> analyser -> destination
source_.connect(analyser_);
analyser_.connect(context_.destination);
try{
source_.start(0);
}
catch(e){
this.playing = true;
(function callback(time) {
processAudio_(time);
reqId_ = window.webkitRequestAnimationFrame(callback);
})();
}
и это работает : вы можете использовать play / pause. Я хотел бы отметить, что это моделирование HAL это действительно невероятно. Следуйте этим простым шагам, это того стоит !