DocumentationクックブックJavaScript SDK大きなサイズのデータを送信する

大きなサイズのデータを送信する

本ドキュメントでは、SkyWay JavaScript SDK の DataStream を使って大きなサイズのデータを送信する方法を説明します。

DataStream にて大きなサイズのデータを一挙に送ろうとした場合、 WebRTC の仕様によりエラーとなります。 なお、エラーとなるデータサイズの閾値は、お使いの環境により異なります。

このようなエラーを回避するためには、データを小さなチャンクに分割して送信する処理が必要です。

Publisher 側でデータを分割する処理の実装例

本ドキュメントでは、サンプルアプリとして公開している Room ライブラリの P2PRoom による 映像・音声・データの PubSub をベースとして、巨大な文字列データを送受信する実装を例示します。

前提として、サンプルアプリの HTML コードで以下のようなフォームが記述されています。 このアプリでは、 write ボタンを押下するとテキストボックスに入力されている文字列を Subscriber 宛に送信します。

index.html

write dataStream: <input id="data-stream" type="text" /> <button id="write">write</button>

RFC8831 によれば、送信するデータのサイズは最大でも 16KiB にすることが推奨されています。 そのため、 16KiB を超えるような長い文字列を入力し write ボタンを押下した場合、パフォーマンス低下や冒頭のエラーによるデータ送信の失敗を引き起こす恐れがあります。

以下は、それらの不具合を回避するために、データを小さなチャンクに分割して送信する処理の実装例です。 手元で動作確認する場合は、サンプルアプリ内の writeButton.onclick を以下のコードに書き換えてください。

Room ライブラリの場合 (main.ts)

import { SkyWayStreamFactory } from '@skyway-sdk/room'; const dataStreamInput = document.getElementById('data-stream') as HTMLInputElement; const writeButton = document.getElementById('write'); const data = await SkyWayStreamFactory.createDataStream(); writeButton.onclick = () => { const chunkSize = 16 * 1024 - 24; // 16KiBから付加情報のサイズ24Byteを引く const inputData = dataStreamInput.value; // チャンク分割処理 for (let sentDataSize = 0; sentDataSize < inputData.length; sentDataSize += chunkSize) { const chunkData = { data: inputData.slice(sentDataSize, sentDataSize + chunkSize), eor: sentDataSize + chunkSize >= inputData.length // End of Record } data.write(JSON.stringify(chunkData)); } dataStreamInput.value = ''; }

なお本実装例では、データを分割するだけでなく、各チャンクに付加情報を追加しています。 この付加情報は一連のデータの末尾か否かを示すフラグ EoR: End of Record であり、後述するデータ復元処理で利用します。

なお、SkyWay JavaScript SDK v2.2.0 以前では、データを高頻度に送信した場合にも同様のエラーが発生することがあります。 この問題に対処するためには、適宜 sleep 処理を入れていただくか、SkyWay JavaScript SDK v2.2.1 以降へアップデートしてご利用ください。

Subscriber 側でデータを復元する処理の実装例

ここでは、分割されたチャンクから元の文字列を復元する方法を説明します。 なお、本セクションも上記と同様にサンプルアプリ Room ライブラリの P2PRoom による 映像・音声・データの PubSub をベースとして実装します。

以下に、データ復元処理の実装例を示します。 手元で動作確認する場合は、サンプルアプリの subscribeButton.onclick 内にある case 'data' の箇所を以下のコードで書き換えてください。

Room ライブラリの場合 (main.ts)

subscribeButton.onclick = async () => { const { stream } = await me.subscribe(publication.id); switch (stream.contentType) { // (中略) case 'data': { const elm = document.createElement('div'); remoteMediaArea.appendChild(elm); elm.innerText = 'data\n'; // データ復元処理 let reconstructedData: string = ""; stream.onData.add((data) => { const chunkData = JSON.parse(data as string); reconstructedData += chunkData.data; if (chunkData.eor) { elm.innerText += reconstructedData + '\n'; reconstructedData = ""; } }); } } };

本実装例では、受信したデータを連結することで元の文字列を復元します。 その上で、 EoRtrue すなわち受信したチャンクが末尾のものであったら、一連の文字列を復元し終えたとして画面に結果を表示しています。