피드로 돌아가기
TIL canvas.captureStream() is video-only — here's how I mixed voiceover + music into a MediaRecorder export" published: true
Dev.toDev.to
Frontend

AudioContext Graph 설계를 통한 Web-based 비디오 믹싱 및 무손실 캡처 구현

TIL canvas.captureStream() is video-only — here's how I mixed voiceover + music into a MediaRecorder export" published: true

Robert Corn2026년 5월 10일8advanced

Context

canvas.captureStream()이 비디오 트랙만 포함하는 제약으로 인해 오디오 믹싱 데이터 유실 발생. 단순 addTrack() 방식은 createMediaElementSource()의 일회성 호출 제한 및 muted 속성에 따른 스트림 단절 문제로 인해 구현 불가능한 구조임.

Technical Solution

  • AudioContext 싱글톤과 Map<HTMLMediaElement, gainNode>를 활용해 모든 미디어 요소를 마운트 시점에 단 한 번만 바인딩하는 구조 설계
  • masterGain 노드를 통한 스피커 출력 제어와 MediaStreamDestination을 통한 내보내기 경로를 분리하여 프리뷰 뮤트와 무관한 독립적 오디오 캡처 구현
  • recorder.onstop 시점에 disconnect()를 호출하여 MediaStreamDestination 인스턴스 중첩으로 인한 에코 및 팬아웃 제한 문제 해결
  • audioContext.resume() 이후 150ms의 Grace Period를 부여해 브라우저별 오디오 초기 버퍼링 지연으로 인한 초반 무음 구간 제거
  • 오디오 유무에 따라 MediaRecorder(정확성 우선)와 WebCodecs(속도 우선) 경로를 선택하는 조건부 파이프라인 채택

1. `createMediaElementSource` 호출은 컴포넌트 라이프사이클 외부에 저장해 중복 호출 방지

2. 사용자 경험(Preview Mute)과 데이터 캡처(Export) 경로를 Gain Node 단계에서 분리

3. `MediaStreamDestination` 사용 후 반드시 명시적 `disconnect` 수행

4. `AudioContext` 활성화 후 짧은 대기 시간을 두어 초기 오디오 유실 방지

원문 읽기