WebRTC Native Client Momo と WebAssembly

V
7 min readNov 21, 2020

これは、こんな事がやれたら楽しそうだなという話でどうするかとかはまだ決まっておりません。

要約

  • Momo に WebAssembly Runtime を載せたい
  • WebAssembly でエンコード前とエンコード後の音声と映像を操作できるようにしたい

課題

Momo は libwebrtc を利用した WebRTC クライアントです。様々な環境で動き、とても軽いのでいろいろなところで利用いただいています。

ただ課題として基本的に Momo が対応していないことをやろうとすると自分でカスタマイズする必要があります。これは体力のある企業でやる場合はいいと思うのですがスタートアップなどでは厳しいのが現状です。

たとえば …

  • Momo が配信する映像にぼかしフィルターをかけたい
  • Momo が投げてる SDP をカスタマイズしたい
  • Momo が受信したパケットの映像部分をダンプしたい
  • Momo の Sora シグナリング時に投げてる JSON を加工したい

これらをやるには必ず Momo のコードに手を入れ自前でビルドする必要があります。

これらをなんとかして Momo に手を入れないで利用できるようにできないかとずっと考えていましたが、思いついたのは LuaJIT を使ってフックポイントからフックして処理できるような感じにするかという OpenResty 的な思考でした。

ただ Lua はまぁ、良い言語で自分も好きなのですが残念ながら流行っているとは言い難いですし、書きたい人もそんなにいません。

実際 Erlang VM 上で動作する Luerl を使った商用システムを何個か作りましたが、刺さるところには刺さるくらいでした。

なんどか めるぽん に「C++ でプラグインの仕組みはやっぱりしんどい?」という相談をしたこともありますが、厳しそうなのでやめました。

WebAssembly

Momo とはあまり関係ないWebRTC における End to End Encryption をブラウザ上で実現するために Go で書いたコードを WebAssembly に出力して利用するというのを実装して、かなりうまく動いたという経験をしました。

このとき思ったのが、Momo に WebAssembly Runtime を載せて WebAssembly 用のフックポイントを Momo に用意して、誰もが気軽に Momo のプラグイン的なものを WebAssembly で書けたらいいのではないか?というものです。

仕事で使っていた Envoy が WebAssembly でフィルターをかけるという記事を読んだのもとても刺激になりました。

Envoy は昔から C++ モジュールと Lua スクリプトによる拡張機能メカニズムを搭載していますが、その両方が欠点を抱えています。Istio を設計した目的の 1 つは、ポリシー、診断、ロギング システムのエコシステムにおいて、簡単に拡張できる機能を実現することでした。これは、コントロール プレーン コンポーネントと、どの言語でも記述できるプロセス外アダプターによって実現しましたが、このアプローチをとると、ネットワークのホップとレイテンシが増加してしまいます。

そこで登場したのが Wasm です。Wasm は、30 以上の言語からコンパイルできるバイナリ命令フォーマットで、それを実行するためのサンドボックス環境を搭載しています。既にすべての主要ブラウザに埋め込まれており、W3C ワーキング グループが標準を定義しています。そして現在、Envoy を通じてサーバーサイドに導入しています。この方式により、再コンパイルやフォーク、難しいロールアウトを行わずに Envoy プロキシに機能を追加できます。Istio はプロキシに拡張機能を配布し、再起動せずに読み込むことができます。これによって最高の拡張性を組み合わせることができるようになり、言語の選択と優れたパフォーマンスを両立できるようになります。

C++ / Lua による拡張の課題を WebAssembly で解決するという話です。これは自分がやりたかったことにとても近いです。

先日、Solo.io は WebAssembly Hub について発表を行いました。これは、Wasm 拡張機能の構築、共有、検索、デプロイを行うためのサービスです。WebAssembly Hub を活用すれば、Wasm 拡張機能をコンテナとして簡単に管理、インストール、実行できるようになります

さらに WebAssembly Hub というのもやりたかったことの一つです。気軽に拡張機能を持ってきて実行できるという仕組みです。

ちょうど WebAssembly Runtime である wasmtimelucent統合されるという話もでてきており、タイミング的に良さそうでもあります。

Momo に wasmtime を載せるというところまでは妄想できました。

Insertable Streams API

ブラウザの WebRTC に登場した Insertabe Streams API というとても強力な API があります。これは「エンコード後」の映像や音声を自由に書き換えられるというものです。先程言った End to End Encryption はこれを利用しています。

また自由にデータを付け加えることができるため映像に独自のタイムスタンプをつけたり、固有の情報を付けたりということも可能になります。

さらに MediaStreamTrack API for Insertable Streams of Media というのが発表されました。これは「エンコード前」の音声や映像を自由に書き換えられるというものです。今までも力技で実現はできていたのですが、この仕組を使うことでとても簡単に利用することが可能になります。特に canvas などを利用しなくていいのは良いです。

最初に実現したいこと

Momo に WebAssembly Runtime を載せて、エンコード前/エンコード後に対する Insertable Streams API のような仕組みをインストールした WebAssembly バイナリから自由に操作できるという事をやりたいと考えています。

コストはとても高いと思っていますが、どうにかしてできたら Momo の活躍の場が一気に広がるのではないかと考えています。カスタマイズせずに自由に音声や映像に手を入れられるのはとても大きいです。

最終的に実現したいこと

課題で上げたような事を実現できるように、様々な場所にフックポイントを用意し、それらを WebAssembly 側からさわれるようにしたいと思っています。Momo はハードウェアを利用するつなぎこみ部分と WebRTC と Signaling のみを担当し、あとは拡張は全て WebAssembly でできたりすると良いなと思っています。

興味ある人へ

もし実際に実現できそうだなと思う人は、仕事として依頼することも可能ですので、プロトタイプありきでご相談ください。また、成果はApache License 2.0 でオープンソースとして公開します。

--

--