devopvoid / webrtc-java

WebRTC for desktop platforms running Java
Apache License 2.0
248 stars 60 forks source link

Fragmentation support for DataChannel #36

Open thelsing opened 2 years ago

thelsing commented 2 years ago

Is your feature request related to a problem? Please describe. I learned today, that DataChannel only supports message sizes around 16 KB. When I tried to send around 770 KB the channel was closed. Now I have to fragment my data.

Describe the solution you'd like It would be nice if I could just send any amount of data. The lib would only deliver the message as a byte array and notify the receiver when the whole message is complete. Additional events for start of transmission and x bytes received would be nice to. This way the receiver can display a progress bar.

Describe alternatives you've considered Write the fragmentation support myself.

thelsing commented 2 years ago

I went with

            ByteBuffer buffer = ByteBuffer.allocate(message.length + Integer.BYTES);
            buffer.putInt(message.length).put(message).rewind();

            int chunkSize = 16 * 1024;

            while (buffer.remaining() > 0) {
              var amountToSend = buffer.remaining() <= chunkSize ? buffer.remaining() : chunkSize;
              ByteBuffer part = buffer;

              if (amountToSend != buffer.capacity()) {
                // we need to allocation a new ByteBuffer because send calls ByteBuffer.array()
                // which would return
                // the whole byte[] and not only the slice. But the lib doesn't use
                // ByteBuffer.arrayOffset().
                var slice = buffer.slice(buffer.position(), amountToSend);
                part = ByteBuffer.allocate(amountToSend);
                part.put(slice);
              }

              buffer.position(buffer.position() + amountToSend);
              localDataChannel.send(new RTCDataChannelBuffer(part, true));
              log.debug(prefix() + " sent " + part.capacity() + " bytes");
            }

for sending and

private ByteBuffer messageBuffer = null;
public final byte[] readMessage(ByteBuffer part) {
    if (messageBuffer == null) {
      int length = part.getInt();
      notifyListeners(Direction.Inbound, State.Start, length, 0);

      if (part.remaining() == length) {
        var ret = new byte[length];
        part.get(ret);
        notifyListeners(Direction.Inbound, State.Complete, length, length);
        return ret;
      }

      messageBuffer = ByteBuffer.allocate(length);
    }

    messageBuffer.put(part);
    notifyListeners(
        Direction.Inbound, State.Progress, messageBuffer.capacity(), messageBuffer.position());

    if (messageBuffer.capacity() == messageBuffer.position()) {
      notifyListeners(
          Direction.Inbound, State.Complete, messageBuffer.capacity(), messageBuffer.capacity());
      var ret = messageBuffer.array();
      messageBuffer = null;
      return ret;
    }

    return null;
  }

plus null checking for receiving.

stserakhau commented 1 year ago

look to this article https://stackoverflow.com/questions/35381237/webrtc-data-channel-max-data-size

plus you should understand that it's UDP and part of the data may lost in network, I saw this case on transmitting files great than 500kb on slow network connection (at the moment not sure is it bug of the library or success part of data transmission via webrtc technology)