본문 바로가기
개발(Development)/Media(오디오&비디오 개발)

[자바스크립트] MediaElementAudioSourceNode 음원 파일(mp3, wav 등) 사용 방법

by 카레유 2022. 1. 20.

Web Audi API는 음원의 타입(파일, 버퍼, 스트림 등)에 따라 소스Node와 작업 방식이 조금씩 다르다.

 

45초 이상의 긴 음원 파일(mp3, wav)을 다루기 위해서는

MediaElementAudioSourceNode를 소스Node로 이용해야 한다.

 

이 글에서는 MediaElementAudioSourceNode를 통해 mp3 등의 음원파일을 다루는 방법을 정리한다.

 

 

※ Web Audio API의 기본 사용 방법은 아래 글 참고

[자바스크립트] Web Audio API 기본 원리와 예제 코드

 

※  45초 이하의 짧은 음원을 다루는 AudioBufferSourceNode는 아래 글 참고

[자바스크립트] AudioBuffer, AudioBufferSourceNode 사용 방법 & 예제 코드


# MediaElementAudioSourceNode 란?

MediaElementAudioSourceNode는 HTMLMeidaElement를 음원으로 입력 받는 소스 Node 이다.

HTMLMeidaElement에는 <audio>, <video> 엘리먼트가 있다.

 

1) HTML 상의 <audio>, <video> 엘리먼트를 자바스크립트로 참조하거나

2) 자바스크립트 상에서 Audio객체를 직접 생성해서 사용하면 된다.

 

단, MediaElementAudioSourceNode는 start(), stop()메서드가 지원되지 않는다.

따라서 음원 재생/정지 자체는 Audio, Video객체의 play(), pause() 메서드로 제어해야 한다.

MediaElementAudioSourceNode은 음원으로 입력되어 있는 Audio의 출력을 자동으로 트래킹한다.


# MediaElementAudioSourceNode 사용 방법

MediaElementAudioSourceNode를 통해 음원 파일(mp3 등)을 다루는 방법은 아래와 같다.

 

1. Audio 객체 생성

2. AudioContext 생성

3. 소스Node 생성

4. 작업Node 생성

5. Audio Graph 연결

6. Audio객체 재생

 

각각에 대해 상세하게 정리해보자.

 

 

1. Audio 객체 생성

HTML에 선언한 <audio>태그를 참조하는 방법과, 자바스크립트에서 직접 Audio객체를 생성하는 방법이 있다.

 

1) HTML의 Audio태그 참조:

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>audio</title>
</head>

<body>
    <audio id="myAudio" src="./sample.mp3"></audio>
</body>

<script>
    // HTML의 audio엘리먼트 참조 코드
    const audio = document.getElementById("myAudio"); 
</script>

<html>

 

 

2) JS에서 Audio객체 생성

const audio = new Audio("./sample.mp3");

 

 

2. AudioContext 생성

: Web Audio API에서는 모든 작업이 AudioContext를 통해 이루어진다.

const audioContext = new (window.AudioContext || window.webkitAudioContext)();

* AudioContext는 window의 프로퍼티이므로 전역에서 사용 가능하다.

* 크로스 브라우저 호환성을 위해 webkit을 사용한다.

 

 

3. 소스Node 생성

: MediaElementAudioSourceNode 객체를 생성 하면서 Audio객체를 음원으로 주입해준다.

 

1) 메서드 방식

const mediaElementSource = audioContext.createMediaElementSource(audio);

 

2) 생성자 방식: 일부 브라우저에서 지원되지 않을 수 있다.

const mediaElementSource = new MediaElementAudioSourceNode(audioContext, {mediaElement: audio});

 

 

4. 작업Node 생성

: GainNode 등의 작업Node를 통해 필요한 작업을 수행해준다.

const gainNode = audioContext.createGain(); // 볼륨 설정용 작업 노드
gainNode.gain.value = 0.5; // 0 ~ 1 사이의 볼륨 설정

 

 

5.  Audio Graph 연결

: 소스Node -> 작업Node들 -> 목적지Node 연결

mediaElementSource.connect(gainNode).connect(audioContext.destination);

* 목적지 출력Node는 AudioContext.destination 으로 참조할 수 있다.

* connect()메서드는 AudioNode에 정의된 메서드로 호출자Node에 파라미터Node를 연결한 객체를 반환하므로 연쇄 호출이 가능하다.

* 참고로 모든 종류의 "소스노드"와 "작업노드"는 AudioNode를 상속받는다.

 

 

6. Audio 객체 재생/정지 처리

audio.play(); // 재생
audio.pause(); // 정지

* 일부 브라우저(특히 크롬)의 경우, 사용자 제스처가 있어야만 오디오의 재생 및 AudioContext 사용이 가능하다.


# MediaElementSourceNode 예제 코드

: mp3 음원 파일을 MediaElementSourceNode를 통해 다루는 코드다.

: 버튼을 누르면 mp3파일이 재생되고, 슬라이드바를 통해 볼륨을 조절할 수 있다.

*** 당연히 sample.mp3 파일은 별도로 준비되어 있어야 한다.

*** 근데 아마 크롬 브라우저에서 실행한다면 아래와 같은 에러 코드를 만나게 될 것이다.(해결 방법은 글의 하단에 있다.)

