9
6

More than 3 years have passed since last update.

ついに映像同期したインライン Data に Webが対応。WebRTC Insertable Streams でのインラインData送受信のやり方

Last updated at Posted at 2020-09-07

これは何?

WebRTC Insertable Streams では、E2EE(エンド to エンドの暗号化)が注目されていますが、僕は 映像に完全同期したインラインDataが可能となる ほうが大きいニュースだと思っています。てことで、それのデモ紹介と使い方。

WebRTC Insertable Streams そのものについては

映像同期したインライン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 が同期して変わっていきます。

image.png

ソースコードは https://github.com/kokutele/kokutele/blob/master/public/labs/insertable-streams-meta/script.js においておきましたので、詳しくはそちらを御覧ください。

おわりに

loopback デモだと、ありがたみ分かりづらいですが、送信側のデータ変更タイミングとタイミングばちこんで、リモート視聴側のエフェクトが変わっていきます。これまでの Web ではこれができなかった。

今回のデモと同じ考え方で、例えばライブイベントでアーティスト登場瞬間に、着ている洋服のURLを送って EC 販売とリアルタイム連動する・・・なんてなことも当然ながら可能です。

アイディア次第で、様々なリアルタイムマッシュアップアプリを作れると思います。バイナリデータの操作は一見面倒ですが、なれてしまえば大したことないですので、是非お試しいただければ。

気になる実装状況ですが、Chrome Status によると、M86 (今のベータチャネル)が stable に落ちてくれば(たぶん3ヶ月後)、普通に使えるようになります。いやーーーー楽しみですねぇ :)

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6