blob: 9e005767b5a910b59b91947a738a64d3baa756ff [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>
fischman@webrtc.orgeb7def22013-12-09 21:34:30 +000064#include <unistd.h>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66#include "talk/app/webrtc/mediaconstraintsinterface.h"
67#include "talk/app/webrtc/peerconnectioninterface.h"
68#include "talk/app/webrtc/videosourceinterface.h"
69#include "talk/base/logging.h"
70#include "talk/base/ssladapter.h"
71#include "talk/media/base/videocapturer.h"
72#include "talk/media/base/videorenderer.h"
73#include "talk/media/devices/videorendererfactory.h"
74#include "talk/media/webrtc/webrtcvideocapturer.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000075#include "third_party/icu/source/common/unicode/unistr.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000076#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000077#include "webrtc/system_wrappers/interface/trace.h"
78#include "webrtc/video_engine/include/vie_base.h"
79#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000081#ifdef ANDROID
82#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
83using webrtc::LogcatTraceContext;
84#endif
85
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086using icu::UnicodeString;
87using webrtc::AudioSourceInterface;
88using webrtc::AudioTrackInterface;
89using webrtc::AudioTrackVector;
90using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +000091using webrtc::DataBuffer;
92using webrtc::DataChannelInit;
93using webrtc::DataChannelInterface;
94using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095using webrtc::IceCandidateInterface;
96using webrtc::MediaConstraintsInterface;
97using webrtc::MediaSourceInterface;
98using webrtc::MediaStreamInterface;
99using webrtc::MediaStreamTrackInterface;
100using webrtc::PeerConnectionFactoryInterface;
101using webrtc::PeerConnectionInterface;
102using webrtc::PeerConnectionObserver;
103using webrtc::SessionDescriptionInterface;
104using webrtc::SetSessionDescriptionObserver;
105using webrtc::StatsObserver;
106using webrtc::StatsReport;
107using webrtc::VideoRendererInterface;
108using webrtc::VideoSourceInterface;
109using webrtc::VideoTrackInterface;
110using webrtc::VideoTrackVector;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111
112// Abort the process if |x| is false, emitting |msg|.
113#define CHECK(x, msg) \
114 if (x) {} else { \
115 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
116 abort(); \
117 }
118// Abort the process if |jni| has a Java exception pending, emitting |msg|.
119#define CHECK_EXCEPTION(jni, msg) \
120 if (0) {} else { \
121 if (jni->ExceptionCheck()) { \
122 jni->ExceptionDescribe(); \
123 jni->ExceptionClear(); \
124 CHECK(0, msg); \
125 } \
126 }
127
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000128// Helper that calls ptr->Release() and logs a useful message if that didn't
129// actually delete *ptr because of extra refcounts.
130#define CHECK_RELEASE(ptr) \
131 do { \
132 int count = (ptr)->Release(); \
133 if (count != 0) { \
134 LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr) \
135 << ": " << count; \
136 } \
137 CHECK(!count, "Unexpected refcount"); \
138 } while (0)
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.orgf41f06b2013-12-11 21:07:18 +0000198// Return a |jlong| that will correctly convert back to |ptr|. This is needed
199// because the alternative (of silently passing a 32-bit pointer to a vararg
200// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000201static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000202 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000203 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000204 // Going through intptr_t to be obvious about the definedness of the
205 // conversion from pointer to integral type. intptr_t to jlong is a standard
206 // widening by the COMPILE_ASSERT above.
207 jlong ret = reinterpret_cast<intptr_t>(ptr);
208 assert(reinterpret_cast<void*>(ret) == ptr);
209 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000210}
211
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212// Android's FindClass() is trickier than usual because the app-specific
213// ClassLoader is not consulted when there is no app-specific frame on the
214// stack. Consequently, we only look up classes once in JNI_OnLoad.
215// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
216class ClassReferenceHolder {
217 public:
218 explicit ClassReferenceHolder(JNIEnv* jni) {
219 LoadClass(jni, "java/nio/ByteBuffer");
220 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000221 LoadClass(jni, "org/webrtc/DataChannel");
222 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
223 LoadClass(jni, "org/webrtc/DataChannel$Init");
224 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225 LoadClass(jni, "org/webrtc/IceCandidate");
226 LoadClass(jni, "org/webrtc/MediaSource$State");
227 LoadClass(jni, "org/webrtc/MediaStream");
228 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
229 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
230 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
231 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
232 LoadClass(jni, "org/webrtc/SessionDescription");
233 LoadClass(jni, "org/webrtc/SessionDescription$Type");
234 LoadClass(jni, "org/webrtc/StatsReport");
235 LoadClass(jni, "org/webrtc/StatsReport$Value");
236 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
237 LoadClass(jni, "org/webrtc/VideoTrack");
238 }
239
240 ~ClassReferenceHolder() {
241 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
242 }
243
244 void FreeReferences(JNIEnv* jni) {
245 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
246 it != classes_.end(); ++it) {
247 jni->DeleteGlobalRef(it->second);
248 }
249 classes_.clear();
250 }
251
252 jclass GetClass(const std::string& name) {
253 std::map<std::string, jclass>::iterator it = classes_.find(name);
254 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
255 return it->second;
256 }
257
258 private:
259 void LoadClass(JNIEnv* jni, const std::string& name) {
260 jclass localRef = jni->FindClass(name.c_str());
261 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
262 CHECK(localRef, name);
263 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
264 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
265 CHECK(globalRef, name);
266 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
267 CHECK(inserted, "Duplicate class name: " << name);
268 }
269
270 std::map<std::string, jclass> classes_;
271};
272
273// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
274static ClassReferenceHolder* g_class_reference_holder = NULL;
275
276// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
277// object/class/method/field is non-null.
278jmethodID GetMethodID(
279 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
280 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
281 CHECK_EXCEPTION(jni,
282 "error during GetMethodID: " << name << ", " << signature);
283 CHECK(m, name << ", " << signature);
284 return m;
285}
286
287jmethodID GetStaticMethodID(
288 JNIEnv* jni, jclass c, const char* name, const char* signature) {
289 jmethodID m = jni->GetStaticMethodID(c, name, signature);
290 CHECK_EXCEPTION(jni,
291 "error during GetStaticMethodID: "
292 << name << ", " << signature);
293 CHECK(m, name << ", " << signature);
294 return m;
295}
296
297jfieldID GetFieldID(
298 JNIEnv* jni, jclass c, const char* name, const char* signature) {
299 jfieldID f = jni->GetFieldID(c, name, signature);
300 CHECK_EXCEPTION(jni, "error during GetFieldID");
301 CHECK(f, name << ", " << signature);
302 return f;
303}
304
305jclass FindClass(JNIEnv* jni, const char* name) {
306 return g_class_reference_holder->GetClass(name);
307}
308
309jclass GetObjectClass(JNIEnv* jni, jobject object) {
310 jclass c = jni->GetObjectClass(object);
311 CHECK_EXCEPTION(jni, "error during GetObjectClass");
312 CHECK(c, "");
313 return c;
314}
315
316jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
317 jobject o = jni->GetObjectField(object, id);
318 CHECK_EXCEPTION(jni, "error during GetObjectField");
319 CHECK(o, "");
320 return o;
321}
322
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000323jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
324 return static_cast<jstring>(GetObjectField(jni, object, id));
325}
326
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000327jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
328 jlong l = jni->GetLongField(object, id);
329 CHECK_EXCEPTION(jni, "error during GetLongField");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000330 return l;
331}
332
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000333jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
334 jint i = jni->GetIntField(object, id);
335 CHECK_EXCEPTION(jni, "error during GetIntField");
336 return i;
337}
338
339bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
340 jboolean b = jni->GetBooleanField(object, id);
341 CHECK_EXCEPTION(jni, "error during GetBooleanField");
342 return b;
343}
344
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000345jobject NewGlobalRef(JNIEnv* jni, jobject o) {
346 jobject ret = jni->NewGlobalRef(o);
347 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
348 CHECK(ret, "");
349 return ret;
350}
351
352void DeleteGlobalRef(JNIEnv* jni, jobject o) {
353 jni->DeleteGlobalRef(o);
354 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
355}
356
357// Given a jweak reference, allocate a (strong) local reference scoped to the
358// lifetime of this object if the weak reference is still valid, or NULL
359// otherwise.
360class WeakRef {
361 public:
362 WeakRef(JNIEnv* jni, jweak ref)
363 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
364 CHECK_EXCEPTION(jni, "error during NewLocalRef");
365 }
366 ~WeakRef() {
367 if (obj_) {
368 jni_->DeleteLocalRef(obj_);
369 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
370 }
371 }
372 jobject obj() { return obj_; }
373
374 private:
375 JNIEnv* const jni_;
376 jobject const obj_;
377};
378
fischman@webrtc.org41776152014-01-09 00:31:17 +0000379// Scope Java local references to the lifetime of this object. Use in all C++
380// callbacks (i.e. entry points that don't originate in a Java callstack
381// through a "native" method call).
382class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000383 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000384 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
385 CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000387 ~ScopedLocalRefFrame() {
388 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000389 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000390
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391 private:
392 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393};
394
395// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000396template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000397class ScopedGlobalRef {
398 public:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000399 explicit ScopedGlobalRef(JNIEnv* jni, T obj)
400 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401 ~ScopedGlobalRef() {
402 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
403 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000404 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000405 return obj_;
406 }
407 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000408 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000409};
410
411// Return the (singleton) Java Enum object corresponding to |index|;
412// |state_class_fragment| is something like "MediaSource$State".
413jobject JavaEnumFromIndex(
414 JNIEnv* jni, const std::string& state_class_fragment, int index) {
415 std::string state_class_name = "org/webrtc/" + state_class_fragment;
416 jclass state_class = FindClass(jni, state_class_name.c_str());
417 jmethodID state_values_id = GetStaticMethodID(
418 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000419 jobjectArray state_values = static_cast<jobjectArray>(
420 jni->CallStaticObjectMethod(state_class, state_values_id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000422 jobject ret = jni->GetObjectArrayElement(state_values, index);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
424 return ret;
425}
426
427// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
428static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
429 UnicodeString ustr(UnicodeString::fromUTF8(native));
430 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
431 CHECK_EXCEPTION(jni, "error during NewString");
432 return jstr;
433}
434
435// Given a (UTF-16) jstring return a new UTF-8 native string.
436static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
437 const jchar* jchars = jni->GetStringChars(j_string, NULL);
438 CHECK_EXCEPTION(jni, "Error during GetStringChars");
439 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
440 CHECK_EXCEPTION(jni, "Error during GetStringLength");
441 jni->ReleaseStringChars(j_string, jchars);
442 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
443 std::string ret;
444 return ustr.toUTF8String(ret);
445}
446
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000447static DataChannelInit JavaDataChannelInitToNative(
448 JNIEnv* jni, jobject j_init) {
449 DataChannelInit init;
450
451 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
452 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
453 jfieldID max_retransmit_time_id =
454 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
455 jfieldID max_retransmits_id =
456 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
457 jfieldID protocol_id =
458 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
459 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
460 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
461
462 init.ordered = GetBooleanField(jni, j_init, ordered_id);
463 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
464 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
465 init.protocol = JavaToStdString(
466 jni, GetStringField(jni, j_init, protocol_id));
467 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
468 init.id = GetIntField(jni, j_init, id_id);
469
470 return init;
471}
472
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473class ConstraintsWrapper;
474
475// Adapter between the C++ PeerConnectionObserver interface and the Java
476// PeerConnection.Observer interface. Wraps an instance of the Java interface
477// and dispatches C++ callbacks to Java.
478class PCOJava : public PeerConnectionObserver {
479 public:
480 PCOJava(JNIEnv* jni, jobject j_observer)
481 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000482 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
483 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
484 j_media_stream_ctor_(GetMethodID(
485 jni, *j_media_stream_class_, "<init>", "(J)V")),
486 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000488 jni, *j_audio_track_class_, "<init>", "(J)V")),
489 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
490 j_video_track_ctor_(GetMethodID(
491 jni, *j_video_track_class_, "<init>", "(J)V")),
492 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
493 j_data_channel_ctor_(GetMethodID(
494 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000495 }
496
497 virtual ~PCOJava() {}
498
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000499 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000500 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 std::string sdp;
502 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
503 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
504 jmethodID ctor = GetMethodID(jni(), candidate_class,
505 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000506 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
507 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
508 jobject j_candidate = jni()->NewObject(
509 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000511 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000513 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
515 }
516
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000517 virtual void OnError() OVERRIDE {
518 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "(V)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 jni()->CallVoidMethod(*j_observer_global_, m);
520 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
521 }
522
523 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000524 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000525 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000527 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000529 jobject new_state_enum =
530 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
531 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
533 }
534
535 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000536 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000537 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000539 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000541 jobject new_state_enum = JavaEnumFromIndex(
542 jni(), "PeerConnection$IceConnectionState", new_state);
543 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
545 }
546
547 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000548 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000549 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000551 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000553 jobject new_state_enum = JavaEnumFromIndex(
554 jni(), "PeerConnection$IceGatheringState", new_state);
555 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
557 }
558
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000559 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000560 ScopedLocalRefFrame local_ref_frame(jni());
561 jobject j_stream = jni()->NewObject(
562 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 CHECK_EXCEPTION(jni(), "error during NewObject");
564
565 AudioTrackVector audio_tracks = stream->GetAudioTracks();
566 for (size_t i = 0; i < audio_tracks.size(); ++i) {
567 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000568 jstring id = JavaStringFromStdString(jni(), track->id());
569 jobject j_track = jni()->NewObject(
570 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000572 jfieldID audio_tracks_id = GetFieldID(jni(),
573 *j_media_stream_class_,
574 "audioTracks",
575 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000576 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000578 GetObjectClass(jni(), audio_tracks),
579 "add",
580 "(Ljava/lang/Object;)Z");
581 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
583 CHECK(added, "");
584 }
585
586 VideoTrackVector video_tracks = stream->GetVideoTracks();
587 for (size_t i = 0; i < video_tracks.size(); ++i) {
588 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000589 jstring id = JavaStringFromStdString(jni(), track->id());
590 jobject j_track = jni()->NewObject(
591 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000593 jfieldID video_tracks_id = GetFieldID(jni(),
594 *j_media_stream_class_,
595 "videoTracks",
596 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000597 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000599 GetObjectClass(jni(), video_tracks),
600 "add",
601 "(Ljava/lang/Object;)Z");
602 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
604 CHECK(added, "");
605 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000606 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
608
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000609 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
610 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000611 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
613 }
614
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000615 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000616 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
618 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
619
620 WeakRef s(jni(), it->second);
621 streams_.erase(it);
622 if (!s.obj())
623 return;
624
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000625 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
626 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
628 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
629 }
630
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000631 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000632 ScopedLocalRefFrame local_ref_frame(jni());
633 jobject j_channel = jni()->NewObject(
634 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000635 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000636
637 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
638 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000639 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000640
641 // Channel is now owned by Java object, and will be freed from
642 // DataChannel.dispose(). Important that this be done _after_ the
643 // CallVoidMethod above as Java code might call back into native code and be
644 // surprised to see a refcount of 2.
645 int bumped_count = channel->AddRef();
646 CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
647
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000648 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
649 }
650
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 void SetConstraints(ConstraintsWrapper* constraints) {
652 CHECK(!constraints_.get(), "constraints already set!");
653 constraints_.reset(constraints);
654 }
655
656 const ConstraintsWrapper* constraints() { return constraints_.get(); }
657
658 private:
659 JNIEnv* jni() {
660 return AttachCurrentThreadIfNeeded();
661 }
662
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000663 const ScopedGlobalRef<jobject> j_observer_global_;
664 const ScopedGlobalRef<jclass> j_observer_class_;
665 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000667 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000669 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000671 const ScopedGlobalRef<jclass> j_data_channel_class_;
672 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
674 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
675 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
676};
677
678// Wrapper for a Java MediaConstraints object. Copies all needed data so when
679// the constructor returns the Java object is no longer needed.
680class ConstraintsWrapper : public MediaConstraintsInterface {
681 public:
682 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
683 PopulateConstraintsFromJavaPairList(
684 jni, j_constraints, "mandatory", &mandatory_);
685 PopulateConstraintsFromJavaPairList(
686 jni, j_constraints, "optional", &optional_);
687 }
688
689 virtual ~ConstraintsWrapper() {}
690
691 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000692 virtual const Constraints& GetMandatory() const OVERRIDE {
693 return mandatory_;
694 }
695
696 virtual const Constraints& GetOptional() const OVERRIDE {
697 return optional_;
698 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699
700 private:
701 // Helper for translating a List<Pair<String, String>> to a Constraints.
702 static void PopulateConstraintsFromJavaPairList(
703 JNIEnv* jni, jobject j_constraints,
704 const char* field_name, Constraints* field) {
705 jfieldID j_id = GetFieldID(jni,
706 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
707 jobject j_list = GetObjectField(jni, j_constraints, j_id);
708 jmethodID j_iterator_id = GetMethodID(jni,
709 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
710 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
711 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
712 jmethodID j_has_next = GetMethodID(jni,
713 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
714 jmethodID j_next = GetMethodID(jni,
715 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
716 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
717 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
718 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
719 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
720 jmethodID get_key = GetMethodID(jni,
721 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
722 jstring j_key = reinterpret_cast<jstring>(
723 jni->CallObjectMethod(entry, get_key));
724 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
725 jmethodID get_value = GetMethodID(jni,
726 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
727 jstring j_value = reinterpret_cast<jstring>(
728 jni->CallObjectMethod(entry, get_value));
729 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
730 field->push_back(Constraint(JavaToStdString(jni, j_key),
731 JavaToStdString(jni, j_value)));
732 }
733 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
734 }
735
736 Constraints mandatory_;
737 Constraints optional_;
738};
739
740static jobject JavaSdpFromNativeSdp(
741 JNIEnv* jni, const SessionDescriptionInterface* desc) {
742 std::string sdp;
743 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
fischman@webrtc.org41776152014-01-09 00:31:17 +0000744 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745
746 jclass j_type_class = FindClass(
747 jni, "org/webrtc/SessionDescription$Type");
748 jmethodID j_type_from_canonical = GetStaticMethodID(
749 jni, j_type_class, "fromCanonicalForm",
750 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000751 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000753 j_type_class, j_type_from_canonical, j_type_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000754 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
755
756 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
757 jmethodID j_sdp_ctor = GetMethodID(
758 jni, j_sdp_class, "<init>",
759 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
760 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000761 j_sdp_class, j_sdp_ctor, j_type, j_description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000762 CHECK_EXCEPTION(jni, "error during NewObject");
763 return j_sdp;
764}
765
766template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
767class SdpObserverWrapper : public T {
768 public:
769 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
770 ConstraintsWrapper* constraints)
771 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000772 j_observer_global_(jni, j_observer),
773 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 }
775
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000776 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000778 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000780 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000781 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
782 jni()->CallVoidMethod(*j_observer_global_, m);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
784 }
785
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000786 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000788 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 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");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000792 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
793 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");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000803 jstring j_error_string = JavaStringFromStdString(jni(), error);
804 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
806 }
807
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 JNIEnv* jni() {
809 return AttachCurrentThreadIfNeeded();
810 }
811
fischman@webrtc.org41776152014-01-09 00:31:17 +0000812 private:
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000814 const ScopedGlobalRef<jobject> j_observer_global_;
815 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816};
817
818class CreateSdpObserverWrapper
819 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
820 public:
821 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
822 ConstraintsWrapper* constraints)
823 : SdpObserverWrapper(jni, j_observer, constraints) {}
824
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000825 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000826 ScopedLocalRefFrame local_ref_frame(jni());
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 {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000839 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 SdpObserverWrapper::OnFailure(std::string("Set"), error);
841 }
842};
843
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000844// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
845// and dispatching the callback from C++ back to Java.
846class DataChannelObserverWrapper : public DataChannelObserver {
847 public:
848 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
849 : j_observer_global_(jni, j_observer),
850 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
851 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
852 "onStateChange", "()V")),
853 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
854 "(Lorg/webrtc/DataChannel$Buffer;)V")),
855 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
856 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
857 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
858 }
859
860 virtual ~DataChannelObserverWrapper() {}
861
862 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000863 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000864 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
865 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
866 }
867
868 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000869 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000870 jobject byte_buffer =
871 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
872 buffer.data.length());
873 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
874 byte_buffer, buffer.binary);
875 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
876 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
877 }
878
879 private:
880 JNIEnv* jni() {
881 return AttachCurrentThreadIfNeeded();
882 }
883
884 const ScopedGlobalRef<jobject> j_observer_global_;
885 const ScopedGlobalRef<jclass> j_observer_class_;
886 const ScopedGlobalRef<jclass> j_buffer_class_;
887 const jmethodID j_on_state_change_mid_;
888 const jmethodID j_on_message_mid_;
889 const jmethodID j_buffer_ctor_;
890};
891
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
893// dispatching the callback from C++ back to Java.
894class StatsObserverWrapper : public StatsObserver {
895 public:
896 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000897 : j_observer_global_(jni, j_observer),
898 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
899 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000901 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 "(Ljava/lang/String;Ljava/lang/String;D"
903 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000904 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 jni, "org/webrtc/StatsReport$Value")),
906 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000907 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908 "(Ljava/lang/String;Ljava/lang/String;)V")) {
909 }
910
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000911 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000912
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000913 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000914 ScopedLocalRefFrame local_ref_frame(jni());
915 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000916 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
917 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000918 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000919 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
920 }
921
922 private:
923 jobjectArray ReportsToJava(
924 JNIEnv* jni, const std::vector<StatsReport>& reports) {
925 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000926 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000927 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000928 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000929 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000930 jstring j_id = JavaStringFromStdString(jni, report.id);
931 jstring j_type = JavaStringFromStdString(jni, report.type);
932 jobjectArray j_values = ValuesToJava(jni, report.values);
933 jobject j_report = jni->NewObject(*j_stats_report_class_,
934 j_stats_report_ctor_,
935 j_id,
936 j_type,
937 report.timestamp,
938 j_values);
939 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940 }
941 return reports_array;
942 }
943
944 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
945 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000946 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000948 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000950 jstring j_name = JavaStringFromStdString(jni, value.name);
951 jstring j_value = JavaStringFromStdString(jni, value.value);
952 jobject j_element_value =
953 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
954 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000955 }
956 return j_values;
957 }
958
959 JNIEnv* jni() {
960 return AttachCurrentThreadIfNeeded();
961 }
962
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000963 const ScopedGlobalRef<jobject> j_observer_global_;
964 const ScopedGlobalRef<jclass> j_observer_class_;
965 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000966 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000967 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000968 const jmethodID j_value_ctor_;
969};
970
971// Adapter presenting a cricket::VideoRenderer as a
972// webrtc::VideoRendererInterface.
973class VideoRendererWrapper : public VideoRendererInterface {
974 public:
975 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
976 if (renderer)
977 return new VideoRendererWrapper(renderer);
978 return NULL;
979 }
980
981 virtual ~VideoRendererWrapper() {}
982
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000983 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000984 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 const bool kNotReserved = false; // What does this param mean??
986 renderer_->SetSize(width, height, kNotReserved);
987 }
988
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000989 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000990 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000991 renderer_->RenderFrame(frame);
992 }
993
994 private:
995 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
996 : renderer_(renderer) {}
997
998 talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
999};
1000
1001// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1002// instance.
1003class JavaVideoRendererWrapper : public VideoRendererInterface {
1004 public:
1005 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001006 : j_callbacks_(jni, j_callbacks),
1007 j_set_size_id_(GetMethodID(
1008 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1009 j_render_frame_id_(GetMethodID(
1010 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1011 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1012 j_frame_class_(jni,
1013 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1014 j_frame_ctor_id_(GetMethodID(
1015 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1016 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001017 CHECK_EXCEPTION(jni, "");
1018 }
1019
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001020 virtual ~JavaVideoRendererWrapper() {}
1021
1022 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001023 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1025 CHECK_EXCEPTION(jni(), "");
1026 }
1027
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001028 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001029 ScopedLocalRefFrame local_ref_frame(jni());
1030 jobject j_frame = CricketToJavaFrame(frame);
1031 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001032 CHECK_EXCEPTION(jni(), "");
1033 }
1034
1035 private:
1036 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1037 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001038 jintArray strides = jni()->NewIntArray(3);
1039 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040 strides_array[0] = frame->GetYPitch();
1041 strides_array[1] = frame->GetUPitch();
1042 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001043 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1044 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1045 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001047 frame->GetYPitch() * frame->GetHeight());
1048 jobject u_buffer = jni()->NewDirectByteBuffer(
1049 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1050 jobject v_buffer = jni()->NewDirectByteBuffer(
1051 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1052 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1053 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1054 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001056 *j_frame_class_, j_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001057 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001058 }
1059
1060 JNIEnv* jni() {
1061 return AttachCurrentThreadIfNeeded();
1062 }
1063
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001064 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001065 jmethodID j_set_size_id_;
1066 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001067 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001069 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001070};
1071
1072} // anonymous namespace
1073
1074
1075// Convenience macro defining JNI-accessible methods in the org.webrtc package.
1076// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1077#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1078 Java_org_webrtc_##name
1079
1080extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1081 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1082 g_jvm = jvm;
1083 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1084
1085 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1086
1087 JNIEnv* jni;
1088 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1089 return -1;
1090 g_class_reference_holder = new ClassReferenceHolder(jni);
1091
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001092 return JNI_VERSION_1_6;
1093}
1094
1095extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001096 delete g_class_reference_holder;
1097 g_class_reference_holder = NULL;
1098 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
1099}
1100
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001101static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001102 jfieldID native_dc_id = GetFieldID(jni,
1103 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1104 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001105 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001106}
1107
1108JOW(jlong, DataChannel_registerObserverNative)(
1109 JNIEnv* jni, jobject j_dc, jobject j_observer) {
1110 talk_base::scoped_ptr<DataChannelObserverWrapper> observer(
1111 new DataChannelObserverWrapper(jni, j_observer));
1112 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00001113 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001114}
1115
1116JOW(void, DataChannel_unregisterObserverNative)(
1117 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1118 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1119 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1120}
1121
1122JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1123 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1124}
1125
1126JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1127 return JavaEnumFromIndex(
1128 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1129}
1130
1131JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1132 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1133 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1134 "buffered_amount overflowed jlong!");
1135 return static_cast<jlong>(buffered_amount);
1136}
1137
1138JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1139 ExtractNativeDC(jni, j_dc)->Close();
1140}
1141
1142JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1143 jbyteArray data, jboolean binary) {
1144 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1145 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1146 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1147 binary));
1148 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1149 return ret;
1150}
1151
1152JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001153 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001154}
1155
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001156JOW(void, Logging_nativeEnableTracing)(
1157 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1158 jint nativeSeverity) {
1159 std::string path = JavaToStdString(jni, j_path);
1160 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00001161 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00001162#ifdef ANDROID
1163 if (path != "logcat:") {
1164#endif
1165 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1166 "SetTraceFile failed");
1167#ifdef ANDROID
1168 } else {
1169 // Intentionally leak this to avoid needing to reason about its lifecycle.
1170 // It keeps no state and functions only as a dispatch point.
1171 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1172 }
1173#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001174 }
1175 talk_base::LogMessage::LogToDebug(nativeSeverity);
1176}
1177
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001179 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001180}
1181
1182JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1183 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1184 delete p;
1185}
1186
1187JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001188 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189}
1190
1191JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1192 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1193}
1194
1195JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1196 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1197}
1198
1199JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001200 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001201}
1202
1203JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1204 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001205 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207}
1208
1209JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1210 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001211 return reinterpret_cast<MediaStreamInterface*>(pointer)
1212 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001213}
1214
1215JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1216 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001217 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219}
1220
1221JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1222 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001223 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225}
1226
1227JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1228 return JavaStringFromStdString(
1229 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1230}
1231
1232JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001233 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001234}
1235
1236JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1237 JNIEnv * jni, jclass, jobject j_observer) {
1238 return (jlong)new PCOJava(jni, j_observer);
1239}
1240
1241#ifdef ANDROID
1242JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1243 JNIEnv* jni, jclass, jobject context) {
1244 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1245 bool failure = false;
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00001246 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001247 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1248 return !failure;
1249}
1250#endif // ANDROID
1251
1252JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1253 JNIEnv* jni, jclass) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001254 webrtc::Trace::CreateTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001255 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1256 webrtc::CreatePeerConnectionFactory());
1257 return (jlong)factory.release();
1258}
1259
1260JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001261 CHECK_RELEASE(reinterpret_cast<PeerConnectionFactoryInterface*>(j_p));
1262 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263}
1264
1265JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1266 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1267 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1268 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1269 talk_base::scoped_refptr<MediaStreamInterface> stream(
1270 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1271 return (jlong)stream.release();
1272}
1273
1274JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1275 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1276 jobject j_constraints) {
1277 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1278 new ConstraintsWrapper(jni, j_constraints));
1279 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1280 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1281 talk_base::scoped_refptr<VideoSourceInterface> source(
1282 factory->CreateVideoSource(
1283 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1284 constraints.get()));
1285 return (jlong)source.release();
1286}
1287
1288JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1289 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1290 jlong native_source) {
1291 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1292 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1293 talk_base::scoped_refptr<VideoTrackInterface> track(
1294 factory->CreateVideoTrack(
1295 JavaToStdString(jni, id),
1296 reinterpret_cast<VideoSourceInterface*>(native_source)));
1297 return (jlong)track.release();
1298}
1299
1300JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1301 JNIEnv* jni, jclass, jlong native_factory, jstring id) {
1302 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1303 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1304 talk_base::scoped_refptr<AudioTrackInterface> track(
1305 factory->CreateAudioTrack(JavaToStdString(jni, id), NULL));
1306 return (jlong)track.release();
1307}
1308
1309static void JavaIceServersToJsepIceServers(
1310 JNIEnv* jni, jobject j_ice_servers,
1311 PeerConnectionInterface::IceServers* ice_servers) {
1312 jclass list_class = GetObjectClass(jni, j_ice_servers);
1313 jmethodID iterator_id = GetMethodID(
1314 jni, list_class, "iterator", "()Ljava/util/Iterator;");
1315 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
1316 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1317 jmethodID iterator_has_next = GetMethodID(
1318 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
1319 jmethodID iterator_next = GetMethodID(
1320 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
1321 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
1322 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1323 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
1324 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1325 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
1326 jfieldID j_ice_server_uri_id =
1327 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
1328 jfieldID j_ice_server_username_id =
1329 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
1330 jfieldID j_ice_server_password_id =
1331 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
1332 jstring uri = reinterpret_cast<jstring>(
1333 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
1334 jstring username = reinterpret_cast<jstring>(
1335 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
1336 jstring password = reinterpret_cast<jstring>(
1337 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
1338 PeerConnectionInterface::IceServer server;
1339 server.uri = JavaToStdString(jni, uri);
1340 server.username = JavaToStdString(jni, username);
1341 server.password = JavaToStdString(jni, password);
1342 ice_servers->push_back(server);
1343 }
1344 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1345}
1346
1347JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
1348 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
1349 jobject j_constraints, jlong observer_p) {
1350 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
1351 reinterpret_cast<PeerConnectionFactoryInterface*>(factory));
1352 PeerConnectionInterface::IceServers servers;
1353 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
1354 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
1355 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
1356 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
1357 servers, observer->constraints(), NULL, observer));
1358 return (jlong)pc.release();
1359}
1360
1361static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
1362 JNIEnv* jni, jobject j_pc) {
1363 jfieldID native_pc_id = GetFieldID(jni,
1364 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
1365 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
1366 return talk_base::scoped_refptr<PeerConnectionInterface>(
1367 reinterpret_cast<PeerConnectionInterface*>(j_p));
1368}
1369
1370JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
1371 const SessionDescriptionInterface* sdp =
1372 ExtractNativePC(jni, j_pc)->local_description();
1373 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1374}
1375
1376JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
1377 const SessionDescriptionInterface* sdp =
1378 ExtractNativePC(jni, j_pc)->remote_description();
1379 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1380}
1381
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001382JOW(jobject, PeerConnection_createDataChannel)(
1383 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
1384 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
1385 talk_base::scoped_refptr<DataChannelInterface> channel(
1386 ExtractNativePC(jni, j_pc)->CreateDataChannel(
1387 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00001388 // Mustn't pass channel.get() directly through NewObject to avoid reading its
1389 // vararg parameter as 64-bit and reading memory that doesn't belong to the
1390 // 32-bit parameter.
1391 jlong nativeChannelPtr = jlongFromPointer(channel.get());
1392 CHECK(nativeChannelPtr, "Failed to create DataChannel");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001393 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
1394 jmethodID j_data_channel_ctor = GetMethodID(
1395 jni, j_data_channel_class, "<init>", "(J)V");
1396 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00001397 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001398 CHECK_EXCEPTION(jni, "error during NewObject");
1399 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001400 int bumped_count = channel->AddRef();
1401 CHECK(bumped_count == 2, "Unexpected refcount");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001402 return j_channel;
1403}
1404
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001405JOW(void, PeerConnection_createOffer)(
1406 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1407 ConstraintsWrapper* constraints =
1408 new ConstraintsWrapper(jni, j_constraints);
1409 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1410 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1411 jni, j_observer, constraints));
1412 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
1413}
1414
1415JOW(void, PeerConnection_createAnswer)(
1416 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1417 ConstraintsWrapper* constraints =
1418 new ConstraintsWrapper(jni, j_constraints);
1419 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1420 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1421 jni, j_observer, constraints));
1422 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
1423}
1424
1425// Helper to create a SessionDescriptionInterface from a SessionDescription.
1426static SessionDescriptionInterface* JavaSdpToNativeSdp(
1427 JNIEnv* jni, jobject j_sdp) {
1428 jfieldID j_type_id = GetFieldID(
1429 jni, GetObjectClass(jni, j_sdp), "type",
1430 "Lorg/webrtc/SessionDescription$Type;");
1431 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
1432 jmethodID j_canonical_form_id = GetMethodID(
1433 jni, GetObjectClass(jni, j_type), "canonicalForm",
1434 "()Ljava/lang/String;");
1435 jstring j_type_string = (jstring)jni->CallObjectMethod(
1436 j_type, j_canonical_form_id);
1437 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1438 std::string std_type = JavaToStdString(jni, j_type_string);
1439
1440 jfieldID j_description_id = GetFieldID(
1441 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
1442 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
1443 std::string std_description = JavaToStdString(jni, j_description);
1444
1445 return webrtc::CreateSessionDescription(
1446 std_type, std_description, NULL);
1447}
1448
1449JOW(void, PeerConnection_setLocalDescription)(
1450 JNIEnv* jni, jobject j_pc,
1451 jobject j_observer, jobject j_sdp) {
1452 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1453 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1454 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1455 ExtractNativePC(jni, j_pc)->SetLocalDescription(
1456 observer, JavaSdpToNativeSdp(jni, j_sdp));
1457}
1458
1459JOW(void, PeerConnection_setRemoteDescription)(
1460 JNIEnv* jni, jobject j_pc,
1461 jobject j_observer, jobject j_sdp) {
1462 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1463 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1464 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1465 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
1466 observer, JavaSdpToNativeSdp(jni, j_sdp));
1467}
1468
1469JOW(jboolean, PeerConnection_updateIce)(
1470 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
1471 PeerConnectionInterface::IceServers ice_servers;
1472 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
1473 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1474 new ConstraintsWrapper(jni, j_constraints));
1475 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
1476}
1477
1478JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
1479 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
1480 jint j_sdp_mline_index, jstring j_candidate_sdp) {
1481 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
1482 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
1483 talk_base::scoped_ptr<IceCandidateInterface> candidate(
1484 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
1485 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
1486}
1487
1488JOW(jboolean, PeerConnection_nativeAddLocalStream)(
1489 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
1490 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1491 new ConstraintsWrapper(jni, j_constraints));
1492 return ExtractNativePC(jni, j_pc)->AddStream(
1493 reinterpret_cast<MediaStreamInterface*>(native_stream),
1494 constraints.get());
1495}
1496
1497JOW(void, PeerConnection_nativeRemoveLocalStream)(
1498 JNIEnv* jni, jobject j_pc, jlong native_stream) {
1499 ExtractNativePC(jni, j_pc)->RemoveStream(
1500 reinterpret_cast<MediaStreamInterface*>(native_stream));
1501}
1502
1503JOW(bool, PeerConnection_nativeGetStats)(
1504 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
1505 talk_base::scoped_refptr<StatsObserverWrapper> observer(
1506 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
1507 return ExtractNativePC(jni, j_pc)->GetStats(
1508 observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
1509}
1510
1511JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
1512 PeerConnectionInterface::SignalingState state =
1513 ExtractNativePC(jni, j_pc)->signaling_state();
1514 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
1515}
1516
1517JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
1518 PeerConnectionInterface::IceConnectionState state =
1519 ExtractNativePC(jni, j_pc)->ice_connection_state();
1520 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
1521}
1522
1523JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
1524 PeerConnectionInterface::IceGatheringState state =
1525 ExtractNativePC(jni, j_pc)->ice_gathering_state();
1526 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
1527}
1528
1529JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1530 ExtractNativePC(jni, j_pc)->Close();
1531 return;
1532}
1533
1534JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1535 talk_base::scoped_refptr<MediaSourceInterface> p(
1536 reinterpret_cast<MediaSourceInterface*>(j_p));
1537 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
1538}
1539
1540JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
1541 JNIEnv* jni, jclass, jstring j_device_name) {
1542 std::string device_name = JavaToStdString(jni, j_device_name);
1543 talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
1544 cricket::DeviceManagerFactory::Create());
1545 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
1546 cricket::Device device;
1547 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00001548 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001549 return 0;
1550 }
1551 talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1552 device_manager->CreateVideoCapturer(device));
1553 return (jlong)capturer.release();
1554}
1555
1556JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
1557 JNIEnv* jni, jclass, int x, int y) {
1558 talk_base::scoped_ptr<VideoRendererWrapper> renderer(
1559 VideoRendererWrapper::Create(
1560 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
1561 return (jlong)renderer.release();
1562}
1563
1564JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
1565 JNIEnv* jni, jclass, jobject j_callbacks) {
1566 talk_base::scoped_ptr<JavaVideoRendererWrapper> renderer(
1567 new JavaVideoRendererWrapper(jni, j_callbacks));
1568 return (jlong)renderer.release();
1569}
1570
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00001571JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
1572 cricket::VideoCapturer* capturer =
1573 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
1574 talk_base::scoped_ptr<cricket::VideoFormatPod> format(
1575 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
1576 capturer->Stop();
1577 return jlongFromPointer(format.release());
1578}
1579
1580JOW(void, VideoSource_restart)(
1581 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
1582 talk_base::scoped_ptr<cricket::VideoFormatPod> format(
1583 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
1584 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
1585 StartCapturing(cricket::VideoFormat(*format));
1586}
1587
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00001588JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00001589 JNIEnv* jni, jclass, jlong j_p) {
1590 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
1591}
1592
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001593JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001594 return JavaStringFromStdString(
1595 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001596}
1597
1598JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001599 return JavaStringFromStdString(
1600 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001601}
1602
1603JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001604 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001605}
1606
1607JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001608 return JavaEnumFromIndex(
1609 jni,
1610 "MediaStreamTrack$State",
1611 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001612}
1613
1614JOW(jboolean, MediaStreamTrack_nativeSetState)(
1615 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001616 MediaStreamTrackInterface::TrackState new_state =
1617 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001618 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1619 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620}
1621
1622JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
1623 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001624 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1625 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626}
1627
1628JOW(void, VideoTrack_nativeAddRenderer)(
1629 JNIEnv* jni, jclass,
1630 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001631 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001632 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1633}
1634
1635JOW(void, VideoTrack_nativeRemoveRenderer)(
1636 JNIEnv* jni, jclass,
1637 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001638 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001639 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1640}