WebRTCのMediaStreamをWebAudioAPIのFilterで加工する方法
WebRTCのMediaStreamをWebAudioAPIのFilterで加工する方法:
最近、SkyWayを使ったビデオチャットシステムを構築していたのだが、ハウリング対策として高音を低減して欲しいと言われた。JavaScript歴2ヶ月なのに無茶言うな
探すのに少し苦労したので、勉強も兼ねた覚え書きとして残しておこうと思う。
WebAudioAPIでは、USBカメラやスピーカーといった入出力先や、音の加工をするフィルターなどをNodeとして表現する。これらを接続(connect)していくことで、渡された順に処理されていく仕組みとなっている。
今回はSourceとして、getUserMediaで取得したMediaStreamを使用する。
最終的に、以下のようになった
HTML側でautoplay属性とmuted属性を指定した場合は、onloadedmetadataのコールバックを指定する必要はない。
ポイントは、加工前のSourceStreamの音声を再生しないことである。HTML側でmuted属性を付与するのが一番手っ取り早い。
試しにmutedじゃなくてもgetAudioTracksしてstopすればいいのでは?と思ったがダメだった。
SkyWayと組み合わせる際は、受け取った相手側でstreamにフィルターをかけるのが楽。
複数のフィルターをかけたい場合は、かけたい順にconnectしていけばOK。
Web Audio API の基礎
BiquadFilterNode
ツッコミどころ等あったらコメントで教えて頂ければ幸いです。
概要
最近、SkyWayを使ったビデオチャットシステムを構築していたのだが、ハウリング対策として高音を低減して欲しいと言われた。探すのに少し苦労したので、勉強も兼ねた覚え書きとして残しておこうと思う。
WebAudioAPIの基本概念
WebAudioAPIでは、USBカメラやスピーカーといった入出力先や、音の加工をするフィルターなどを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();
});
});
video.html
<video autoplay muted></video>
試しにmutedじゃなくてもgetAudioTracksしてstopすればいいのでは?と思ったがダメだった。
failed.js
stream.getAudioTracks()[0].stop(); // 失敗例
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
ツッコミどころ等あったらコメントで教えて頂ければ幸いです。
コメント
コメントを投稿