16

我经常读到无法使用Web Audio API暂停/恢复音频文件。
但现在我看到了一个例子,他们实际上可以暂停和恢复它。我试图弄清楚他们是怎么做到的。我认为也许source.looping = false是关键,但事实并非如此。
现在我的音频总是从头开始重新播放。

这是我当前的代码

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;
};

有人知道该怎么做,让它工作吗?

4

9 回答 9

22

Oskar 的回答和 ayke 的评论非常有帮助,但我错过了一个代码示例。所以我写了一个: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);
于 2013-09-01T20:56:43.690 回答
16

在当前的浏览器(Chrome 43、Firefox 40)中,AudioContext 现在有 'suspend' 和 'resume' 方法可用:

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的修改示例代码)

于 2015-10-14T12:51:31.597 回答
8

实际上,网络音频 API 可以为您完成暂停和播放任务。它知道音频上下文的当前状态(运行或暂停),因此您可以通过以下简单方式执行此操作:

susresBtn.onclick = function() {
  if(audioCtx.state === 'running') {
    audioCtx.suspend()
  } else if(audioCtx.state === 'suspended') {
    audioCtx.resume()  
  }
}

我希望这会有所帮助。

于 2016-03-16T17:56:06.753 回答
6

无需花费任何时间检查示例的来源,我会说您将要使用 AudioBufferSourceNode 的 noteGrainOn 方法(https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/规范.html#methodsandparams-AudioBufferSourceNode )

只需跟踪调用 noteOff 时进入缓冲区的距离,然后在新的 AudioBufferSourceNode 上恢复时从那里执行 noteGrainOn。

这有意义吗?

编辑: 有关更新的 API 调用,请参阅下面的评论。

2019 年第 2 版:请参阅 MDN 了解更新的 API 调用;https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode/start

于 2012-07-16T14:45:55.983 回答
5

对于 chrome 修复,每次要播放声音时,请将其设置为:

if(audioCtx.state === 'suspended') {
    audioCtx.resume().then(function() {
      audio.play();
   });  
}else{
     audio.play();
}
于 2018-12-27T17:54:21.393 回答
0

WebAudio API 中缺乏内置的暂停功能对我来说似乎是一个重大疏忽。将来可能会使用计划的 MediaElementSource 来执行此操作,这将使您可以将元素(支持暂停)连接到 Web 音频。目前,大多数解决方法似乎都是基于记住播放时间(例如 imbrizi 的回答中所述)。这样的解决方法在循环声音时会出现问题(实现是否循环无缝?),以及当您允许动态更改声音的播放速率时(因为两者都会影响时间)。另一个同样 hack-ish 并且在技术上不正确,但您可以使用的更简单的解决方法是:

source.playbackRate = paused?0.0000001:1;

不幸的是, 0 不是一个有效的回放速率值(它实际上会暂停声音)。但是,对于许多实际用途,一些非常低的值(例如 0.000001)已经足够接近,并且不会产生任何可听输出。

于 2014-01-09T09:29:27.713 回答
0

更新:这仅对 Chrome 有效。Firefox (v29) 尚未实现该MediaElementAudioSourceNode.mediaElement属性。

假设您已经拥有 AudioContext 引用和媒体源(例如通过AudioContext.createMediaElementSource()方法调用),您可以在源上调用MediaElement.play()MediaElement.pause(),例如

source.mediaElement.pause();
source.mediaElement.play();

无需破解和变通方法,它是受支持的。如果您使用<audio>标签作为源,则不应直接在 JavaScript 中的音频元素上调用 pause,这将停止播放。

于 2014-05-27T13:26:13.807 回答
0

在 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);
}

*旁注:我知道在 click 函数中设置 songOnTime 可能看起来更简洁,但我认为尽可能接近 src.start 获取时间码是有意义的,就像我们如何尽可能接近获取暂停时间一样到 src.stop。

于 2017-01-20T18:07:34.290 回答
0

我没有关注完整的讨论,但我很快就会关注。我只是通过 HAL 演示来了解。对于那些现在喜欢我的人,我想告诉 1 - 如何让这段代码现在工作。2 - 从这段代码中获得暂停/播放的技巧。

1 : 将 noteOn(xx) 替换为 start(xx) 并将任何有效的 url 放入 sound.load() 中。我想这就是我所做的一切。您将在控制台中收到一些非常有指导意义的错误。跟着他们。或不:有时你可以忽略它们,它现在可以工作了:它与某些函数中的 -webkit 前缀有关。新的被给予。2:在某些时候,当它起作用时,您可能想要暂停声音。它会起作用的。但是,众所周知,新的比赛压力会引发错误。结果,错误的source_.start(0)之后的this.play()中的代码没有被执行。我只是将这些行包含在 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);
    })();
  }

它有效:您可以使用播放/暂停。我想提一下,这个HAL 模拟真的令人难以置信。按照这些简单的步骤,这是值得的!

于 2018-07-21T08:49:34.587 回答