ボイスチェンジャー
こちらの記事ではブラウザ上で動作する Twilio Programmable Video の JavaScript client について説明します。オーディオデータにエフェクトをかけるのには Tone.js を利用します。他の何かを利用したい場合でも、入出力の扱い方は同じなのでまあ参考になるといいですね。
一般的にWebRTCによるビデオ通話を実装する場合、実行環境であるブラウザ側に用意されたデバイスへのインターフェース getUserMedia
を通して取得した MediaStream
である LocalMediaStream
を相手方に送信し、相手方もまた同じ仕組みを通じてこちら側にデータを送り返すやり取りを繰り返すことになります。データの送受信は MediaStreamTrack
という一種のコンテナを通じて実行されますが、そこに track
と呼ばれる実際の映像や音声を追加したり外したりしてコントロールすることもできます。 音声を扱う track
にはそれぞれ一つ以上の channel
があります(例えばステレオの左右のチャンネルとか)が、まあ普通は track
が最も低レベルのレイヤーになります。ただし、 DataChannel
は違います。これは全然別のものです。
うん。訳がわかりませんよね。
getUserMedia で↓をget!
+--------------------+ +--------------------+
| LocalMediaStream | | MediaStream |
| +-------------+ | | +-------------+ |
| | Video Track | | | | Video Track | |
| +-------------+ | | +-------------+ |
| | ===> | | ===> 相手側に届く
| +----------------+ | | +----------------+ |
| | Audio Track | | | | Audio Track | |
| | | | | | | |
| | "left channel" | | | | "left channel" | |
| | "right channel"| | | | "right channel"| |
| | | | | | | |
| +----------------+ | | +----------------+ |
+--------------------+ +--------------------+
魔法のようにわかりやすい図ですね。
さて、今回取り扱うのは、Tone.js
経由で取得した音声入力にエフェクトをかけ、改めてLocalMediaStreamにaudio trackとして追加してやる例です。省略の多いコードですがまあわかるでしょう。
import * as Video from 'twilio-video';
import * as Tone from 'tone';
const micAudio = new Tone.UserMedia(); // Tone.jsのgetUserMedia
await micAudio.open().then(() => {
// ピッチシフターで声の高さを変えます
const shifter = new Tone.PitchShift(7);
const effectedDest = Tone.context.createMediaStreamDestination();
micAudio.connect(shifter);
shifter.connect(effectedDest);
const effectedTrack = effectedDest.stream.getAudioTracks()[0];
// LocalTrackを作成してRoomに接続します
Video.createLocalTracks({
audio: true,
video: true,
}).then((localTracks) => {
localTracks.push(effectedTrack); // エフェクトがかかったtrackを追加
Video.connect(token, {
tracks: localTracks,
})
}).catch(...省略)
}).catch(...省略)
これで凶悪犯の住んでいた地域の住民がテレビで匿名でインタビューを受けるような音声になります。Tone.jsには他にもいろいろなエフェクトが用意されているので、試してみてください。
バーチャル背景
うん。
いろいろ書いたんだ。
でも
ここを読んだ方が早いよ。ちゃんと検索すればよかったよ。