Transmitting an ArrayBuffer with metadata (over a

2019-05-31 23:44发布

In docs, I see the following example for sending a string over a WebRTC data channel:

var message = messageInputBox.value;
sendChannel.send(message);

I'm trying to send images and video - so I create an ArrayBuffer:

var reader = new FileReader();
reader.addEventListener("loadend", function () {
     // reader.result contains the contents of blob as a typed array
     data.media = reader.result; // ArrayBuffer
     outboundMediaQueue.push(data);
});
reader.readAsArrayBuffer(data.media);

I can transmit this ArrayBuffer, but I'm trying to also send some metadata alongside it (media ID). Given that I can't JSON.serialize an ArrayBuffer - how can I transfer this data with corresponding metadata?

Update:

This works:

sendChannel.send(data.media); // sending `ArrayBuffer` only

But this doesn't work:

sendChannel.send(data); // arbitrary object with desired metadata

And this also doesn't work:

sendChannel.send(JSON.stringify(data));

Update 2

I've composed the following module that seems to handle the encoding and decoding. It's not quite fully tested and hasn't been run against large files; I'll keep this updated as I figure out what works:

define([], function () {
    // https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#Solution_2_–_rewrite_the_DOMs_atob()_and_btoa()_using_JavaScript's_TypedArrays_and_UTF-8
    // https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String

    const arrayBufferConverter = {};
    arrayBufferConverter.bufferToString = function (outboundBuffer) {
        const dataView = new DataView(outboundBuffer);
        const decoder = new TextDecoder('utf-8'); // base64?
        const decodedString = decoder.decode(dataView);
        return decodedString;
    }

    arrayBufferConverter.stringToBuffer = function (inboundString) {
        var encoded = new TextEncoderLite('utf-8').encode(inboundString);
        var b64Encoded = base64js.fromByteArray(encoded);
        return b64Encoded;
    }

    return arrayBufferConverter;
});

Update 3

Since my only real need here is to pair metadata with the ArrayBuffer, I'm going to forget the encoding/decoding nonsense and just generate a digest on both ends of the transaction:

arrayBufferConverter.getDigestFromBuffer = function (buffer) {
    const view = new DataView(buffer);
    const numBytes = view.byteLength;
    const interval = Math.floor(numBytes / 32);
    var currentIndex = 0;
    var digest = "";
    while (currentIndex < numBytes) {
        digest += view.getInt8(currentIndex);
        currentIndex += interval;
    }
    return digest;
}

This way I'll send the ArrayBuffers and corresponding metadata in two separate requests and manage the pairing with some basic queue logic. This totally eliminates ongoing processing cost and the risks inherent in encoding/decoding large media files in favor of a small fixed cost of pairing logic. I'll leave this open in case anyone has any other recommendations.

0条回答
登录 后发表回答