부트캠프 JavaScript 막바지쯤 브라우저에서 제공하는 음성 녹음 기능을 구현했다. 한 번도 구현해 본 적이 없는 기능이어서 정리해보려고 한다.

화면에 위와같이 두 버튼을 만들어준다

HTML 코드

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>음성 녹음</title>
		<link rel="icon" type="image/png" href="#" />
		<script src="jquery-3.7.1.min.js"></script>
		<script src="voiceRecord.js"></script>
	</head>
	<body>
		<button id="recordBtn">녹음</button> 
		<button id="stopBtn">정지</button>
		
		<!-- <audio> 컨트롤 동적 추가 -->
		<div id="sound-clips"></div>
	</body>
</html>

윈도우 실행 시 코드를 실행하도록 window.onload() 함수 안에 정의한다.

window.onload = function() {...}

id를 이용해서 태그를 가져온다.

let record = document.getElementById("recordBtn");
let stop = document.getElementById("stopBtn");
let soundClips = document.getElementById("sound-clips");

브라우저에 media device라는 인터페이스가 있는지 확인 후,

if (navigator.mediaDevices)

있으면 if문 안에 constraints를 정의해준다.

var constraints = {
	audio:true // 마이크 사용하겠다!
	// video: false // 카메라는 안 쓰겠다!
}
		

녹음 데이터를 저장할 배열을 생성하고,

let chunks = [];

브라우저에서 제공하는 기본 객체를 가져다가

navigator

현재 연결된 미디어 입력장치로의 접근 방법 제공하는 인터페이스를 호출해서

navigator.mediaDevices

사용자에게 카메라나 마이크를 사용할 수 있는 권한을 요청한다. 이때 constraints를 넘겨주어 요청이 필요한 것에만 요청한다.

navigator.mediaDevices.getUserMedia(constraints)

여기까지 과정이 끝나면 브라우저에 위와같이 권한 요청 창이 뜬다.

getUserMedia()는 Promise를 반환하는데 사용자가 마이크 접근을 허락하면 이 약속이 "성공" 상태로 바뀌고, then() 안에 있는 함수를 실행할 수 있다.

.then((stream) => { ... }

(여기서 stream은 브라우저가 마이크를 열어주어 그 마이크로부터 들어오는 오디오 데이터이다.)

녹음을 위한 MediaRecorder 클래스 사용해서 녹음 객체를 생성하고 stream객체를 생성자에 전달한다.

const mediaRecorder = new MediaRecorder(stream);

녹음 버튼을 클릭했을 때 작업을 정의해준다.

record.onclick = () => {
	mediaRecorder.start(); // 녹음 시작
	record.style.background = "red"; // 녹음 버튼 배경 색상 변경
	record.style.color = "black"; // 녹음 버튼 글자 색상 변경
}

브라우저에는 녹음 아이콘이 표시된다

유효한 녹음 데이터가 들어온다면 다음 함수를 실행하게된다.
이벤트 객체에는 녹음데이터가 data라는 이름으로 담겨있다. 이를 앞서 정의한 배열에 넣어준다.

mediaRecorder.ondataavailable = e => { 
	chunks.push(e.data)
}

(이때 e.data는 아직 사용할 수 없는 상태이다. mp3 및 코덱 설정을 아직 안해주었기 때문이다.)

정지버튼을 클릭했을 때 작업을 정의해준다.

stop.onclick = () => {
	mediaRecorder.stop(); // 녹음 정지
	record.style.background = ""; // 원래 상태로 되돌림
    record.style.color = ""; // 원래 상태로 되돌림
}

녹음이 정지되면 발생하는 onstop이벤트를 정의해준다

mediaRecorder.onstop = e => {...}

이제 녹음을 끝냈으니 stop이벤트 후 녹음 파일을 다운받을 수 있도록 해 줄 것이다.
순서는 다음과 같다.
1. audio 담을 컨테이너 객체 생성

const clipContainer = document.createElement('article'); // article 태그 생성
  1. audio 객체 생성 속성 설정
const audio = document.createElement('audio');
audio.setAttribute('controls', ''); // name, value설정
									// 재생, 일시정지, 음량 조절 등 기본 UI를 브라우저에 표시
                                    // ontrols 같은 boolean 속성은 빈 문자열도 값으로 허용
  1. audio 객체와 컨테이너 객체 연결 (이전 내용 삭제)
clipContainer.appendChild(audio);
if (soundClips.hasChildNodes()){
	soundClips.removeChild(soundClips.childNodes[0]);
}
  1. sound-clip에 컨테이너 연결
soundClips.appendChild(clipContainer);
  1. 녹음된 데이터를 audio양식으로 설정 -> 2진수를 mp3로 변환
const blob = new Blob(chunks, {
						'type':'audio/mp3 codcs=opus'
					})
chunks = []; // 녹음 내용이 누적되지 않도록 초기화
  1. 녹음 내용을 파일로 저장 -> 다운로드
const audioURL = URL.createObjectURL(blob); // mp3, 코덱 설정 후 url 객체 생성
audio.src = audioURL;
					
const clipName = "voiceRecord"; // 다운로드시 사용할 파일 이름
const a = document.createElement('a'); // a 태그를 생성
clipContainer.appendChild(a);

// a태그는 download 속성이 있고 파일명을 주면 클릭이벤트 발생시 해당 파일명으로 다운로드를 진행함
a.href = audio.src;

a.download = clipName;
a.click(); 

정지 버튼을 누르면

이렇게 컨트롤 바가 뜨고

이렇게 파일 저장 화면이 나온다

외부 장치를 사용했으니 .then() 예외처리는 필수다

0개의 댓글