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 であり、後述するデータ復元処理で利用します。

上記の実装を施してもエラーが発生する場合、内部バッファが溢れている恐れがあります。 その際には、適宜 sleep 処理を入れるなどしてご対応ください。

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 すなわち受信したチャンクが末尾のものであったら、一連の文字列を復元し終えたとして画面に結果を表示しています。