Slide 1

Slide 1 text

もっと大きなデータを送りませんか? エラーがゴロゴロ出るようなデータです WebRTC Meetup Tokyo #29 2025/03/10

Slide 2

Slide 2 text

自己紹介 ● @sublimer ● NTT CommunicationsでSkyWayを作るお仕事をしています

Slide 3

Slide 3 text

本日お話すること・しないこと ● お話すること ○ WebRTCのDatachannelでサイズが大きなデータを効率的に送る方法 ● お話しないこと ○ Datachannel自体の詳細な解説 ● 今日のゴール ○ WebRTCのDatachannelで「エラーがゴロゴロ出るような」サイズが大きいデータをエラーを 出さずに効率的に送る方法を理解する

Slide 4

Slide 4 text

前提 ● 以下の環境で動作確認をしています ○ Google Chrome 134 ○ macOS Sonoma ○ 同一ホストの別タブ同士で通信 ● 以下の設定で動作確認をしています ○ DataChannelは信頼性あり・順序保証あり ● Firefox、Safariでは挙動が異なる可能性があります

Slide 5

Slide 5 text

Datachannelで大きなデータを送る ● 何も考えずに、とりあえず32MBのデータを送ってみる Uncaught OperationError: Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel send queue is full ● Chrome内部の送信用のキューのサイズが16MiB[1] なのでエラーになる uint64_t DataChannelInterface::MaxSendQueueSize() { return 16 * 1024 * 1024; // 16 MiB } [1]https://source.chromium.org/chromium/_/webrtc/src/+/b101a7e335a360438c022f43e4826d1af73c3283:api/data_channel_interface.cc;l=56;bpv=1;bpt=0;drc=c4024d62a4944ddb2 088c6d2798784b43507a696

Slide 6

Slide 6 text

一度に送れる最大のデータ量は? ● Q. 1MiBなら? ● A. DataChannelのerrorイベントが発火し、コネクションが切断される OperationError: Failure to send data ● ブラウザごとに一度に送れるデータ量(MaxMessageSize)が異なる ブラウザ MaxMessageSize Google Chrome 256KiB Firefox 1GiB Safari 256KiB

Slide 7

Slide 7 text

MaxMessageSizeについて ● ブラウザでハードコーディング[2] されている ● SDPの a=max-message-size: に乗ってくる ● ネゴシエーション後に、実際に利用できるMaxMessageSizeが決まる ○ 値が小さい方に合わせる[3] ● RTCPeerConnection.sctp.maxMessageSize [4] で参照できる [2]https://source.chromium.org/chromium/_/webrtc/src/+/b101a7e335a360438c022f43e4826d1af73c3283:net/dcsctp/public/dcsctp_options.h;l=73;bpv=1;bpt=0;drc=f6902aff958cab549c3 d138305bc7f9ed7983ebd [3]https://source.chromium.org/chromium/_/webrtc/src/+/cec4b95104c3660e0a1eeafea3e0f6176b8d389d:pc/sdp_offer_answer.cc;l=5052-5054;drc=d8d041046e5507a530abe09e7baefc ebd35470b6;bpv=1;bpt=0 [4]https://developer.mozilla.org/en-US/docs/Web/API/RTCSctpTransport/maxMessageSize

Slide 8

Slide 8 text

Datachannelで大きなデータを送るためには… ● 一度に送るデータのサイズをMaxMessageSize以下とし ● かつ送信用のキューを溢れさせないようにする ● → チャンク分割と適切な流量制御が必要

Slide 9

Slide 9 text

チャンク分割について ● 16KiBごとにデータを分割する ○ RFC8831で「最大のメッセージサイズは16KiBにすべき(SHOULD)」と書かれている[5] [5]https://www.rfc-editor.org/rfc/rfc8831.html#name-transferring-user-data-on-a

Slide 10

Slide 10 text

送信用のキューを溢れさせないようにするには ● RTCDataChannelの以下のプロパティ・イベントを使う ○ bufferedAmount[6] ■ 送信用のキューに入っているデータ量 ○ bufferedAmountLowThreshold[7] ■ bufferedamountlowイベントを発火させる閾値 ○ bufferedamountlow Event[8] ■ bufferedAmountがbufferedAmountLowThreshold以下になった時に発火するイベント [6]https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/bufferedAmount [7]https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/bufferedAmountLowThreshold [8]https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/bufferedamountlow_event

Slide 11

Slide 11 text

各プロパティとイベント発火のタイミングのイメージ 🔥bufferedamountlow 🔥bufferedamountlow

Slide 12

Slide 12 text

流量制御の流れ 1. DataChannelのbufferedAmountLowThresholdを設定する 2. DataChannel.send()を呼ぶ前にbufferedAmountが bufferedAmountLowThresholdを超えていないかをチェックする 3. bufferedAmountがbufferedAmountLowThresholdを超えている場合、 bufferedamountlowイベントが発火するのを待つ 4. bufferedAmountがbufferedAmountLowThreshold未満、または bufferedamountlowイベントが発火したら、DataChannel.send()を呼ぶ

Slide 13

Slide 13 text

まとめ ● WebRTCのDataChannelで大きなデータを効率よく送るためには… 1. データを16KiBごとに分割する 2. bufferedAmount、bufferedAmountLowThreshold、bufferedamountlow の3つのプロパティ・イベントを利用し、適切に流量制御を行う ※検証で使ったコードは以下のGitHubリポジトリで公開しています https://github.com/kadoshita/webrtc-datachannel-efficient

Slide 14

Slide 14 text

参考サイト ● RTCSctpTransport: maxMessageSize property - Web APIs | MDN ● RFC 8831: WebRTC Data Channels ● RTCDataChannel: bufferedAmount property - Web APIs | MDN ● RTCDataChannel: bufferedAmountLowThreshold property - Web APIs | MDN ● RTCDataChannel: bufferedamountlow event - Web APIs | MDN ● Large Data Channel Messages - Advancing WebRTC ● Using WebRTC data channels - Web APIs | MDN