blob: 50c81c5c78f776445ac73183fdea3a9cade9c5f8 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/devtools_bridge/android/session_dependency_factory_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/bind.h"
#include "components/devtools_bridge/abstract_data_channel.h"
#include "components/devtools_bridge/abstract_peer_connection.h"
#include "components/devtools_bridge/rtc_configuration.h"
#include "components/devtools_bridge/socket_tunnel_server.h"
#include "jni/SessionDependencyFactoryNative_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
namespace devtools_bridge {
namespace android {
namespace {
/**
* Wraps Java observer and adapts it to native delegate. Chromium code normally
* leaves local java references for automatic disposing. It doesn't happen here
* (because calls originated from native thread). For instance, instead of
*
* ConvertUTF8ToJavaString(env, ...).Release()
*
* please use ConvertUTF8ToJavaString(env, ...).obj() or ScopedJavaLocalFrame.
*/
class PeerConnectionDelegateImpl
: public AbstractPeerConnection::Delegate {
public:
PeerConnectionDelegateImpl(JNIEnv* env, jobject java_object) {
java_object_.Reset(env, java_object);
connected_ = false;
}
void OnIceConnectionChange(bool connected) override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyIceConnectionChange(
env, java_object_.obj(), connected);
}
void OnIceCandidate(const std::string& sdp_mid,
int sdp_mline_index,
const std::string& sdp) override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyIceCandidate(
env, java_object_.obj(),
ConvertUTF8ToJavaString(env, sdp_mid).obj(),
sdp_mline_index, ConvertUTF8ToJavaString(env, sdp).obj());
}
void NotifyLocalOfferCreatedAndSetSet(const std::string& description) {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyLocalOfferCreatedAndSetSet(
env, java_object_.obj(),
ConvertUTF8ToJavaString(env, description).obj());
}
void OnLocalOfferCreatedAndSetSet(const std::string& description) override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyLocalOfferCreatedAndSetSet(
env, java_object_.obj(),
ConvertUTF8ToJavaString(env, description).obj());
}
void OnLocalAnswerCreatedAndSetSet(const std::string& description) override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyLocalAnswerCreatedAndSetSet(
env, java_object_.obj(),
ConvertUTF8ToJavaString(env, description).obj());
}
void OnRemoteDescriptionSet() override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyRemoteDescriptionSet(
env, java_object_.obj());
}
void OnFailure(const std::string& description) override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyConnectionFailure(
env, java_object_.obj(),
ConvertUTF8ToJavaString(env, description).obj());
}
private:
base::android::ScopedJavaGlobalRef<jobject> java_object_;
bool connected_;
};
class DataChannelObserverImpl : public AbstractDataChannel::Observer {
public:
DataChannelObserverImpl(JNIEnv* env, jobject java_object) {
java_object_.Reset(env, java_object);
}
void OnOpen() override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyChannelOpen(
env, java_object_.obj());
}
void OnClose() override {
JNIEnv* env = AttachCurrentThread();
Java_SessionDependencyFactoryNative_notifyChannelClose(
env, java_object_.obj());
}
void OnMessage(const void* data, size_t length) override {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> byte_buffer(
env, env->NewDirectByteBuffer(const_cast<void*>(data), length));
Java_SessionDependencyFactoryNative_notifyMessage(
env, java_object_.obj(), byte_buffer.obj());
}
private:
base::android::ScopedJavaGlobalRef<jobject> java_object_;
};
static void CleanupOnSignalingThread() {
// Called on signaling thread when SessionDependencyFactory is destroying.
base::android::DetachFromVM();
}
} // namespace
// SessionDependencyFactoryNative
SessionDependencyFactoryAndroid::SessionDependencyFactoryAndroid()
: impl_(SessionDependencyFactory::CreateInstance(
base::Bind(&CleanupOnSignalingThread))) {
}
SessionDependencyFactoryAndroid::~SessionDependencyFactoryAndroid() {
}
// static
bool SessionDependencyFactoryAndroid::RegisterNatives(JNIEnv* env) {
return RegisterNativesImpl(env);
}
scoped_ptr<AbstractPeerConnection>
SessionDependencyFactoryAndroid::CreatePeerConnection(
scoped_ptr<RTCConfiguration> config,
scoped_ptr<AbstractPeerConnection::Delegate> delegate) {
return impl_->CreatePeerConnection(config.Pass(), delegate.Pass());
}
scoped_refptr<base::TaskRunner>
SessionDependencyFactoryAndroid::signaling_thread_task_runner() {
return impl_->signaling_thread_task_runner();
}
scoped_refptr<base::TaskRunner>
SessionDependencyFactoryAndroid::io_thread_task_runner() {
return impl_->io_thread_task_runner();
}
// JNI generated methods
static jlong CreateFactory(JNIEnv* env, jclass jcaller) {
return reinterpret_cast<jlong>(new SessionDependencyFactoryAndroid());
}
static void DestroyFactory(JNIEnv* env, jclass jcaller, jlong factory_ptr) {
delete reinterpret_cast<SessionDependencyFactoryAndroid*>(factory_ptr);
}
static jlong CreateConfig(JNIEnv* env, jclass jcaller) {
return reinterpret_cast<jlong>(
RTCConfiguration::CreateInstance().release());
}
static void AddIceServer(
JNIEnv* env, jclass jcaller, jlong config_ptr,
jstring uri, jstring username, jstring credential) {
reinterpret_cast<RTCConfiguration*>(config_ptr)->AddIceServer(
ConvertJavaStringToUTF8(env, uri),
ConvertJavaStringToUTF8(env, username),
ConvertJavaStringToUTF8(env, credential));
}
static jlong CreatePeerConnection(
JNIEnv* env, jclass jcaller,
jlong factory_ptr, jlong config_ptr, jobject observer) {
auto factory =
reinterpret_cast<SessionDependencyFactoryAndroid*>(factory_ptr);
auto config = reinterpret_cast<RTCConfiguration*>(config_ptr);
auto delegate = new PeerConnectionDelegateImpl(env, observer);
return reinterpret_cast<jlong>(factory->CreatePeerConnection(
make_scoped_ptr(config), make_scoped_ptr(delegate)).release());
}
static void DestroyPeerConnection(
JNIEnv* env, jclass jcaller, jlong connection_ptr) {
delete reinterpret_cast<AbstractPeerConnection*>(connection_ptr);
}
static void CreateAndSetLocalOffer(
JNIEnv* env, jclass jcaller, jlong connection_ptr) {
reinterpret_cast<AbstractPeerConnection*>(
connection_ptr)->CreateAndSetLocalOffer();
}
static void CreateAndSetLocalAnswer(
JNIEnv* env, jclass jcaller, jlong connection_ptr) {
reinterpret_cast<AbstractPeerConnection*>(
connection_ptr)->CreateAndSetLocalAnswer();
}
static void SetRemoteOffer(
JNIEnv* env, jclass jcaller, jlong connection_ptr, jstring description) {
reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->SetRemoteOffer(
ConvertJavaStringToUTF8(env, description));
}
static void SetRemoteAnswer(
JNIEnv* env, jclass jcaller, jlong connection_ptr, jstring description) {
reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->SetRemoteAnswer(
ConvertJavaStringToUTF8(env, description));
}
static void AddIceCandidate(
JNIEnv* env, jclass jcaller,
jlong connection_ptr, jstring sdp_mid, jint sdp_mline_index, jstring sdp) {
reinterpret_cast<AbstractPeerConnection*>(connection_ptr)->AddIceCandidate(
ConvertJavaStringToUTF8(env, sdp_mid),
sdp_mline_index,
ConvertJavaStringToUTF8(env, sdp));
}
static jlong CreateDataChannel(
JNIEnv* env, jclass jcaller, jlong connection_ptr, jint channel_id) {
return reinterpret_cast<jlong>(
reinterpret_cast<AbstractPeerConnection*>(
connection_ptr)->CreateDataChannel(channel_id).release());
}
static void DestroyDataChannel(
JNIEnv* env, jclass jcaller, jlong channel_ptr) {
delete reinterpret_cast<AbstractDataChannel*>(channel_ptr);
}
static void RegisterDataChannelObserver(
JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject observer) {
reinterpret_cast<AbstractDataChannel*>(channel_ptr)->RegisterObserver(
make_scoped_ptr(new DataChannelObserverImpl(env, observer)));
}
static void UnregisterDataChannelObserver(
JNIEnv* env, jclass jcaller, jlong channel_ptr) {
reinterpret_cast<AbstractDataChannel*>(channel_ptr)->UnregisterObserver();
}
static void SendBinaryMessage(
JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject message,
jint size) {
DCHECK(size > 0);
reinterpret_cast<AbstractDataChannel*>(channel_ptr)->SendBinaryMessage(
env->GetDirectBufferAddress(message), size);
}
static void SendTextMessage(
JNIEnv* env, jclass jcaller, jlong channel_ptr, jobject message,
jint size) {
DCHECK(size > 0);
reinterpret_cast<AbstractDataChannel*>(channel_ptr)->SendTextMessage(
env->GetDirectBufferAddress(message), size);
}
static void CloseDataChannel(JNIEnv* env, jclass jcaller, jlong channel_ptr) {
reinterpret_cast<AbstractDataChannel*>(channel_ptr)->Close();
}
static jlong CreateSocketTunnelServer(
JNIEnv* env, jclass jcaller, jlong factory_ptr, jlong channel_ptr,
jstring socket_name) {
return reinterpret_cast<jlong>(
new SocketTunnelServer(
reinterpret_cast<SessionDependencyFactory*>(factory_ptr),
reinterpret_cast<AbstractDataChannel*>(channel_ptr),
ConvertJavaStringToUTF8(env, socket_name)));
}
static void DestroySocketTunnelServer(
JNIEnv* env, jclass jcaller, jlong tunnel_ptr) {
delete reinterpret_cast<SocketTunnelServer*>(tunnel_ptr);
}
} // namespace android
} // namespace devtools_bridge