これは何?
WebRTC Insertable Streams では、E2EE(エンド to エンドの暗号化)が注目されていますが、僕は 映像に完全同期したインラインDataが可能となる ほうが大きいニュースだと思っています。てことで、それのデモ紹介と使い方。
WebRTC Insertable Streams そのものについては
- https://qiita.com/massie_g/items/2b0b6d4f61f1865b4da5 や
- https://qiita.com/komasshu/items/13b0225ed839ac20548d を参照ください。
映像同期したインラインDataの嬉しさ
これまでの WebRTC では映像と同時に通常のデータも送受信できました(WebRTC Data Channel)。しかし、Media Stream とはアウトバウンドの関係にあるため、送受信のタイミングをとることが難しく、例えば
- 特定フレームにあわせて、広告を挿入する。
- 特定フレームにあわせて、商品紹介ページを表示する
- 特定フレームにあわせて、何かしらのエフェクトを効かせる
といったことが困難でした。なんていうのかな。これまでの WebRTC は Web1.0 な感じで、Web ページの中に
「映像通信を埋め込む」
ことはできたのですが、Web2.0 的な
「映像と外部データとが、がんがん連携して、イノベーティブなアプリケーションを生み出す(古い言葉でいうとマッシュアップ)」
ということができなかった。
でも、これが Insertable Streams でついに搭載された、インライン Data のサポートにより可能となります。 Realtime Web 2.0 の幕開けといっていいんじゃないかな?と個人的には興奮していたりします。Webでここまでワクワクするのはホント久しぶり ;)
てことで使い方
インラインDataのやり方は、そんなに難しくないです。。。。バイナリデータのやりとりになれているネットワークエンジニア民にとっては。
Insertable Streams では、 TransformStream
インスタンスを定義して、そこでエンコードデータに対して自由にストリーム処理ができるというものになっていますが、ここで、映像データの 末尾 に、バイナリ形式で additional データを突っ込んだり/とったりするだけです。
例えば、映像フレームに併せて、何かしらの色素情報(RGB3バイト)をやりとりするのであれば、送信側は
const transformStream = new TransformStream({
transform: (chunk, controller) => {
// videoストリームに、データを追加する場合
if( kind === 'video' ) {
// 最後に 3 バイトの固定フィールドを足す(RGBそれぞれの値を1バイトづつ指定)
const rgb = new Uint8Array( 3 )
rgb[0] = this._red
rgb[1] = this._green
rgb[2] = this._blue
// 新たな、データコンテナ(Uint8Array)を作る。
// 最初に、もともとの映像データを書き込んだ後、
// RBGデータを末尾追加する
const len = chunk.data.byteLength
const container = new Uint8Array(len + 3)
container.set( new Uint8Array( chunk.data ), 0)
container.set( rgb, chunk.data.byteLength)
// chunk.data をRGBデータが追加されたものに差し替える
chunk.data = container.buffer
}
controller.enqueue( chunk )
},
}
てな感じでいけますし、受け側で抜き出す場合は、
const transformStream = new TransformStream({
transform: (chunk, controller) => {
if( kind === 'video' ) {
// 最後の3バイト(RGB) を取り出し、border color としてセットする
const rgb = new Uint8Array( chunk.data.slice(-3) )
// rgb[0], rgb[1], rgb[2] に、それぞれ色素データ (0 - 255 )
// が入っているので、これをよしなに処理するコードをここに記述
// 最後の3バイトを除外することで映像データのみをとりだす
const mediaData = new Uint8Array( chunk.data.slice(0, -3) )
// chunk.data を映像データのみのものに差し替える
chunk.data = mediaData.buffer
}
controller.enqueue(chunk)
},
});
といった形でいけます(コードの詳細は、コメントを参照ください)。
デモ Web アプリ
https://conf.kokutele.com/labs/insertable-streams-meta/ に、デモの Web アプリをおいておきました。
( Chrome の M85(stable) で動作確認。 chrome://flags/#enable-experimental-web-platform-features の enable を忘れずに )
画面中央部の add
ボタンクリック後、ボタン上部の red, blue, green の数字を変えてやると、それに応じて下部映像(WebRTC loopback P2P 受信映像)の border color が同期して変わっていきます。
ソースコードは https://github.com/kokutele/kokutele/blob/master/public/labs/insertable-streams-meta/script.js においておきましたので、詳しくはそちらを御覧ください。
おわりに
loopback デモだと、ありがたみ分かりづらいですが、送信側のデータ変更タイミングとタイミングばちこんで、リモート視聴側のエフェクトが変わっていきます。これまでの Web ではこれができなかった。
今回のデモと同じ考え方で、例えばライブイベントでアーティスト登場瞬間に、着ている洋服のURLを送って EC 販売とリアルタイム連動する・・・なんてなことも当然ながら可能です。
アイディア次第で、様々なリアルタイムマッシュアップアプリを作れると思います。バイナリデータの操作は一見面倒ですが、なれてしまえば大したことないですので、是非お試しいただければ。
気になる実装状況ですが、Chrome Status によると、M86 (今のベータチャネル)が stable に落ちてくれば(たぶん3ヶ月後)、普通に使えるようになります。いやーーーー楽しみですねぇ :)