blob: de7e3dd0b79322dca716f94c0e878aeb17224abb [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
fischman@webrtc.org33584f92013-07-25 16:43:30 +00003 * Copyright 2013, Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Hints for future visitors:
29// This entire file is an implementation detail of the org.webrtc Java package,
30// the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31// The layout of this file is roughly:
32// - various helper C++ functions & classes that wrap Java counterparts and
33// expose a C++ interface that can be passed to the C++ PeerConnection APIs
34// - implementations of methods declared "static" in the Java package (named
35// things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36// the JNI spec).
37//
38// Lifecycle notes: objects are owned where they will be called; in other words
39// FooObservers are owned by C++-land, and user-callable objects (e.g.
40// PeerConnection and VideoTrack) are owned by Java-land.
41// When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42// ref simulating the jlong held in Java-land, and then Release()s the ref in
43// the respective free call. Sometimes this AddRef is implicit in the
44// construction of a scoped_refptr<> which is then .release()d.
45// Any persistent (non-local) references from C++ to Java must be global or weak
46// (in which case they must be checked before use)!
47//
48// Exception notes: pretty much all JNI calls can throw Java exceptions, so each
49// call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50// call. In this file this is done in CHECK_EXCEPTION, making for much easier
51// debugging in case of failure (the alternative is to wait for control to
52// return to the Java frame that called code in this file, at which point it's
53// impossible to tell which JNI call broke).
54
55#include <jni.h>
56#undef JNIEXPORT
57#define JNIEXPORT __attribute__((visibility("default")))
58
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000059#include <asm/unistd.h>
henrike@webrtc.org723d6832013-07-12 16:04:50 +000060#include <limits>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061#include <map>
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000062#include <sys/prctl.h>
63#include <sys/syscall.h>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064
65#include "talk/app/webrtc/mediaconstraintsinterface.h"
66#include "talk/app/webrtc/peerconnectioninterface.h"
67#include "talk/app/webrtc/videosourceinterface.h"
68#include "talk/base/logging.h"
69#include "talk/base/ssladapter.h"
70#include "talk/media/base/videocapturer.h"
71#include "talk/media/base/videorenderer.h"
72#include "talk/media/devices/videorendererfactory.h"
73#include "talk/media/webrtc/webrtcvideocapturer.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000074#include "third_party/icu/source/common/unicode/unistr.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000075#include "webrtc/system_wrappers/interface/trace.h"
76#include "webrtc/video_engine/include/vie_base.h"
77#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078
79using icu::UnicodeString;
80using webrtc::AudioSourceInterface;
81using webrtc::AudioTrackInterface;
82using webrtc::AudioTrackVector;
83using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +000084using webrtc::DataBuffer;
85using webrtc::DataChannelInit;
86using webrtc::DataChannelInterface;
87using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088using webrtc::IceCandidateInterface;
89using webrtc::MediaConstraintsInterface;
90using webrtc::MediaSourceInterface;
91using webrtc::MediaStreamInterface;
92using webrtc::MediaStreamTrackInterface;
93using webrtc::PeerConnectionFactoryInterface;
94using webrtc::PeerConnectionInterface;
95using webrtc::PeerConnectionObserver;
96using webrtc::SessionDescriptionInterface;
97using webrtc::SetSessionDescriptionObserver;
98using webrtc::StatsObserver;
99using webrtc::StatsReport;
100using webrtc::VideoRendererInterface;
101using webrtc::VideoSourceInterface;
102using webrtc::VideoTrackInterface;
103using webrtc::VideoTrackVector;
104using webrtc::VideoRendererInterface;
105
106// Abort the process if |x| is false, emitting |msg|.
107#define CHECK(x, msg) \
108 if (x) {} else { \
109 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
110 abort(); \
111 }
112// Abort the process if |jni| has a Java exception pending, emitting |msg|.
113#define CHECK_EXCEPTION(jni, msg) \
114 if (0) {} else { \
115 if (jni->ExceptionCheck()) { \
116 jni->ExceptionDescribe(); \
117 jni->ExceptionClear(); \
118 CHECK(0, msg); \
119 } \
120 }
121
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000122// Helper that calls ptr->Release() and logs a useful message if that didn't
123// actually delete *ptr because of extra refcounts.
124#define CHECK_RELEASE(ptr) \
125 do { \
126 int count = (ptr)->Release(); \
127 if (count != 0) { \
128 LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr) \
129 << ": " << count; \
130 } \
131 CHECK(!count, "Unexpected refcount"); \
132 } while (0)
133
fischman@webrtc.org87881672013-09-03 18:58:12 +0000134// Lifted from chromium's base/basictypes.h.
135template <bool>
136struct CompileAssert {};
137#define COMPILE_ASSERT(expr, msg) \
138 typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
139
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140namespace {
141
142static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
143
144static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
145static pthread_key_t g_jni_ptr; // Key for per-thread JNIEnv* data.
146
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000147// Return thread ID as a string.
148static std::string GetThreadId() {
149 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
150 CHECK(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)) <= sizeof(buf),
151 "Thread id is bigger than uint64??");
152 return std::string(buf);
153}
154
155// Return the current thread's name.
156static std::string GetThreadName() {
157 char name[17];
158 CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
159 name[16] = '\0';
160 return std::string(name);
161}
162
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163static void ThreadDestructor(void* unused) {
164 jint status = g_jvm->DetachCurrentThread();
165 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
166}
167
168static void CreateJNIPtrKey() {
169 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
170 "pthread_key_create");
171}
172
173// Deal with difference in signatures between Oracle's jni.h and Android's.
174static JNIEnv* AttachCurrentThreadIfNeeded() {
175 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
176 "pthread_once");
177 JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
178 if (jni == NULL) {
179#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
180 void* env;
181#else
182 JNIEnv* env;
183#endif
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000184 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
185 JavaVMAttachArgs args;
186 args.version = JNI_VERSION_1_6;
187 args.name = name;
188 args.group = NULL;
189 CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
190 free(name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000191 CHECK(env, "AttachCurrentThread handed back NULL!");
192 jni = reinterpret_cast<JNIEnv*>(env);
193 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
194 }
195 return jni;
196}
197
fischman@webrtc.org87881672013-09-03 18:58:12 +0000198// Return a |jlong| that will automatically convert back to |ptr| when assigned
199// to a |uint64|
200static jlong jlongFromPointer(void* ptr) {
201 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(uint64),
202 Time_to_rethink_the_use_of_jlongs);
203 // Guaranteed to fit by the COMPILE_ASSERT above.
204 uint64 u64 = reinterpret_cast<intptr_t>(ptr);
205 // If the unsigned value fits in the signed type, return it directly.
206 if (u64 <= std::numeric_limits<int64>::max())
207 return u64;
208 // Otherwise, we need to get move u64 into the range of [int64min, -1] subject
209 // to the constraints of remaining equal to |u64| modulo |2^64|.
210 u64 = std::numeric_limits<uint64>::max() - u64; // In [0,int64max].
211 int64 i64 = -u64; // In [-int64max, 0].
212 i64 -= 1; // In [int64min, -1], and i64+2^64==u64.
213 return i64;
214}
215
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216// Android's FindClass() is trickier than usual because the app-specific
217// ClassLoader is not consulted when there is no app-specific frame on the
218// stack. Consequently, we only look up classes once in JNI_OnLoad.
219// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
220class ClassReferenceHolder {
221 public:
222 explicit ClassReferenceHolder(JNIEnv* jni) {
223 LoadClass(jni, "java/nio/ByteBuffer");
224 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000225 LoadClass(jni, "org/webrtc/DataChannel");
226 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
227 LoadClass(jni, "org/webrtc/DataChannel$Init");
228 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229 LoadClass(jni, "org/webrtc/IceCandidate");
230 LoadClass(jni, "org/webrtc/MediaSource$State");
231 LoadClass(jni, "org/webrtc/MediaStream");
232 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
233 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
234 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
235 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
236 LoadClass(jni, "org/webrtc/SessionDescription");
237 LoadClass(jni, "org/webrtc/SessionDescription$Type");
238 LoadClass(jni, "org/webrtc/StatsReport");
239 LoadClass(jni, "org/webrtc/StatsReport$Value");
240 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
241 LoadClass(jni, "org/webrtc/VideoTrack");
242 }
243
244 ~ClassReferenceHolder() {
245 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
246 }
247
248 void FreeReferences(JNIEnv* jni) {
249 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
250 it != classes_.end(); ++it) {
251 jni->DeleteGlobalRef(it->second);
252 }
253 classes_.clear();
254 }
255
256 jclass GetClass(const std::string& name) {
257 std::map<std::string, jclass>::iterator it = classes_.find(name);
258 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
259 return it->second;
260 }
261
262 private:
263 void LoadClass(JNIEnv* jni, const std::string& name) {
264 jclass localRef = jni->FindClass(name.c_str());
265 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
266 CHECK(localRef, name);
267 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
268 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
269 CHECK(globalRef, name);
270 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
271 CHECK(inserted, "Duplicate class name: " << name);
272 }
273
274 std::map<std::string, jclass> classes_;
275};
276
277// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
278static ClassReferenceHolder* g_class_reference_holder = NULL;
279
280// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
281// object/class/method/field is non-null.
282jmethodID GetMethodID(
283 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
284 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
285 CHECK_EXCEPTION(jni,
286 "error during GetMethodID: " << name << ", " << signature);
287 CHECK(m, name << ", " << signature);
288 return m;
289}
290
291jmethodID GetStaticMethodID(
292 JNIEnv* jni, jclass c, const char* name, const char* signature) {
293 jmethodID m = jni->GetStaticMethodID(c, name, signature);
294 CHECK_EXCEPTION(jni,
295 "error during GetStaticMethodID: "
296 << name << ", " << signature);
297 CHECK(m, name << ", " << signature);
298 return m;
299}
300
301jfieldID GetFieldID(
302 JNIEnv* jni, jclass c, const char* name, const char* signature) {
303 jfieldID f = jni->GetFieldID(c, name, signature);
304 CHECK_EXCEPTION(jni, "error during GetFieldID");
305 CHECK(f, name << ", " << signature);
306 return f;
307}
308
309jclass FindClass(JNIEnv* jni, const char* name) {
310 return g_class_reference_holder->GetClass(name);
311}
312
313jclass GetObjectClass(JNIEnv* jni, jobject object) {
314 jclass c = jni->GetObjectClass(object);
315 CHECK_EXCEPTION(jni, "error during GetObjectClass");
316 CHECK(c, "");
317 return c;
318}
319
320jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
321 jobject o = jni->GetObjectField(object, id);
322 CHECK_EXCEPTION(jni, "error during GetObjectField");
323 CHECK(o, "");
324 return o;
325}
326
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000327jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
328 return static_cast<jstring>(GetObjectField(jni, object, id));
329}
330
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
332 jlong l = jni->GetLongField(object, id);
333 CHECK_EXCEPTION(jni, "error during GetLongField");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000334 return l;
335}
336
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000337jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
338 jint i = jni->GetIntField(object, id);
339 CHECK_EXCEPTION(jni, "error during GetIntField");
340 return i;
341}
342
343bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
344 jboolean b = jni->GetBooleanField(object, id);
345 CHECK_EXCEPTION(jni, "error during GetBooleanField");
346 return b;
347}
348
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349jobject NewGlobalRef(JNIEnv* jni, jobject o) {
350 jobject ret = jni->NewGlobalRef(o);
351 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
352 CHECK(ret, "");
353 return ret;
354}
355
356void DeleteGlobalRef(JNIEnv* jni, jobject o) {
357 jni->DeleteGlobalRef(o);
358 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
359}
360
361// Given a jweak reference, allocate a (strong) local reference scoped to the
362// lifetime of this object if the weak reference is still valid, or NULL
363// otherwise.
364class WeakRef {
365 public:
366 WeakRef(JNIEnv* jni, jweak ref)
367 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
368 CHECK_EXCEPTION(jni, "error during NewLocalRef");
369 }
370 ~WeakRef() {
371 if (obj_) {
372 jni_->DeleteLocalRef(obj_);
373 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
374 }
375 }
376 jobject obj() { return obj_; }
377
378 private:
379 JNIEnv* const jni_;
380 jobject const obj_;
381};
382
383// Given a local ref, take ownership of it and delete the ref when this goes out
384// of scope.
385template<class T> // T is jclass, jobject, jintArray, etc.
386class ScopedLocalRef {
387 public:
388 ScopedLocalRef(JNIEnv* jni, T obj)
389 : jni_(jni), obj_(obj) {}
390 ~ScopedLocalRef() {
391 jni_->DeleteLocalRef(obj_);
392 }
393 T operator*() const {
394 return obj_;
395 }
396 private:
397 JNIEnv* jni_;
398 T obj_;
399};
400
401// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000402template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403class ScopedGlobalRef {
404 public:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000405 explicit ScopedGlobalRef(JNIEnv* jni, T obj)
406 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000407 ~ScopedGlobalRef() {
408 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
409 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000410 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411 return obj_;
412 }
413 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000414 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415};
416
417// Return the (singleton) Java Enum object corresponding to |index|;
418// |state_class_fragment| is something like "MediaSource$State".
419jobject JavaEnumFromIndex(
420 JNIEnv* jni, const std::string& state_class_fragment, int index) {
421 std::string state_class_name = "org/webrtc/" + state_class_fragment;
422 jclass state_class = FindClass(jni, state_class_name.c_str());
423 jmethodID state_values_id = GetStaticMethodID(
424 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
425 ScopedLocalRef<jobjectArray> state_values(
426 jni,
427 (jobjectArray)jni->CallStaticObjectMethod(state_class, state_values_id));
428 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
429 jobject ret = jni->GetObjectArrayElement(*state_values, index);
430 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
431 return ret;
432}
433
434// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
435static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
436 UnicodeString ustr(UnicodeString::fromUTF8(native));
437 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
438 CHECK_EXCEPTION(jni, "error during NewString");
439 return jstr;
440}
441
442// Given a (UTF-16) jstring return a new UTF-8 native string.
443static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
444 const jchar* jchars = jni->GetStringChars(j_string, NULL);
445 CHECK_EXCEPTION(jni, "Error during GetStringChars");
446 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
447 CHECK_EXCEPTION(jni, "Error during GetStringLength");
448 jni->ReleaseStringChars(j_string, jchars);
449 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
450 std::string ret;
451 return ustr.toUTF8String(ret);
452}
453
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000454static DataChannelInit JavaDataChannelInitToNative(
455 JNIEnv* jni, jobject j_init) {
456 DataChannelInit init;
457
458 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
459 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
460 jfieldID max_retransmit_time_id =
461 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
462 jfieldID max_retransmits_id =
463 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
464 jfieldID protocol_id =
465 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
466 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
467 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
468
469 init.ordered = GetBooleanField(jni, j_init, ordered_id);
470 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
471 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
472 init.protocol = JavaToStdString(
473 jni, GetStringField(jni, j_init, protocol_id));
474 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
475 init.id = GetIntField(jni, j_init, id_id);
476
477 return init;
478}
479
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480class ConstraintsWrapper;
481
482// Adapter between the C++ PeerConnectionObserver interface and the Java
483// PeerConnection.Observer interface. Wraps an instance of the Java interface
484// and dispatches C++ callbacks to Java.
485class PCOJava : public PeerConnectionObserver {
486 public:
487 PCOJava(JNIEnv* jni, jobject j_observer)
488 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000489 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
490 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
491 j_media_stream_ctor_(GetMethodID(
492 jni, *j_media_stream_class_, "<init>", "(J)V")),
493 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000495 jni, *j_audio_track_class_, "<init>", "(J)V")),
496 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
497 j_video_track_ctor_(GetMethodID(
498 jni, *j_video_track_class_, "<init>", "(J)V")),
499 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
500 j_data_channel_ctor_(GetMethodID(
501 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 }
503
504 virtual ~PCOJava() {}
505
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000506 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 std::string sdp;
508 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
509 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
510 jmethodID ctor = GetMethodID(jni(), candidate_class,
511 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
512 ScopedLocalRef<jstring> j_mid(
513 jni(), JavaStringFromStdString(jni(), candidate->sdp_mid()));
514 ScopedLocalRef<jstring> j_sdp(jni(), JavaStringFromStdString(jni(), sdp));
515 ScopedLocalRef<jobject> j_candidate(jni(), jni()->NewObject(
516 candidate_class, ctor, *j_mid, candidate->sdp_mline_index(), *j_sdp));
517 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000518 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
520 jni()->CallVoidMethod(*j_observer_global_, m, *j_candidate);
521 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
522 }
523
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000524 virtual void OnError() OVERRIDE {
525 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "(V)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 jni()->CallVoidMethod(*j_observer_global_, m);
527 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
528 }
529
530 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000531 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000533 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
535 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
536 jni(), "PeerConnection$SignalingState", new_state));
537 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
538 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
539 }
540
541 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000542 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000544 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
546 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
547 jni(), "PeerConnection$IceConnectionState", new_state));
548 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
549 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
550 }
551
552 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000553 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000555 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
557 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
558 jni(), "PeerConnection$IceGatheringState", new_state));
559 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
560 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
561 }
562
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000563 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 ScopedLocalRef<jobject> j_stream(jni(), jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000565 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566 CHECK_EXCEPTION(jni(), "error during NewObject");
567
568 AudioTrackVector audio_tracks = stream->GetAudioTracks();
569 for (size_t i = 0; i < audio_tracks.size(); ++i) {
570 AudioTrackInterface* track = audio_tracks[i];
571 ScopedLocalRef<jstring> id(
572 jni(), JavaStringFromStdString(jni(), track->id()));
573 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000574 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000576 jfieldID audio_tracks_id = GetFieldID(jni(),
577 *j_media_stream_class_,
578 "audioTracks",
579 "Ljava/util/LinkedList;");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 ScopedLocalRef<jobject> audio_tracks(jni(), GetObjectField(
581 jni(), *j_stream, audio_tracks_id));
582 jmethodID add = GetMethodID(jni(),
583 GetObjectClass(jni(), *audio_tracks), "add", "(Ljava/lang/Object;)Z");
584 jboolean added = jni()->CallBooleanMethod(*audio_tracks, add, *j_track);
585 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
586 CHECK(added, "");
587 }
588
589 VideoTrackVector video_tracks = stream->GetVideoTracks();
590 for (size_t i = 0; i < video_tracks.size(); ++i) {
591 VideoTrackInterface* track = video_tracks[i];
592 ScopedLocalRef<jstring> id(
593 jni(), JavaStringFromStdString(jni(), track->id()));
594 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000595 *j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000597 jfieldID video_tracks_id = GetFieldID(jni(),
598 *j_media_stream_class_,
599 "videoTracks",
600 "Ljava/util/LinkedList;");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 ScopedLocalRef<jobject> video_tracks(jni(), GetObjectField(
602 jni(), *j_stream, video_tracks_id));
603 jmethodID add = GetMethodID(jni(),
604 GetObjectClass(jni(), *video_tracks), "add", "(Ljava/lang/Object;)Z");
605 jboolean added = jni()->CallBooleanMethod(*video_tracks, add, *j_track);
606 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
607 CHECK(added, "");
608 }
609 streams_[stream] = jni()->NewWeakGlobalRef(*j_stream);
610 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
611
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000612 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
613 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 jni()->CallVoidMethod(*j_observer_global_, m, *j_stream);
615 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
616 }
617
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000618 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
620 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
621
622 WeakRef s(jni(), it->second);
623 streams_.erase(it);
624 if (!s.obj())
625 return;
626
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000627 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
628 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
630 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
631 }
632
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000633 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
634 ScopedLocalRef<jobject> j_channel(jni(), jni()->NewObject(
635 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel));
636 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000637
638 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
639 "(Lorg/webrtc/DataChannel;)V");
640 jni()->CallVoidMethod(*j_observer_global_, m, *j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000641
642 // Channel is now owned by Java object, and will be freed from
643 // DataChannel.dispose(). Important that this be done _after_ the
644 // CallVoidMethod above as Java code might call back into native code and be
645 // surprised to see a refcount of 2.
646 int bumped_count = channel->AddRef();
647 CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
648
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000649 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
650 }
651
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 void SetConstraints(ConstraintsWrapper* constraints) {
653 CHECK(!constraints_.get(), "constraints already set!");
654 constraints_.reset(constraints);
655 }
656
657 const ConstraintsWrapper* constraints() { return constraints_.get(); }
658
659 private:
660 JNIEnv* jni() {
661 return AttachCurrentThreadIfNeeded();
662 }
663
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000664 const ScopedGlobalRef<jobject> j_observer_global_;
665 const ScopedGlobalRef<jclass> j_observer_class_;
666 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000668 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000670 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000672 const ScopedGlobalRef<jclass> j_data_channel_class_;
673 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000674 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
675 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
676 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
677};
678
679// Wrapper for a Java MediaConstraints object. Copies all needed data so when
680// the constructor returns the Java object is no longer needed.
681class ConstraintsWrapper : public MediaConstraintsInterface {
682 public:
683 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
684 PopulateConstraintsFromJavaPairList(
685 jni, j_constraints, "mandatory", &mandatory_);
686 PopulateConstraintsFromJavaPairList(
687 jni, j_constraints, "optional", &optional_);
688 }
689
690 virtual ~ConstraintsWrapper() {}
691
692 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000693 virtual const Constraints& GetMandatory() const OVERRIDE {
694 return mandatory_;
695 }
696
697 virtual const Constraints& GetOptional() const OVERRIDE {
698 return optional_;
699 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700
701 private:
702 // Helper for translating a List<Pair<String, String>> to a Constraints.
703 static void PopulateConstraintsFromJavaPairList(
704 JNIEnv* jni, jobject j_constraints,
705 const char* field_name, Constraints* field) {
706 jfieldID j_id = GetFieldID(jni,
707 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
708 jobject j_list = GetObjectField(jni, j_constraints, j_id);
709 jmethodID j_iterator_id = GetMethodID(jni,
710 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
711 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
712 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
713 jmethodID j_has_next = GetMethodID(jni,
714 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
715 jmethodID j_next = GetMethodID(jni,
716 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
717 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
718 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
719 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
720 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
721 jmethodID get_key = GetMethodID(jni,
722 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
723 jstring j_key = reinterpret_cast<jstring>(
724 jni->CallObjectMethod(entry, get_key));
725 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
726 jmethodID get_value = GetMethodID(jni,
727 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
728 jstring j_value = reinterpret_cast<jstring>(
729 jni->CallObjectMethod(entry, get_value));
730 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
731 field->push_back(Constraint(JavaToStdString(jni, j_key),
732 JavaToStdString(jni, j_value)));
733 }
734 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
735 }
736
737 Constraints mandatory_;
738 Constraints optional_;
739};
740
741static jobject JavaSdpFromNativeSdp(
742 JNIEnv* jni, const SessionDescriptionInterface* desc) {
743 std::string sdp;
744 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
745 ScopedLocalRef<jstring> j_description(jni, JavaStringFromStdString(jni, sdp));
746
747 jclass j_type_class = FindClass(
748 jni, "org/webrtc/SessionDescription$Type");
749 jmethodID j_type_from_canonical = GetStaticMethodID(
750 jni, j_type_class, "fromCanonicalForm",
751 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
752 ScopedLocalRef<jstring> j_type_string(
753 jni, JavaStringFromStdString(jni, desc->type()));
754 jobject j_type = jni->CallStaticObjectMethod(
755 j_type_class, j_type_from_canonical, *j_type_string);
756 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
757
758 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
759 jmethodID j_sdp_ctor = GetMethodID(
760 jni, j_sdp_class, "<init>",
761 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
762 jobject j_sdp = jni->NewObject(
763 j_sdp_class, j_sdp_ctor, j_type, *j_description);
764 CHECK_EXCEPTION(jni, "error during NewObject");
765 return j_sdp;
766}
767
768template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
769class SdpObserverWrapper : public T {
770 public:
771 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
772 ConstraintsWrapper* constraints)
773 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000774 j_observer_global_(jni, j_observer),
775 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000776 }
777
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000778 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000780 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781 virtual void OnSuccess() {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000782 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
783 jni()->CallVoidMethod(*j_observer_global_, m);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
785 }
786
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000787 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000788 virtual void OnSuccess(SessionDescriptionInterface* desc) {
789 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000790 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 "(Lorg/webrtc/SessionDescription;)V");
792 ScopedLocalRef<jobject> j_sdp(jni(), JavaSdpFromNativeSdp(jni(), desc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000793 jni()->CallVoidMethod(*j_observer_global_, m, *j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
795 }
796
797 protected:
798 // Common implementation for failure of Set & Create types, distinguished by
799 // |op| being "Set" or "Create".
800 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000801 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
802 "(Ljava/lang/String;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803 ScopedLocalRef<jstring> j_error_string(
804 jni(), JavaStringFromStdString(jni(), error));
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000805 jni()->CallVoidMethod(*j_observer_global_, m, *j_error_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
807 }
808
809 private:
810 JNIEnv* jni() {
811 return AttachCurrentThreadIfNeeded();
812 }
813
814 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000815 const ScopedGlobalRef<jobject> j_observer_global_;
816 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817};
818
819class CreateSdpObserverWrapper
820 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
821 public:
822 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
823 ConstraintsWrapper* constraints)
824 : SdpObserverWrapper(jni, j_observer, constraints) {}
825
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000826 virtual void OnFailure(const std::string& error) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 SdpObserverWrapper::OnFailure(std::string("Create"), error);
828 }
829};
830
831class SetSdpObserverWrapper
832 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
833 public:
834 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
835 ConstraintsWrapper* constraints)
836 : SdpObserverWrapper(jni, j_observer, constraints) {}
837
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000838 virtual void OnFailure(const std::string& error) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839 SdpObserverWrapper::OnFailure(std::string("Set"), error);
840 }
841};
842
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000843// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
844// and dispatching the callback from C++ back to Java.
845class DataChannelObserverWrapper : public DataChannelObserver {
846 public:
847 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
848 : j_observer_global_(jni, j_observer),
849 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
850 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
851 "onStateChange", "()V")),
852 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
853 "(Lorg/webrtc/DataChannel$Buffer;)V")),
854 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
855 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
856 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
857 }
858
859 virtual ~DataChannelObserverWrapper() {}
860
861 virtual void OnStateChange() OVERRIDE {
862 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
863 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
864 }
865
866 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
867 jobject byte_buffer =
868 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
869 buffer.data.length());
870 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
871 byte_buffer, buffer.binary);
872 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
873 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
874 }
875
876 private:
877 JNIEnv* jni() {
878 return AttachCurrentThreadIfNeeded();
879 }
880
881 const ScopedGlobalRef<jobject> j_observer_global_;
882 const ScopedGlobalRef<jclass> j_observer_class_;
883 const ScopedGlobalRef<jclass> j_buffer_class_;
884 const jmethodID j_on_state_change_mid_;
885 const jmethodID j_on_message_mid_;
886 const jmethodID j_buffer_ctor_;
887};
888
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000889// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
890// dispatching the callback from C++ back to Java.
891class StatsObserverWrapper : public StatsObserver {
892 public:
893 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000894 : j_observer_global_(jni, j_observer),
895 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
896 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000898 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 "(Ljava/lang/String;Ljava/lang/String;D"
900 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000901 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 jni, "org/webrtc/StatsReport$Value")),
903 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000904 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 "(Ljava/lang/String;Ljava/lang/String;)V")) {
906 }
907
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000908 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000910 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 ScopedLocalRef<jobjectArray> j_reports(jni(),
912 ReportsToJava(jni(), reports));
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000913 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
914 "([Lorg/webrtc/StatsReport;)V");
915 jni()->CallVoidMethod(*j_observer_global_, m, *j_reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
917 }
918
919 private:
920 jobjectArray ReportsToJava(
921 JNIEnv* jni, const std::vector<StatsReport>& reports) {
922 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000923 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000924 for (int i = 0; i < reports.size(); ++i) {
925 const StatsReport& report = reports[i];
926 ScopedLocalRef<jstring> j_id(
927 jni, JavaStringFromStdString(jni, report.id));
928 ScopedLocalRef<jstring> j_type(
929 jni, JavaStringFromStdString(jni, report.type));
930 ScopedLocalRef<jobjectArray> j_values(
931 jni, ValuesToJava(jni, report.values));
932 ScopedLocalRef<jobject> j_report(jni, jni->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000933 *j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934 report.timestamp, *j_values));
935 jni->SetObjectArrayElement(reports_array, i, *j_report);
936 }
937 return reports_array;
938 }
939
940 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
941 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000942 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000943 for (int i = 0; i < values.size(); ++i) {
944 const StatsReport::Value& value = values[i];
945 ScopedLocalRef<jstring> j_name(
946 jni, JavaStringFromStdString(jni, value.name));
947 ScopedLocalRef<jstring> j_value(
948 jni, JavaStringFromStdString(jni, value.value));
949 ScopedLocalRef<jobject> j_element_value(jni, jni->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000950 *j_value_class_, j_value_ctor_, *j_name, *j_value));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951 jni->SetObjectArrayElement(j_values, i, *j_element_value);
952 }
953 return j_values;
954 }
955
956 JNIEnv* jni() {
957 return AttachCurrentThreadIfNeeded();
958 }
959
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000960 const ScopedGlobalRef<jobject> j_observer_global_;
961 const ScopedGlobalRef<jclass> j_observer_class_;
962 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000963 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000964 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965 const jmethodID j_value_ctor_;
966};
967
968// Adapter presenting a cricket::VideoRenderer as a
969// webrtc::VideoRendererInterface.
970class VideoRendererWrapper : public VideoRendererInterface {
971 public:
972 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
973 if (renderer)
974 return new VideoRendererWrapper(renderer);
975 return NULL;
976 }
977
978 virtual ~VideoRendererWrapper() {}
979
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000980 virtual void SetSize(int width, int height) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981 const bool kNotReserved = false; // What does this param mean??
982 renderer_->SetSize(width, height, kNotReserved);
983 }
984
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000985 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 renderer_->RenderFrame(frame);
987 }
988
989 private:
990 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
991 : renderer_(renderer) {}
992
993 talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
994};
995
996// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
997// instance.
998class JavaVideoRendererWrapper : public VideoRendererInterface {
999 public:
1000 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001001 : j_callbacks_(jni, j_callbacks),
1002 j_set_size_id_(GetMethodID(
1003 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1004 j_render_frame_id_(GetMethodID(
1005 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1006 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1007 j_frame_class_(jni,
1008 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1009 j_frame_ctor_id_(GetMethodID(
1010 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1011 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001012 CHECK_EXCEPTION(jni, "");
1013 }
1014
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001015 virtual ~JavaVideoRendererWrapper() {}
1016
1017 virtual void SetSize(int width, int height) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1019 CHECK_EXCEPTION(jni(), "");
1020 }
1021
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001022 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001023 ScopedLocalRef<jobject> j_frame(jni(), CricketToJavaFrame(frame));
1024 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, *j_frame);
1025 CHECK_EXCEPTION(jni(), "");
1026 }
1027
1028 private:
1029 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1030 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
1031 ScopedLocalRef<jintArray> strides(jni(), jni()->NewIntArray(3));
1032 jint* strides_array = jni()->GetIntArrayElements(*strides, NULL);
1033 strides_array[0] = frame->GetYPitch();
1034 strides_array[1] = frame->GetUPitch();
1035 strides_array[2] = frame->GetVPitch();
1036 jni()->ReleaseIntArrayElements(*strides, strides_array, 0);
1037 ScopedLocalRef<jobjectArray> planes(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001038 jni(), jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 ScopedLocalRef<jobject> y_buffer(jni(), jni()->NewDirectByteBuffer(
1040 const_cast<uint8*>(frame->GetYPlane()),
1041 frame->GetYPitch() * frame->GetHeight()));
1042 ScopedLocalRef<jobject> u_buffer(jni(), jni()->NewDirectByteBuffer(
1043 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize()));
1044 ScopedLocalRef<jobject> v_buffer(jni(), jni()->NewDirectByteBuffer(
1045 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize()));
1046 jni()->SetObjectArrayElement(*planes, 0, *y_buffer);
1047 jni()->SetObjectArrayElement(*planes, 1, *u_buffer);
1048 jni()->SetObjectArrayElement(*planes, 2, *v_buffer);
1049 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001050 *j_frame_class_, j_frame_ctor_id_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051 frame->GetWidth(), frame->GetHeight(), *strides, *planes);
1052 }
1053
1054 JNIEnv* jni() {
1055 return AttachCurrentThreadIfNeeded();
1056 }
1057
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001058 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059 jmethodID j_set_size_id_;
1060 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001061 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001063 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064};
1065
1066} // anonymous namespace
1067
1068
1069// Convenience macro defining JNI-accessible methods in the org.webrtc package.
1070// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1071#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1072 Java_org_webrtc_##name
1073
1074extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1075 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1076 g_jvm = jvm;
1077 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1078
1079 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1080
1081 JNIEnv* jni;
1082 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1083 return -1;
1084 g_class_reference_holder = new ClassReferenceHolder(jni);
1085
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001086 return JNI_VERSION_1_6;
1087}
1088
1089extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090 delete g_class_reference_holder;
1091 g_class_reference_holder = NULL;
1092 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
1093}
1094
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001095static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001096 jfieldID native_dc_id = GetFieldID(jni,
1097 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1098 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001099 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001100}
1101
1102JOW(jlong, DataChannel_registerObserverNative)(
1103 JNIEnv* jni, jobject j_dc, jobject j_observer) {
1104 talk_base::scoped_ptr<DataChannelObserverWrapper> observer(
1105 new DataChannelObserverWrapper(jni, j_observer));
1106 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
1107 return reinterpret_cast<jlong>(observer.release());
1108}
1109
1110JOW(void, DataChannel_unregisterObserverNative)(
1111 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1112 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1113 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1114}
1115
1116JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1117 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1118}
1119
1120JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1121 return JavaEnumFromIndex(
1122 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1123}
1124
1125JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1126 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1127 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1128 "buffered_amount overflowed jlong!");
1129 return static_cast<jlong>(buffered_amount);
1130}
1131
1132JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1133 ExtractNativeDC(jni, j_dc)->Close();
1134}
1135
1136JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1137 jbyteArray data, jboolean binary) {
1138 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1139 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1140 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1141 binary));
1142 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1143 return ret;
1144}
1145
1146JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001147 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001148}
1149
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001150JOW(void, Logging_nativeEnableTracing)(
1151 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1152 jint nativeSeverity) {
1153 std::string path = JavaToStdString(jni, j_path);
1154 if (nativeLevels != webrtc::kTraceNone) {
1155 CHECK(!webrtc::Trace::SetTraceFile(path.c_str(), false),
1156 "SetTraceFile failed");
andrew@webrtc.org90805182013-09-05 16:40:43 +00001157 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001158 }
1159 talk_base::LogMessage::LogToDebug(nativeSeverity);
1160}
1161
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001162JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001163 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001164}
1165
1166JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1167 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1168 delete p;
1169}
1170
1171JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001172 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173}
1174
1175JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1176 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1177}
1178
1179JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1180 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1181}
1182
1183JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001184 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001185}
1186
1187JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1188 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001189 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191}
1192
1193JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1194 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001195 return reinterpret_cast<MediaStreamInterface*>(pointer)
1196 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197}
1198
1199JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1200 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001201 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203}
1204
1205JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1206 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001207 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001208 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001209}
1210
1211JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1212 return JavaStringFromStdString(
1213 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1214}
1215
1216JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001217 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218}
1219
1220JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1221 JNIEnv * jni, jclass, jobject j_observer) {
1222 return (jlong)new PCOJava(jni, j_observer);
1223}
1224
1225#ifdef ANDROID
1226JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1227 JNIEnv* jni, jclass, jobject context) {
1228 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1229 bool failure = false;
1230 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
1231 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1232 return !failure;
1233}
1234#endif // ANDROID
1235
1236JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1237 JNIEnv* jni, jclass) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001238 webrtc::Trace::CreateTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1240 webrtc::CreatePeerConnectionFactory());
1241 return (jlong)factory.release();
1242}
1243
1244JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001245 CHECK_RELEASE(reinterpret_cast<PeerConnectionFactoryInterface*>(j_p));
1246 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247}
1248
1249JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1250 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1251 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1252 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1253 talk_base::scoped_refptr<MediaStreamInterface> stream(
1254 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1255 return (jlong)stream.release();
1256}
1257
1258JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1259 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1260 jobject j_constraints) {
1261 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1262 new ConstraintsWrapper(jni, j_constraints));
1263 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1264 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1265 talk_base::scoped_refptr<VideoSourceInterface> source(
1266 factory->CreateVideoSource(
1267 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1268 constraints.get()));
1269 return (jlong)source.release();
1270}
1271
1272JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1273 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1274 jlong native_source) {
1275 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1276 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1277 talk_base::scoped_refptr<VideoTrackInterface> track(
1278 factory->CreateVideoTrack(
1279 JavaToStdString(jni, id),
1280 reinterpret_cast<VideoSourceInterface*>(native_source)));
1281 return (jlong)track.release();
1282}
1283
1284JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1285 JNIEnv* jni, jclass, jlong native_factory, jstring id) {
1286 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1287 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1288 talk_base::scoped_refptr<AudioTrackInterface> track(
1289 factory->CreateAudioTrack(JavaToStdString(jni, id), NULL));
1290 return (jlong)track.release();
1291}
1292
1293static void JavaIceServersToJsepIceServers(
1294 JNIEnv* jni, jobject j_ice_servers,
1295 PeerConnectionInterface::IceServers* ice_servers) {
1296 jclass list_class = GetObjectClass(jni, j_ice_servers);
1297 jmethodID iterator_id = GetMethodID(
1298 jni, list_class, "iterator", "()Ljava/util/Iterator;");
1299 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
1300 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1301 jmethodID iterator_has_next = GetMethodID(
1302 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
1303 jmethodID iterator_next = GetMethodID(
1304 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
1305 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
1306 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1307 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
1308 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1309 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
1310 jfieldID j_ice_server_uri_id =
1311 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
1312 jfieldID j_ice_server_username_id =
1313 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
1314 jfieldID j_ice_server_password_id =
1315 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
1316 jstring uri = reinterpret_cast<jstring>(
1317 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
1318 jstring username = reinterpret_cast<jstring>(
1319 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
1320 jstring password = reinterpret_cast<jstring>(
1321 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
1322 PeerConnectionInterface::IceServer server;
1323 server.uri = JavaToStdString(jni, uri);
1324 server.username = JavaToStdString(jni, username);
1325 server.password = JavaToStdString(jni, password);
1326 ice_servers->push_back(server);
1327 }
1328 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1329}
1330
1331JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
1332 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
1333 jobject j_constraints, jlong observer_p) {
1334 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
1335 reinterpret_cast<PeerConnectionFactoryInterface*>(factory));
1336 PeerConnectionInterface::IceServers servers;
1337 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
1338 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
1339 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
1340 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
1341 servers, observer->constraints(), NULL, observer));
1342 return (jlong)pc.release();
1343}
1344
1345static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
1346 JNIEnv* jni, jobject j_pc) {
1347 jfieldID native_pc_id = GetFieldID(jni,
1348 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
1349 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
1350 return talk_base::scoped_refptr<PeerConnectionInterface>(
1351 reinterpret_cast<PeerConnectionInterface*>(j_p));
1352}
1353
1354JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
1355 const SessionDescriptionInterface* sdp =
1356 ExtractNativePC(jni, j_pc)->local_description();
1357 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1358}
1359
1360JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
1361 const SessionDescriptionInterface* sdp =
1362 ExtractNativePC(jni, j_pc)->remote_description();
1363 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1364}
1365
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001366JOW(jobject, PeerConnection_createDataChannel)(
1367 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
1368 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
1369 talk_base::scoped_refptr<DataChannelInterface> channel(
1370 ExtractNativePC(jni, j_pc)->CreateDataChannel(
1371 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00001372 // Mustn't pass channel.get() directly through NewObject to avoid reading its
1373 // vararg parameter as 64-bit and reading memory that doesn't belong to the
1374 // 32-bit parameter.
1375 jlong nativeChannelPtr = jlongFromPointer(channel.get());
1376 CHECK(nativeChannelPtr, "Failed to create DataChannel");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001377 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
1378 jmethodID j_data_channel_ctor = GetMethodID(
1379 jni, j_data_channel_class, "<init>", "(J)V");
1380 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00001381 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001382 CHECK_EXCEPTION(jni, "error during NewObject");
1383 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001384 int bumped_count = channel->AddRef();
1385 CHECK(bumped_count == 2, "Unexpected refcount");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001386 return j_channel;
1387}
1388
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001389JOW(void, PeerConnection_createOffer)(
1390 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1391 ConstraintsWrapper* constraints =
1392 new ConstraintsWrapper(jni, j_constraints);
1393 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1394 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1395 jni, j_observer, constraints));
1396 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
1397}
1398
1399JOW(void, PeerConnection_createAnswer)(
1400 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1401 ConstraintsWrapper* constraints =
1402 new ConstraintsWrapper(jni, j_constraints);
1403 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1404 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1405 jni, j_observer, constraints));
1406 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
1407}
1408
1409// Helper to create a SessionDescriptionInterface from a SessionDescription.
1410static SessionDescriptionInterface* JavaSdpToNativeSdp(
1411 JNIEnv* jni, jobject j_sdp) {
1412 jfieldID j_type_id = GetFieldID(
1413 jni, GetObjectClass(jni, j_sdp), "type",
1414 "Lorg/webrtc/SessionDescription$Type;");
1415 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
1416 jmethodID j_canonical_form_id = GetMethodID(
1417 jni, GetObjectClass(jni, j_type), "canonicalForm",
1418 "()Ljava/lang/String;");
1419 jstring j_type_string = (jstring)jni->CallObjectMethod(
1420 j_type, j_canonical_form_id);
1421 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1422 std::string std_type = JavaToStdString(jni, j_type_string);
1423
1424 jfieldID j_description_id = GetFieldID(
1425 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
1426 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
1427 std::string std_description = JavaToStdString(jni, j_description);
1428
1429 return webrtc::CreateSessionDescription(
1430 std_type, std_description, NULL);
1431}
1432
1433JOW(void, PeerConnection_setLocalDescription)(
1434 JNIEnv* jni, jobject j_pc,
1435 jobject j_observer, jobject j_sdp) {
1436 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1437 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1438 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1439 ExtractNativePC(jni, j_pc)->SetLocalDescription(
1440 observer, JavaSdpToNativeSdp(jni, j_sdp));
1441}
1442
1443JOW(void, PeerConnection_setRemoteDescription)(
1444 JNIEnv* jni, jobject j_pc,
1445 jobject j_observer, jobject j_sdp) {
1446 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1447 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1448 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1449 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
1450 observer, JavaSdpToNativeSdp(jni, j_sdp));
1451}
1452
1453JOW(jboolean, PeerConnection_updateIce)(
1454 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
1455 PeerConnectionInterface::IceServers ice_servers;
1456 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
1457 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1458 new ConstraintsWrapper(jni, j_constraints));
1459 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
1460}
1461
1462JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
1463 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
1464 jint j_sdp_mline_index, jstring j_candidate_sdp) {
1465 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
1466 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
1467 talk_base::scoped_ptr<IceCandidateInterface> candidate(
1468 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
1469 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
1470}
1471
1472JOW(jboolean, PeerConnection_nativeAddLocalStream)(
1473 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
1474 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1475 new ConstraintsWrapper(jni, j_constraints));
1476 return ExtractNativePC(jni, j_pc)->AddStream(
1477 reinterpret_cast<MediaStreamInterface*>(native_stream),
1478 constraints.get());
1479}
1480
1481JOW(void, PeerConnection_nativeRemoveLocalStream)(
1482 JNIEnv* jni, jobject j_pc, jlong native_stream) {
1483 ExtractNativePC(jni, j_pc)->RemoveStream(
1484 reinterpret_cast<MediaStreamInterface*>(native_stream));
1485}
1486
1487JOW(bool, PeerConnection_nativeGetStats)(
1488 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
1489 talk_base::scoped_refptr<StatsObserverWrapper> observer(
1490 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
1491 return ExtractNativePC(jni, j_pc)->GetStats(
1492 observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
1493}
1494
1495JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
1496 PeerConnectionInterface::SignalingState state =
1497 ExtractNativePC(jni, j_pc)->signaling_state();
1498 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
1499}
1500
1501JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
1502 PeerConnectionInterface::IceConnectionState state =
1503 ExtractNativePC(jni, j_pc)->ice_connection_state();
1504 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
1505}
1506
1507JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
1508 PeerConnectionInterface::IceGatheringState state =
1509 ExtractNativePC(jni, j_pc)->ice_gathering_state();
1510 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
1511}
1512
1513JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1514 ExtractNativePC(jni, j_pc)->Close();
1515 return;
1516}
1517
1518JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1519 talk_base::scoped_refptr<MediaSourceInterface> p(
1520 reinterpret_cast<MediaSourceInterface*>(j_p));
1521 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
1522}
1523
1524JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
1525 JNIEnv* jni, jclass, jstring j_device_name) {
1526 std::string device_name = JavaToStdString(jni, j_device_name);
1527 talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
1528 cricket::DeviceManagerFactory::Create());
1529 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
1530 cricket::Device device;
1531 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
1532 LOG(LS_ERROR) << "GetVideoCaptureDevice failed";
1533 return 0;
1534 }
1535 talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1536 device_manager->CreateVideoCapturer(device));
1537 return (jlong)capturer.release();
1538}
1539
1540JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
1541 JNIEnv* jni, jclass, int x, int y) {
1542 talk_base::scoped_ptr<VideoRendererWrapper> renderer(
1543 VideoRendererWrapper::Create(
1544 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
1545 return (jlong)renderer.release();
1546}
1547
1548JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
1549 JNIEnv* jni, jclass, jobject j_callbacks) {
1550 talk_base::scoped_ptr<JavaVideoRendererWrapper> renderer(
1551 new JavaVideoRendererWrapper(jni, j_callbacks));
1552 return (jlong)renderer.release();
1553}
1554
1555JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001556 return JavaStringFromStdString(
1557 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001558}
1559
1560JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001561 return JavaStringFromStdString(
1562 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001563}
1564
1565JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001566 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001567}
1568
1569JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001570 return JavaEnumFromIndex(
1571 jni,
1572 "MediaStreamTrack$State",
1573 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001574}
1575
1576JOW(jboolean, MediaStreamTrack_nativeSetState)(
1577 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001578 MediaStreamTrackInterface::TrackState new_state =
1579 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001580 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1581 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001582}
1583
1584JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
1585 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001586 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1587 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001588}
1589
1590JOW(void, VideoTrack_nativeAddRenderer)(
1591 JNIEnv* jni, jclass,
1592 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001593 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001594 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1595}
1596
1597JOW(void, VideoTrack_nativeRemoveRenderer)(
1598 JNIEnv* jni, jclass,
1599 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001600 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001601 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1602}