Search code examples
webrtcfile-transferrtcdatachannelpeer-connection

WebRTC DataChannel buffered full


At first, I hope you understand that I'm not good at english.

For file transfer, in Mesh topology, in Chrome,

When buffered amount is 16MB, the channel is closed with an error message.

"Uncaught NetworkError: Failed to execute 'send' on 'RTCDataChannel': Could not send data"
(It is in chrome, not firefox.)

How to send a file(more than 16MB)?

fileWorker.js

var chunkSize = 16384;
onmessage = function(event) {
    var file = event.data[0],
        callbackId = event.data[1],
        totalSize = file.size,
        chunks = [],
        curSize = 0,
        reader,
        chunk;

    if (!FileReaderSync) {
        reader = new FileReader();
        reader.onload = function(event) {
            console.log('chunking...');
            chunks.push(event.target.result);
            curSize += chunkSize;
            slice();
        };
        slice();
    } else {
        reader = new FileReaderSync();
        while (curSize < totalSize) {
            console.log('chunking...');
            chunk = file.slice(curSize, curSize + chunkSize);
            chunks.push(reader.readAsArrayBuffer(chunk));
            curSize += chunkSize;
        }
        postMessage([chunks, file.name, callbackId]);
    }

    function slice() {
        if (curSize > totalSize) {
            postMessage([chunks, file.name, callbackId]);
        } else {
            chunk = file.slice(curSize, curSize + chunkSize);
            reader.readAsArrayBuffer(chunk);
        }
    }
};

fileSender

_fileToPeers: function(chunks, fileName, progressCallbackId) {
    var callback = callbacks[progressCallbackId],
        chunkCount,
        peerCount = 0;

    objForEach(this.peers, function(peer) {
        var channel = peer.fileChannel;
        peerCount += 1;

        if (channel) {
            chunkCount = 0;
            chunks.forEach(function(chunk) {
                channel.send(chunk);
                chunkCount += 1;
                console.log('sending...');         // abnormal works!  
                callback(peerCount, chunkCount);   // abnormal works!
            });
            channel.send(['end', fileName].join(','));
        }
    });
    delete callbacks[progressCallbackId];
},

Solution

  • I tried to solve this problem.
    I just use the recursive function call with setTimeout.

    Code

        _fileToPeers: function(chunks, fileName, progressCallbackId) {
            var callback = callbacks[progressCallbackId];
    
            objForEach(this.peers, function(peer) {
                var channel = peer.fileChannel;
                if (channel && !channel.using) {
                    channel.using = true;
                    this._chunksInChannel(chunks, 0, fileName, channel, callback);
                }
            }, this);
            delete callbacks[progressCallbackId];
        },
    
        _chunksInChannel: function(chunks, chunkIdx, fileName, channel, callback) {
            var length = chunks.length,
                doNext = chunkIdx < length;
    
            while (doNext) {
                if (channel.bufferedAmount > CHANNEL_BUFFER_MAX) {
                    setTimeout(function () {
                        this._chunksInChannel(chunks, chunkIdx, fileName, channel, callback);
                    }.bind(this), 500);
                    doNext = false;
                } else {
                    channel.send(chunks[chunkIdx]);
                    chunkIdx += 1;
                    if (chunkIdx === length) {
                        channel.send(['end', fileName].join(','));
                        doNext = false;
                        channel.using = false;
                    }
                    callback(chunkIdx);
                }
            }
        },
    

    Haven't you something better?