フロントエンドエンジニアからみる、この界隈で今どんなIssueが話題になってるのかと、この先どういう動きがありそうかについて。
そこまで自分に先見の明があるとも思ってないけど、アウトプットしておかないと忘れてしまいそうなので・・。
ちなみにここでいうフロントエンドは、いわゆるブラウザとかJavaScriptのAPIのことです。
プロトコル的な側面はそこまで詳しくないのであまり触れません。
WebRTC 1.0
まず、RTCといえばズバリのWebRTCから。
昨年末にWDからCRへ格上げということで、もうAPIが激変したりはしない・・はず。
実際のところ、ここ半年くらい大きな対応した覚えがないです。(WebRTCそのものを実装してる人は、地味にいろいろ対応してると思うけど)
ガワのAPIという観点でいうと、最近はもうユースケースを掘り下げていくフェーズというよりか、仕様としてのつじつま合わせやら、こんなときどうなるの?っていうコーナーケースへのIssueが多い印象。
たとえば通信中のノートPCをパタンって閉じたら、その通信はどうなる?とか、APIとしてこういうケースは可能になってるけど、その場合の状態遷移はどうあるべきか?とか。
JSのAPIネタでいうと、Perfect Negotiationの一連APIたちが実装された暁には、何かしら対応してみてもよいかもしれない。
まあ、シグナリングのグレアは他にも回避方法あるし、今さら・・とは思う。
(そんなことよりFirefoxに`setConfiguration()`実装してほしい。)
蛇足: Unified-plan
この記事を書いてて思い出したネタ。
Unified-planってそういえばどうなったっけ・・みんなちゃんと使ってる?恩恵受けてる?っていうやつ。
まぁその記事としても、Chromeの中の人たちとしても、どうやらあんましらしい。
857004 - chromium - An open-source project to help move the web forward. - Monorail
まあ実際は1トランスポートあたり1audio+1video以上やりとりしたいユースケースってあまり思いつかん + 別に2トランスポートでなんとかなるので、ほんとシビアな仕様やったんやなとは思う・・。
セマンティクスとしてはこっちのほうがシュッとしてると思うけど。
webrtc-extensions
GitHub - w3c/webrtc-extensions: A repository for "WebRTC 1.1+" features
そんな1.0のスコープから漏れた機能群は、だいたい拡張仕様って扱いになってます。
たとえばTPACでも話題になってた`RTCRtpReceiver`の`playoutDelay`。
いまだと受け取ったメディアはASAPで再生されるけど、そこに恣意的な遅延をつけられるようにしてちょっとバッファしたい・・とか。
あとはHWエンコードできるコーデックがAPIで事前にわかると嬉しいよね、とか。
まあこの界隈は論者が限られてるので、全般的にアクティブではないです。
そういう意味ではNextVersionに関しても、ここのところ下火。
Media Capture and Streams
GitHub - w3c/mediacapture-main: Media Capture and Streams specification (aka getUserMedia)
おなじみの`getUserMedia()`とか、`enumerateDevices()`とか。
こちらもCRながら、セマンティクスの問題とプライバシー方面の議論が入り混じって大乱闘状態。
すごくかいつまんでトピックを並べると、
- デバイス機能の詳細はFingerprintになるから見せられないよ
- `{ video: true }`ですべてのデバイスの許可取れるのおかしくない?
- `getDisplayMedia()`みたいに、ブラウザがピッカー持つべきでは?
- `{ video: true, semantics: "user-chooses" }`的な
- そもそも許可なしでデバイス一覧見れるのがおかしくない?
- 一口にaudioって言っても、チャット用と演説用とで性質違うしその旨も指定したいです
- etc..
`enumerateDevices()`もついこの間も変更があったところなので、これらに関してはまだこれからも変わりそうやなーという感じ。
ここに関しては、PSAが出たらさっさと検証するしかなさそう・・。
WebTransport
GitHub - WICG/web-transport: WebTransport is a web API for flexible data transport
ここからはちょっと先の話題。
サーバーとクライアント間の双方向で低遅延なやり取りがしたい場合の選択肢として、現状ではWebSocketかWebRTCのDataChannelかが主な選択肢になるはず。
ただWebSocketだとHoLBでパフォーマンスの問題があるし、WebRTCだとICEいらないしDTLSでSCTPなので実装が大変+そもそもサバクラで使いにくい。
ちょうどいいUDPベースのWebSocketライクなやつが欲しい・・ということで生まれたのが、QUICの上で動くWebTransport。
QUICとか、プロトコルの詳細については、別に詳しい人がいると思うので気になった人は調べてみてください。
ドラフトを訳したやつがあるのでいちおう置いておきます。
たとえばクラウドゲーミングだと、クライアントからサーバーにはユーザー操作をデータで送って、サーバーからは結果がメディアで返ってくるのでそれを描画する感じ。
// Example of sending unreliable game state to server using QUIC datagrams const transport = new QuicTransport('example.com', 10001); const datagramWriter = transport.sendDatagrams().getWriter(); setInterval(() => { const message = getSerializedGameState(); datagramWriter.write(message); }, 100);
`ReadableStream`しかり`WritableStream`しかりをよしなに使うことになるはずで、このあたりのAPIは慣れが必要そう。
ただChromeですらまだIn developmentなので、まっだまだ先の話です。
WebRTC-QUIC
GitHub - w3c/webrtc-quic: Interface to create and manage QUIC streams
ChromeではOriginTrialまでしてたけど、最近はWebTransportのこともあってかやや下火。
というか、気付けばWebTransportありきの仕様になってる感。
クライアントP2PでのWebRTCは、しばらく今のままって感じですかねー。
WebSocketStream
GitHub - ricea/websocketstream-explainer: Explainer for the WebSocketStream JavaScript API
WebSocketで`Stream`のAPIを使えるようにして、BackPressureに対応したモダンな書き味にしたいよねというプロポーザル。
const wss = new WebSocketStream(url); const { readable } = await wss.connection; const reader = readable.getReader(); while (true) { const { value, done } = await reader.read(); if (done) break; await process(value); } done();
こちらもモノはおなじく`whatwg/streams`ですね。
QUIC上で動くWebTransportのほうが上位互換ではあるけど、UDPが通らない環境とかもあると思うし、WebTransportがくるまでのつなぎとしての狙いもありそう。
ともあれデータをいい感じに流す土管は揃い踏みした感あるので、あとは何をやり取りするか。
ChromeCanaryではもう動くので、WebTransportよりは早そうではある。
WebCodecs
GitHub - WICG/web-codecs: WebCodecs is a flexible web API for encoding and decoding audio and video
いい感じの土管ができたら、そのデータを描画する部分のAPIがあるといいよね、ということで。
今もJS/WASMで自前エンコード・デコードすることはできるけど、それだとメモリ効率とかHWも有効利用できないし、そもそもブラウザに載ってるコーデックを再実装するのが無駄という話もあり。
WebRTCでも生のメディアには触れないし、やっぱあらゆるユースケースに対応するためには、コンポーネントを細かく切っていくしか無い世相を感じますね。
// Example of video rendering to Canvas for low-latency live streaming or cloud gaming class CanvasRendererSink { constructor(canvas) { this._context = canvas.getContext('bitmaprenderer'); } write(videoFrame) { _context.transferFromImageBitmap(videoFrame.image); return Promise.resolve(); } } const canvas = document.getElementById("canvas"); const renderingStream = new WritableStream(new CanvasRendererSink(canvas)); const videoDecoder = new VideoDecoder({ codec: "vp8" } ); encodedVideoStream.pipeThrough(videoDecoder).pipeTo(renderingStream);
これもAPIとしては`whatwg/streams`のそれ(だいたい`TransformStream`)で、用途に応じていろいろ用意されるクラスを使い分けることになる想定。
これもIn developmentなやつ。
Insertable Streams API for WebRTC
GitHub - alvestrand/webrtc-media-streams: Insertable Streams API for WebRTC
話は戻ってまたWebRTC。
これもまだ単なるプロポーザルではあるけど、WebRTCでやり取りするメディアを手元で加工したいよねという話。
// それ用のフラグ const pc = new RTCPeerConnection({ forceEncodedVideoInsertableStreams: true, forceEncodedAudioInsertableStreams: true }); // TransformStream const senderTransform = new TransformStream({ async transform(chunk, controller) { /* ... */ } }); const videoSender = pc.addTrack(track, stream) const senderStreams = videoSender.getEncodedVideoStreams(); senderStreams.readable .pipeThrough(senderTransform) .pipeTo(senderStreams.writable);
これは先述のWebCodecsありきなコードになってるけど、今の時点でも有効なユースケースが実はある。
それが、このAPIを使って今話題のE2Eの暗号化を実現するサンプル。
まだChromeのCanaryでしか動かないけど。
あとは受け取ったvideoのキーフレームをカウントするサンプルとかもレビュー中。
Video analyzer by alvestrand · Pull Request #1276 · webrtc/samples · GitHub
なんしか、画一的なやり方でメディアを加工できるようになるのはよいですね。
フロントエンドエンジニアとして
SDKを作る側としては、今後も仕様の動向やプロトコルそれ自体についてもある程度知っておく必要がありそう + APIとしては`Stream`に慣れておくとよいかも?
一般的なフロントエンドエンジニアがRTC系のことをやる場合は、基本的に何某かのSDKを使うはず。
なので、その背景のプロトコルやAPIを知っておく必要は実際ほぼないと思ってて、それよりもそのSDKの通信モデルやらAPIを熟知して、できること・できないことを判断できるようになっておくほうがよいのかなと思います。
とは言っても汎用性の高いSDKを選んだなら、自分で`Stream`経由で生メディアに触れることもあるかもしれんけど・・。