blob: d07e00e39a5010875aac2b9f563af502b114cba5 [file] [log] [blame]
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <memory>
#include <limits>
#include "absl/memory/memory.h"
#include "api/datachannelinterface.h"
#include "rtc_base/logging.h"
#include "sdk/android/generated_peerconnection_jni/jni/DataChannel_jni.h"
#include "sdk/android/native_api/jni/java_types.h"
#include "sdk/android/src/jni/jni_helpers.h"
#include "sdk/android/src/jni/pc/datachannel.h"
namespace webrtc {
namespace jni {
namespace {
// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
// and dispatching the callback from C++ back to Java.
class DataChannelObserverJni : public DataChannelObserver {
public:
DataChannelObserverJni(JNIEnv* jni, const JavaRef<jobject>& j_observer);
~DataChannelObserverJni() override {}
void OnBufferedAmountChange(uint64_t previous_amount) override;
void OnStateChange() override;
void OnMessage(const DataBuffer& buffer) override;
private:
const ScopedJavaGlobalRef<jobject> j_observer_global_;
};
DataChannelObserverJni::DataChannelObserverJni(
JNIEnv* jni,
const JavaRef<jobject>& j_observer)
: j_observer_global_(jni, j_observer) {}
void DataChannelObserverJni::OnBufferedAmountChange(uint64_t previous_amount) {
JNIEnv* env = AttachCurrentThreadIfNeeded();
Java_Observer_onBufferedAmountChange(env, j_observer_global_,
previous_amount);
}
void DataChannelObserverJni::OnStateChange() {
JNIEnv* env = AttachCurrentThreadIfNeeded();
Java_Observer_onStateChange(env, j_observer_global_);
}
void DataChannelObserverJni::OnMessage(const DataBuffer& buffer) {
JNIEnv* env = AttachCurrentThreadIfNeeded();
ScopedJavaLocalRef<jobject> byte_buffer = NewDirectByteBuffer(
env, const_cast<char*>(buffer.data.data<char>()), buffer.data.size());
ScopedJavaLocalRef<jobject> j_buffer =
Java_Buffer_Constructor(env, byte_buffer, buffer.binary);
Java_Observer_onMessage(env, j_observer_global_, j_buffer);
}
DataChannelInterface* ExtractNativeDC(JNIEnv* jni,
const JavaParamRef<jobject>& j_dc) {
return reinterpret_cast<DataChannelInterface*>(
Java_DataChannel_getNativeDataChannel(jni, j_dc));
}
} // namespace
DataChannelInit JavaToNativeDataChannelInit(JNIEnv* env,
const JavaRef<jobject>& j_init) {
DataChannelInit init;
init.ordered = Java_Init_getOrdered(env, j_init);
init.maxRetransmitTime = Java_Init_getMaxRetransmitTimeMs(env, j_init);
init.maxRetransmits = Java_Init_getMaxRetransmits(env, j_init);
init.protocol = JavaToStdString(env, Java_Init_getProtocol(env, j_init));
init.negotiated = Java_Init_getNegotiated(env, j_init);
init.id = Java_Init_getId(env, j_init);
return init;
}
ScopedJavaLocalRef<jobject> WrapNativeDataChannel(
JNIEnv* env,
rtc::scoped_refptr<DataChannelInterface> channel) {
if (!channel)
return nullptr;
// Channel is now owned by Java object, and will be freed from there.
return Java_DataChannel_Constructor(env, jlongFromPointer(channel.release()));
}
static jlong JNI_DataChannel_RegisterObserver(
JNIEnv* jni,
const JavaParamRef<jobject>& j_dc,
const JavaParamRef<jobject>& j_observer) {
auto observer = absl::make_unique<DataChannelObserverJni>(jni, j_observer);
ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
return jlongFromPointer(observer.release());
}
static void JNI_DataChannel_UnregisterObserver(
JNIEnv* jni,
const JavaParamRef<jobject>& j_dc,
jlong native_observer) {
ExtractNativeDC(jni, j_dc)->UnregisterObserver();
delete reinterpret_cast<DataChannelObserverJni*>(native_observer);
}
static ScopedJavaLocalRef<jstring> JNI_DataChannel_Label(
JNIEnv* jni,
const JavaParamRef<jobject>& j_dc) {
return NativeToJavaString(jni, ExtractNativeDC(jni, j_dc)->label());
}
static jint JNI_DataChannel_Id(JNIEnv* jni, const JavaParamRef<jobject>& j_dc) {
int id = ExtractNativeDC(jni, j_dc)->id();
RTC_CHECK_LE(id, std::numeric_limits<int32_t>::max())
<< "id overflowed jint!";
return static_cast<jint>(id);
}
static ScopedJavaLocalRef<jobject> JNI_DataChannel_State(
JNIEnv* jni,
const JavaParamRef<jobject>& j_dc) {
return Java_State_fromNativeIndex(jni, ExtractNativeDC(jni, j_dc)->state());
}
static jlong JNI_DataChannel_BufferedAmount(JNIEnv* jni,
const JavaParamRef<jobject>& j_dc) {
uint64_t buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
RTC_CHECK_LE(buffered_amount, std::numeric_limits<int64_t>::max())
<< "buffered_amount overflowed jlong!";
return static_cast<jlong>(buffered_amount);
}
static void JNI_DataChannel_Close(JNIEnv* jni,
const JavaParamRef<jobject>& j_dc) {
ExtractNativeDC(jni, j_dc)->Close();
}
static jboolean JNI_DataChannel_Send(JNIEnv* jni,
const JavaParamRef<jobject>& j_dc,
const JavaParamRef<jbyteArray>& data,
jboolean binary) {
jbyte* bytes = jni->GetByteArrayElements(data.obj(), nullptr);
bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
rtc::CopyOnWriteBuffer(bytes, jni->GetArrayLength(data.obj())), binary));
jni->ReleaseByteArrayElements(data.obj(), bytes, JNI_ABORT);
return ret;
}
} // namespace jni
} // namespace webrtc