WebRTC의 MediaStream을 WebAudioAPI의 Filter로 처리하는 방법

개요



최근 SkyWay를 사용한 화상 채팅 시스템을 구축하고 있었지만, 하울링 대책으로서 고음을 저감해 주었으면 한다고 했다. 자바스크립트 경력 2개월인데 무차 말하지 마

찾는데 조금 고생했기 때문에 공부도 겸한 기억으로 남겨두려고 생각한다.

WebAudioAPI의 기본 개념



WebAudioAPI에서는, 마이크나 스피커라고 하는 입출력처나, 소리의 가공을 하는 필터등을 Node로서 표현한다. 이것들을 접속(connect)해 가는 것으로, 건네받은 순서로 처리되어 가는 구조가 되고 있다.

이번에는 Source로서 getUserMedia로 취득한 MediaStream을 사용한다.

결과



결국 다음과 같이

apply_filter.js
navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
}).then(stream => {
  // AudioContextを生成
  const audioContext = new AudioContext();

  // BiquadFilterを生成
  const biquadFilter = audioContext.createBiquadFilter();
  biquadFilter.type = 'highshelf';     // ハイシェルフフィルター
  biquadFilter.frequency.value = 1000; // 周波数閾値
  biquadFilter.gain.value = -50;       // Gain(強さ)

  // getUserMediaで取得したMediaStreamからMediaStreamAudioSourceNodeを生成
  const mediaStreamSource = audioContext.createMediaStreamSource(stream);

  // MediaStreamAudioSourceNodeをBiquadFilterNodeに、BiquadFilterNodeをAudioContext.destinationに接続する
  // AudioContext.destinationはブラウザの出力先を示しており、ここに音を流せばブラウザから出力される
  mediaStreamSource.connect(biquadFilter);
  biquadFilter.connect(audioContext.destination);

  // 最後にHTMLの<video>や<audio>のsrcObjectにstreamを渡す
  const video = document.querySelector('video');
  video.srcObject = stream;

  // HTML側で属性の指定をした場合は不要
  video.addEventListener('loadedmetadata', e => {
    video.muted = true; // streamの加工前音声を無効化
    video.play();
  });
});

HTML 측에서 autoplay 속성과 muted 속성을 지정했을 경우는, onloadedmetadata 의 콜백을 지정할 필요는 없다.

video.html
<video autoplay muted></video>

요점은 가공 전에 SourceStream의 오디오를 재생하지 않는다는 것입니다. HTML 측에서 muted 속성을 부여하는 것이 가장 빠르다.
시험에 muted가 아니어도 getAudioTracks하고 stop하면 좋을까? 라고 생각했지만 좋지 않았다.

failed.js
stream.getAudioTracks()[0].stop(); // 失敗例

SkyWay와 조합할 때는, 받은 상대측에서 stream에 필터를 걸는 것이 편하다.

filter_skyway.js
const peer = new Peer({ key: 'your API key' });
peer.on('call', call => {
  // 事前にgetUserMediaで取得したMediaStreamを渡す
  call.answer(localStream);
  // 相手のMediaStreamを受け取ると発火
  call.on('stream', stream => {
    ApplyFilter(stream); // ここでフィルターをかける
  });
});



복수의 필터를 걸고 싶은 경우는, 걸고 싶은 순서로 connect 해 가면 OK.

multi_filter.js
audioSource.connect(filter1);
filter1.connect(filter2);
filter2.connect(filter3);
filter3.connect(audioContext.destination);

참고문헌



Web Audio API의 기초
BiquadFilterNode



츳코미가 등등 있으면 코멘트로 가르쳐 주시면 다행입니다.

좋은 웹페이지 즐겨찾기