2012-07-16 510 views
8

我經常讀到,無法使用Web Audio API暫停/恢復音頻文件。
但現在我看到一個example他們實際上可以暫停和恢復它。我試圖弄清楚他們是怎麼做到的。我想也許source.looping = false是關鍵,但事實並非如此。
現在我的音頻始終從頭播放。Web音頻API從暫停恢復

這是我當前的代碼

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

有誰知道做什麼,得到它的工作?

回答

5

無需花費任何時間檢查你的榜樣的來源,我說你要使用AudioBufferSourceNode的noteGrainOn方法(https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#methodsandparams-AudioBufferSourceNode

只是跟蹤你是如何在緩衝區中,當你打電話給noteOff,然後在新的AudioBufferSourceNode上恢復時從那裏做noteGrainOn。

這有道理嗎?

編輯: 有關更新的API調用,請參閱下面的註釋。

+0

那麼他在示例中沒有使用'noteGrainOn()'(儘管如此,仍然無法弄清楚他是如何做到的)。但無論如何,這是一種魅力,所以我將把它作爲一個被接受的答案。謝謝:) – 2012-07-16 14:59:49

+1

noteGrainOn()現在已經在spec中重命名了,就像noteOn() - 都是現在的play(),有或沒有grain偏移參數。儘管如此,還沒有看到這種支持。 – LeeGee 2012-10-03 12:53:50

+1

它實際上是'開始'(有或沒有參數'開始(howSoonRelativeToCurrentTime,fromSecondInBuffer,forDuration)'),它似乎在鉻金絲雀工作 – 2013-01-27 10:12:43

15

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); 
0

在WebAudio API中缺少內置的暫停功能似乎是對我的一個重大疏漏。可能,將來可以使用計劃的MediaElementSource來完成此操作,它可以讓您將一個元素(支持暫停)連接到Web Audio。目前,大多數解決方法似乎基於記憶播放時間(如imbrizi的答案中所述)。這樣的解決方法在循環聲音時會遇到問題(執行循環是否無間隙?),以及何時允許動態更改聲音的播放速率(因爲兩者都會影響定時)。另外,你可以使用,同樣劈十歲上下,技術上不正確的,但更簡單的解決方法是:

source.playbackRate = paused?0.0000001:1; 

遺憾的是,0不是playbackRate有效值(這實際上將暫停的聲音)。但是,對於許多實際用途,某些非常低的值(如0.000001)足夠接近,並且不會產生任何聲音輸出。

+0

+10爲快速入侵:-) – Sam 2014-05-25 16:50:11

+0

這不是一個好主意,因爲您將阻止瀏覽器清除任何未使用的音頻緩衝區。使用API​​實際上有點笨拙,但是它出於性能和內存效率的原因而設計。 OPs問題中的小包裝庫是更好的方法。 – 2014-06-14 11:43:33

0

更新:這隻適用於Chrome。 Firefox(v29)尚未實現MediaElementAudioSourceNode.mediaElement屬性。

假設你已經有了AudioContext參考和媒體來源(例如通過AudioContext.createMediaElementSource()方法調用),您可以將您的來源,例如在呼叫MediaElement.play()MediaElement.pause()

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

不需要黑客和變通辦法,它是受支持的。 如果您使用<audio>標記作爲源,則不應直接在JavaScript中的音頻元素上調用暫停,以停止播放。

9

在當前的瀏覽器(瀏覽器43,火狐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代碼)

3

實際上在網絡 - 音頻API可以爲您暫停並播放任務。它知道音頻方面的當前狀態(運行或暫停),這樣你就可以在這個簡單的方法做到這一點:

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

我希望這可以幫助。

0

2017年,使用ctx.currentTime非常適合追蹤歌曲中的點。下面的代碼使用一個按鈕(songStartPause),它在播放&暫停按鈕之間切換。爲了簡單起見,我使用了全局變量。變量musicStartPoint記錄您在歌曲中的時間。音樂api以秒爲單位記錄時間。

爲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設置你的初始musicStartPoint向然而到目前爲止你減去這首歌從什麼時候開始結束時間,並追加這段時間的長度最初在歌曲中。

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

*旁註:我知道這可能看起來更清潔的點擊功能設置songOnTime了,但我想這是有道理搶時間碼儘可能接近到src.start,就像我們如何搶暫停時間儘可能靠近src.stop。