🧊

WebRTC QUICがChromeでOrigin Trialできるように

RTCQuicTransport Coming to an Origin Trial Near You (Chrome 73)  |  Web  |  Google Developers

今回は翻訳ではなく、気になる点の抜粋です。

TL;DR

  • WebRTCにQUICがくるよ
  • まずは`RTCQuicTransport`がChromeに実装されます
  • M73からOriginTrialできます

WebRTCにQUICがくる

  • まずは`RTCQuicTransport`というクラスから
  • ICEは変わらず、`RTCIceTransport`というクラスに
  • QUICなので順序も再送も保証!
    • ゲームやメディアや様々な用途に使えるよ

なんで

  • こういう低レイヤーが充実すると、もっといろんなことができる
  • それがWebRTC Next Versionだよ

なぜQUIC

  • リアルタイム性のため
  • UDPの上に位置する
  • `RTCDataChannel`的に見えるかも
    • 似てるけど違う
    • それSCTPじゃなくてQUICでできるよ
    • `RTCPeerConnection`とも隔離されてるし

どうやって使うの

  • 3つの構成要素がカギ
    • `RTCIceTransport`
    • `RTCQuicTransport`
    • `RTCQuicStream`

RTCIceTransport

  • ICEです
  • `RTCQuicTransport`のコンストラクタに渡される

RTCQuicTransport

  • QUICのコネクション
    • なので接続状況のstatsとかもとれる

RTCQuicStream

  • Read/Write
  • 1つの`RTCQuicTransport`に複数もてる
  • なんかWriteすると`onquicstream`イベントがリモートで発火する
  • 軽量でコネクションを越えてmultiprexされる

コードのイメージ

コネクションの確立

ただコピペしてもしゃーないので、コメントをいれてみた。

とあるクライアント。

const iceTransport = new RTCIceTransport();
// ICEは別クラスになってて渡せる
const quicTransport = new RTCQuicTransport(iceTransport);

// いわゆるオファー
// シグナリングを規定しないのは変わらず
signalingChannel.send({
  // SDPの代わり
  iceParams: iceTransport.getLocalParameters(),
  quicKey: quicTransport.getKey(),
});

// TrickleICEっぽい
iceTransport.onicecandidate = e => {
  if (e.candidate) {
    signalingChannel.send({candidate: e.candidate} );
  }
}

// いわゆるアンサー待ち
signalingChannel.onMessage = async ({iceParams, candidate}) => {
  // これがアンサー
  if (iceParams) {
    iceTransport.start(iceParams);
    quicTransport.connect();
  }
  // ICE candidateだけ
  else if (candidate) {
    iceTransport.addRemoteCandidate(candidate);
  }
};

とあるサーバー。
ほとんど一緒。

const iceTransport = new RTCIceTransport();
const quicTransport = new RTCQuicTransport(iceTransport);

signalingChannel.send({
  iceParams: iceTransport.getLocalParameters(),
});
iceTransport.onicecandidate = e => {
  if (e.candidate) {
    signalingChannel.send({candidate: e.candidate});
  }
}

signalingChannel.onMessage = async ({iceParams, quicKey, candidate}) => {
  if (iceParams && quicKey) {
    iceTransport.start(iceParams);
    quicTransport.listen(quicKey);
  } else if (candidate) {
    iceTransport.addRemoteCandidate(candidate);
  }
};

実行順序やら細かいところには目をつぶるとして、だいたいこんな感じらしい。

`RTCPeerConnection`的な層がないとこんな感じよねー。

データを送る

`RTCQuicStream`にあるAPIはこんな感じらしい。

RTCQuicStreamReadResult readInto(Uint8Array data);
void write(RTCQuicStreamWriteParameters data);
Promise<void> waitForWriteBufferedAmountBelow(unsigned long amount);
Promise<void> waitForReadable(unsigned long amount);

肝心の`stream`はこのように。

quicTransport.addEventListener('quicstream', stream => {
  // ...
});

受け取った`stream`の使い方はこちらから。

GitHub - shampson/RTCQuicTransport-Origin-Trial-Documentation: Documentation and demos for developers using the RTCQuicTransport in Chrome's origin trial.

Read
let readAllData = false;
while (!readAllData) {
  await readStream.waitForReadable(readStream.maxReadBufferedAmount / 2);
  const readBuffer = new Uint8Array(stream.maxReadBufferedAmount);
  const { amount, finished } = readStream.readInto(readBuffer);
  // Do something with the data.
}
// Close the stream. Writing a finish back to the remote side also will close
// the stream.
readStream.reset();
Write
while (haveDataToWrite()) {
  await waitForWriteBufferedAmountBelow(writeStream.maxWriteBufferedAmount / 2);
  const nextChunkSize =
      writeStream.maxWriteBufferedAmount - writeStream.writeBufferedAmount;
  writeStream.write({ data: getNextChunk(nextChunkSize) })
}
// All waitForReadable promises are resolved when the finish arrives to the read
// buffer on the remote side. Writing it after we are done here ensures that
// all chunks of data are read out on the remote side.
writeStream.write({ finish: true });

という感じで、どことなくWHATWG Streamを思わせる・・・。

バッファリング
unordered/unreliable
  • QUICだとデフォルトでできない
  • なので意図的にストリームを分けるとかしてやって

いつから使えるの

  • ChromeのM73からOriginTrial
  • M75まで

対象ブラウザ

その他

Feedback

  • フィードバックがほしいです

- APIの使い勝手とか
- パフォーマンスとか

Spec

  • WHATWG Streamとも足並み揃えるよ
  • 再送を無効にするのも検討中
  • あとはデータグラム
    • なにこれ?UDP直で叩けるの・・?

セキュリティ

  • QUICのhandshakeで使うキーはJSから見えます
  • シグナリングするときは気をつけて
    • PSK

というわけで

まだ全然一般ユーザーには関係ないけど、WebRTC業界としては大きな動きがありそうという。

実装される風のAPIたちも、本家のSpecと微妙に違うようにも見えるし、まだまだ変わる可能性に満ち溢れてるけど・・。

初OriginTrialしてみようかしら。