앞의 글에서 stop() 메서드가 호출된 오디오 소스 노드는 재활용이 불가능하고, 오디오를 다시 재생하기 위해서는 새로운 소스 노드를 생성해야 함을 살펴보았다. 그리고 이를 활용한 오디오의 재생-멈춤-(이어서)재생 방법에 대해서도 살펴보았다.
오디오 그래프의 currentTime 속성 값은 audio context 객체의 resume() 메서드를 통해 오디오 그래프가 활성화된 이후로 계속 증가한다. 따라서 이를 이용해서 start() 시점과 stop() 호출 시점의 차이를 구하면 오디오를 얼마나 재생했는지 알 수 있고 멈췄던 오디오를 이어서 재생할 수 있다.
멈춘 오디오를 이어서 재생하기 위해 어느 시점에 오디오 소스 노드를 새로 생성해야 하는지 전체 코드의 관점에서 살펴보자. 아래 예제 코드는 서버로부터 오디오 데이터를 가져오는 Fetch API 부분을 중심으로 코드를 본 것이다.
fetch('/get_audio_data', {
method: 'POST', body: formData
}).then((response) => {
return response.blob();
}).then((resBody) => {
resBody.arrayBuffer().then((buffer) => {
// 오디오 데이터 해석(decoding)
audioContext.decodeAudioData(...);
playPauseButton.addEventListener('click', (event) => {
// 오디오 그래프 활성화(=resume() 메서드 호출)
audioContext.resume();
if(멈춤 상태인 경우){
startTime = audioContext.currentTime;
// 오디오 그래프 재구성
source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioContext.destination);
source.start(0, elapsedTime);
}
else{
// 재생 시간 계산 및 멈춤
elapsedTime = (elapsedTime + audioContext.currentTime - startTime)%source.buffer.duration;
source.stop();
}
});
}).catch((error) => {
// arrayBuffer() 메서드 호출 오류 처리
});
}).catch((error) => {
// fetch API 호출 오류 처리
});
예제 코드에서는 오디오가 재생되는 시점, 즉 사용자가 '재생/멈춤' 버튼을 클릭했을 때 오디오 소스 노드를 생성하고 오디오 그래프를 재구성하였다. 예제에서와 같이 굳이 오디오 그래프를 비활성화(suspend() 메서드 호출) 시키지 않고 오디오 그래프가 활성화된 상태(=audio context의 상태가 'running')에서도 오디오 그래프는 재구성 될 수 있다.
오디오 소스 노드 생성 및 오디오 그래프 재구성 시점을 보기 위해 생략했던 부분까지 포함한 전체 코드를 나타내면 아래와 같다. 재생-멈춤-이어서 재생 기능을 구현하기 위해 어느 시점에서 재생 시간(elapsed time)을 계산하고 또 어느 시점에 오디오 소스 노드를 재생성하고 오디오 그래프를 재구성하는지 살펴볼 수 있을 것이다.
var formData = new FormData();
formData.set('fileName', document.querySelector('p').innerHTML);
fetch('/get_audio_data', {
method: 'POST',
body: formData
}).then((response) => {
return response.blob();
}).then((resBody) => {
resBody.arrayBuffer().then((buffer) => {
var audioBuffer = null;
var source = null;
audioContext.decodeAudioData(buffer, (buffer) => {
audioBuffer = buffer;
});
var startTime = 0;
var elapsedTime = 0;
playPauseButton.addEventListener('click', (event) => {
if(audioContext.state == 'suspended'){
audioContext.resume();
}
if(event.target.dataset.playing == 'false'){
event.target.dataset.playing = 'true';
event.target.innerHTML = 'Pause';
startTime = audioContext.currentTime;
source = audioContext.createBufferSource();
source.buffer = audioBuffer;
source.connect(audioContext.destination);
source.start(0, elapsedTime);
}
else{
event.target.dataset.playing = 'false';
event.target.innerHTML = 'Play';
elapsedTime = (elapsedTime + audioContext.currentTime - startTime)%source.buffer.duration;
source.stop();
}
});
}).catch((error) => {
console.log('[Error] resBody.arrayBuffer: ', error);
});
}).catch((error) => {
console.log('[Error] fetch.getAudioData: ', error);
});
만약 코드의 특정 라인의 의미가 이해되지 않는다면 이전 글 '[Web Audio API] 재생-멈춤-재생' 참고를 부탁드린다. 이전 글에서 기능 구현을 위한 요소들에 대해 설명해두었다.
■
'웹 오디오 프로그래밍' 카테고리의 다른 글
[Web Audio API #7] 음량 조절 (0) | 2021.07.04 |
---|---|
[Web Audio API #6] 여러개의 웹 오디오 소스 재생 잠시멈춤 (0) | 2021.07.01 |
[Web Audio API #4] 재생-멈춤-재생 (0) | 2021.06.28 |
[Web Audio API #3] 오디오 재생 - 서버 (0) | 2021.06.25 |
[Web Audio API #2] 오디오 재생 (0) | 2021.06.18 |
댓글