diff --git a/webrtc/src/main/java/dev/onvoid/webrtc/RTCDataChannel.java b/webrtc/src/main/java/dev/onvoid/webrtc/RTCDataChannel.java index 87c3ec6b..b04f076e 100644 --- a/webrtc/src/main/java/dev/onvoid/webrtc/RTCDataChannel.java +++ b/webrtc/src/main/java/dev/onvoid/webrtc/RTCDataChannel.java @@ -143,7 +143,10 @@ private RTCDataChannel() { public native void dispose(); /** - * Sends data in the provided buffer to the remote peer. + * Sends data in the provided buffer to the remote peer. Only the bytes + * between the buffer's position and limit are sent, for heap and direct + * buffers alike. The buffer is read through a duplicate, so the caller's + * position is left untouched. * * @param buffer The buffer to be queued for transmission. * @@ -154,21 +157,37 @@ public void send(RTCDataChannelBuffer buffer) throws Exception { ByteBuffer data = buffer.data; if (data.isDirect()) { - sendDirectBuffer(data, buffer.binary); - } - else { - byte[] arrayBuffer; - - if (data.hasArray()) { - arrayBuffer = data.array(); + if (data.position() == 0 && data.limit() == data.capacity()) { + sendDirectBuffer(data, buffer.binary); } else { - arrayBuffer = new byte[data.remaining()]; - data.get(arrayBuffer); + ByteBuffer window = ByteBuffer.allocateDirect(data.remaining()); + window.put(data.duplicate()); + window.flip(); + sendDirectBuffer(window, buffer.binary); } + } + else { + sendByteArrayBuffer(copyWindow(data), buffer.binary); + } + } - sendByteArrayBuffer(arrayBuffer, buffer.binary); + /** + * Copies the readable window of a heap buffer, position to limit, into a + * fresh array for the byte array send path, which transmits whole arrays. + * The backing array is handed over directly only when the window covers + * it exactly; bytes outside the window (a nonzero position, a short + * limit, an array offset) must never reach the wire. Reads through a + * duplicate, so the caller's position is left untouched. + */ + private static byte[] copyWindow(ByteBuffer data) { + if (data.hasArray() && data.arrayOffset() == 0 && data.position() == 0 + && data.remaining() == data.array().length) { + return data.array(); } + byte[] window = new byte[data.remaining()]; + data.duplicate().get(window); + return window; } private native void sendDirectBuffer(ByteBuffer buffer, boolean binary);