Skip to content

Commit f531fa6

Browse files
feat: add asynchronous sendAsync to RTCDataChannel (#246)
1 parent 2a7449c commit f531fa6

3 files changed

Lines changed: 105 additions & 1 deletion

File tree

webrtc-jni/src/main/cpp/include/JNI_RTCDataChannel.h

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webrtc-jni/src/main/cpp/src/JNI_RTCDataChannel.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "JavaUtils.h"
2424

2525
#include "api/data_channel_interface.h"
26+
#include "rtc_base/logging.h"
2627

2728
#include <memory>
2829

@@ -192,11 +193,64 @@ JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_sendByteArrayBuffer
192193
webrtc::CopyOnWriteBuffer data(arrayPtr, arrayLength);
193194

194195
env->ReleaseByteArrayElements(jBufferArray, arrayPtr, JNI_ABORT);
195-
196+
196197
try {
197198
channel->Send(webrtc::DataBuffer(data, static_cast<bool>(isBinary)));
198199
}
199200
catch (...) {
200201
ThrowCxxJavaException(env);
201202
}
203+
}
204+
205+
// Completion handler shared by the async send paths. Queueing failures are
206+
// logged; on fatal errors WebRTC closes the channel, which the registered
207+
// data channel observer sees as a state change.
208+
static void logSendAsyncError(webrtc::RTCError error)
209+
{
210+
if (!error.ok()) {
211+
RTC_LOG(LS_WARNING) << "SendAsync failed: " << error.message();
212+
}
213+
}
214+
215+
JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_sendDirectBufferAsync
216+
(JNIEnv * env, jobject caller, jobject jBuffer, jint position, jint length, jboolean isBinary)
217+
{
218+
webrtc::DataChannelInterface * channel = GetHandle<webrtc::DataChannelInterface>(env, caller);
219+
CHECK_HANDLE(channel);
220+
221+
uint8_t * address = static_cast<uint8_t *>(env->GetDirectBufferAddress(jBuffer));
222+
223+
if (address != NULL) {
224+
jlong capacity = env->GetDirectBufferCapacity(jBuffer);
225+
226+
if (position < 0 || length < 0 || static_cast<jlong>(position) + length > capacity) {
227+
env->Throw(jni::JavaError(env, "Buffer position/length out of bounds"));
228+
return;
229+
}
230+
231+
// The data is copied into the CopyOnWriteBuffer before this call
232+
// returns, so the caller may reuse the direct buffer immediately.
233+
webrtc::CopyOnWriteBuffer data(address + position, static_cast<size_t>(length));
234+
235+
channel->SendAsync(webrtc::DataBuffer(data, static_cast<bool>(isBinary)), &logSendAsyncError);
236+
}
237+
else {
238+
env->Throw(jni::JavaError(env, "Non-direct buffer provided"));
239+
}
240+
}
241+
242+
JNIEXPORT void JNICALL Java_dev_onvoid_webrtc_RTCDataChannel_sendByteArrayBufferAsync
243+
(JNIEnv * env, jobject caller, jbyteArray jBufferArray, jboolean isBinary)
244+
{
245+
webrtc::DataChannelInterface * channel = GetHandle<webrtc::DataChannelInterface>(env, caller);
246+
CHECK_HANDLE(channel);
247+
248+
int8_t * arrayPtr = env->GetByteArrayElements(jBufferArray, nullptr);
249+
size_t arrayLength = env->GetArrayLength(jBufferArray);
250+
251+
webrtc::CopyOnWriteBuffer data(arrayPtr, arrayLength);
252+
253+
env->ReleaseByteArrayElements(jBufferArray, arrayPtr, JNI_ABORT);
254+
255+
channel->SendAsync(webrtc::DataBuffer(data, static_cast<bool>(isBinary)), &logSendAsyncError);
202256
}

webrtc/src/main/java/dev/onvoid/webrtc/RTCDataChannel.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,38 @@ private static byte[] copyWindow(ByteBuffer data) {
194194

195195
private native void sendByteArrayBuffer(byte[] buffer, boolean binary);
196196

197+
/**
198+
* Sends data in the provided buffer to the remote peer without blocking
199+
* the calling thread on the native network thread, unlike
200+
* {@link #send(RTCDataChannelBuffer)} whose call is marshalled
201+
* synchronously. The data is copied out of the buffer before this method
202+
* returns, so the buffer may be reused immediately; only the bytes
203+
* between position and limit are sent.
204+
*
205+
* Errors are reported asynchronously: queueing failures are logged
206+
* natively, and fatal errors close the data channel, which the registered
207+
* {@link RTCDataChannelObserver} sees as a state change.
208+
*
209+
* @param buffer The buffer to be queued for transmission.
210+
*/
211+
public void sendAsync(RTCDataChannelBuffer buffer) {
212+
ByteBuffer data = buffer.data;
213+
214+
if (data.isDirect()) {
215+
sendDirectBufferAsync(data, data.position(), data.remaining(), buffer.binary);
216+
}
217+
else {
218+
// The byte array path transmits whole arrays, so copy exactly
219+
// the readable window, position to limit; a duplicate leaves
220+
// the caller's position untouched.
221+
byte[] window = new byte[data.remaining()];
222+
data.duplicate().get(window);
223+
sendByteArrayBufferAsync(window, buffer.binary);
224+
}
225+
}
226+
227+
private native void sendDirectBufferAsync(ByteBuffer buffer, int position, int length, boolean binary);
228+
229+
private native void sendByteArrayBufferAsync(byte[] buffer, boolean binary);
230+
197231
}

0 commit comments

Comments
 (0)