WebAudio APIでMediaStreamを作ろうとしたらつまずいた話

はじめに

mp3ファイルの音声データをWebRTCで送信しようとしたところ、MediaStreamの作成でつまずいたので、どのようなコードを書くと正しく動作するのか、原因は何だったのかをまとめておこうと思います。

書いたコード

const ctx = new AudioContext();
let fakeAudioBuffer = null;
const res = await fetch('bgm.mp3');
const arrayBuffer = await res.arrayBuffer();
const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
fakeAudioBuffer = audioBuffer;
const source = ctx.createBufferSource();
source.buffer = fakeAudioBuffer;
source.connect(ctx.destination);
const {stream} = ctx.createMediaStreamDestination();

このようなコードを書きましたが、streamaddStream()して送信するとなぜか無音になっていました。
streamconsole.log()で出力してみましたが、特に問題がなさそうに見えました。

原因

const ctx = new AudioContext();
let fakeAudioBuffer = null;
const res = await fetch("bgm.mp3");
const arrayBuffer = await res.arrayBuffer();
const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
fakeAudioBuffer = audioBuffer;
const source = ctx.createBufferSource();
source.buffer = fakeAudioBuffer;
const mediaStreamDest = ctx.createMediaStreamDestination();
source.connect(mediaStreamDest);
const {stream} = mediaStreamDest;

こちらが正しく動作するコードです。
createMediaStreamDestination()MediaStreamAudioDestinationNodeを作成し、source.connect()でNodeを繋いだ後でmediaStreamDestからstreamを取り出しています。間違っていたコードではcreateMediaStreamDestination()を呼ぶ前にsource.connect()を呼んでいたため、Nodeのつながりが途中で途切れていました。

まとめ

mp3ファイルからMediaStreamを生成できると何が嬉しいのかというと、例えばWebRTCを使ったビデオ会議システムで、保留音を流すといったことができるようになります。
また、WebAudio APIでは各Nodeを正しく繋いでいかないと目的の音が得られません。WebAudio APIは非常に高機能なので、今後も活用していきたいと思いました。