--- MediaElementAudioSource outputs zeroes due to CORS access restrictions

 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MediaElementAudioSourceNode</title>
</head>
<body>
    
    <!-- 재생/정지 버튼 -->
    <button id="btn_play">재생/정지</button>

    <br><br>

    <!-- 볼륨 조절바 -->
    <label for="seekbar_volume">볼륨 조정</label>
    <input type="range" name="seekbar_volume" id="seekbar_volume" min="0" max="100" value="50">

    <!-- HTML에서 audio엘리먼트 선언 후, JS에서 참조해 사용해도 된다 -->
    <!-- <audio id="myAudio" src="./sample.mp3"></audio> -->
</body>

<script>
    // 1. Audio 객체 생성
    const audio = new Audio("./sample.mp3");
    // const audio = document.getElementById("myAudio"); // HTML의 audio엘리먼트 참조 코드
    

    // 2. AudioContext 생성
    const audioContext = new (window.AudioContext || window.webkitAudioContext)();
    

    // 3. 소스 Node 생성: 
    // - mp3등의 파일은 MediaElementAudioSourceNode를 소스Node로 사용해야 한다.
    // - MediaElementAudioSourceNode는 Audio객체를 음원으로 입력 받는다.
    const mediaElementSource = audioContext.createMediaElementSource(audio); // 메서드 방식
    // const mediaElementSource = new MediaElementAudioSourceNode(audioContext, {mediaElement: audio}); // 생성자 방식
    

    // 4. 작업 Node 생성
    // // GainNode: 볼륨 설정 용도
    const gainNode = audioContext.createGain(); // gainNode로 볼륨 설정 가능
    gainNode.gain.value = 0.5; // 볼륨 크기는 0~1 사이로 설정
    

    // 5. 소스Node -> 작업Node들 -> 목적지Node 연결
    mediaElementSource.connect(gainNode).connect(audioContext.destination);


    // 6. Audio 객체 재생/정지 처리
    document.getElementById("btn_play").onclick = (event)=>{
        if(audio.paused){
            // audioContext 작동 처리
            // 크롬에서는 사용자의 제스처가 있어야만 audioContext를 작동시킬 수 있다.)
            audioContext.resume();

            // 재생 시작: 재생 자체는 Audio객체를 통해 수행해야 한다.
            // MediaElementAudioSourceNode는 start()메서드가 없다.
            audio.play(); 

        }else{
            // 재생 멈춤
            audio.pause(); 
        }
    }
    
    // 볼륨 조절 이벤트 처리
    document.getElementById("seekbar_volume").oninput = (event)=>{
        // GainNode를 통해 음원의 gain값(==볼륨)을 조정할 수 있다.
        gainNode.gain.value = parseInt(event.currentTarget.value)/100; // 0~1사이로 변환
    }

</script>

    
</html>

 


 주의 사항

1. CORS 이슈

- 일부 브라우저의 경우(특히 크롬) CORS 정책으로 인해 로컬 음원파일(mp3등)을 불러와 사용할 수 없다.

- 즉, MediaElementAudioSource outputs zeroes due to CORS access restrictions 에러를 만나게 된다.

- 이 문제를 해결하기 위해서는 서버 환경에서 구동해 주어야 하는데, VSCode 작업 환경에서 테스트 중이라면 Live Server를 통해 실행시켜 주면 된다.

- 아니면 그냥 사파리 같은 다른 브라우저에서 실행해주면 된다.

 

2. 사용자 제스처 이슈

- 일부 브라우저의 경우(특히 크롬), 사용자의 제스처가 없으면 AudioContext가 구동되지 않는다.

- 사용자 클릭 등이 없는 상태에서 AudioContext 객체를 생성하면 AudioContext가 동작하지 않으며, The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. 에러를 만나게 된다.

- 이 문제를 해결하기 위해서는 사용자의 제스처(클릭 등)를 입력받는 이벤트 핸들러 등에서 AudioContext 객체를 생성해주거나, AudioContext.resume()을 호출해 재가동 해주면 된다.

 

3. MeidaElementAudioSource의 음원 재생 이슈

- MediaElementAudioSourceNode는 입력된 음원을 직접 재생할 수 없다.

- 음원의 재생 자체는 Audio객체의 play(), pause() 메서드로 컨트롤 해야 한다.

- 자세한 내용은 아래의 소스Node의 상속구조를 참고하자.


※ 참고: "소스 Node"의 상속구조 

AudioNode

ㄴ MediaElementAudioSourceNode

 MediaStreamAudioSourceNode

 AudioScheduledSourceNode 
    ㄴ OscillatorNode

    ㄴ AudioBufferSourceNode

 

- start(), stop() 메서드는 AudioScheduledSourceNode 에만 정의 되어 있다.

- 따라서 AudioScheduledSourceNode를 상속 받는 OscillatorNode, AudioBufferSourceNode만 start(), stop() 메서드로 직접 재생/정지가 가능하다.

- AudioScheduledSourceNode 를 상속받지 않는 MediaElementAudioSourceNode, MediaStreamAudioSourceNode는 start(), stop() 메서드를 사용할 수 없다.


MediaElementAudioSourceNode 에 대해 나름대로 상세하게 정리해보았다.

자바스크립트로 Audio를 다루려는 분들에게 도움이 되길 바란다.

 

 

 

댓글