3 * Copyright 2013, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
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
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)!
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).
57 #define JNIEXPORT __attribute__((visibility("default")))
59 #include <asm/unistd.h>
62 #include <sys/prctl.h>
63 #include <sys/syscall.h>
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"
75 #include "third_party/icu/source/common/unicode/unistr.h"
76 #include "webrtc/system_wrappers/interface/compile_assert.h"
77 #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"
82 #include "webrtc/system_wrappers/interface/logcat_trace_context.h"
83 using webrtc::LogcatTraceContext;
86 using icu::UnicodeString;
87 using webrtc::AudioSourceInterface;
88 using webrtc::AudioTrackInterface;
89 using webrtc::AudioTrackVector;
90 using webrtc::CreateSessionDescriptionObserver;
91 using webrtc::DataBuffer;
92 using webrtc::DataChannelInit;
93 using webrtc::DataChannelInterface;
94 using webrtc::DataChannelObserver;
95 using webrtc::IceCandidateInterface;
96 using webrtc::MediaConstraintsInterface;
97 using webrtc::MediaSourceInterface;
98 using webrtc::MediaStreamInterface;
99 using webrtc::MediaStreamTrackInterface;
100 using webrtc::PeerConnectionFactoryInterface;
101 using webrtc::PeerConnectionInterface;
102 using webrtc::PeerConnectionObserver;
103 using webrtc::SessionDescriptionInterface;
104 using webrtc::SetSessionDescriptionObserver;
105 using webrtc::StatsObserver;
106 using webrtc::StatsReport;
107 using webrtc::VideoRendererInterface;
108 using webrtc::VideoSourceInterface;
109 using webrtc::VideoTrackInterface;
110 using webrtc::VideoTrackVector;
112 // Abort the process if |x| is false, emitting |msg|.
113 #define CHECK(x, msg) \
115 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
118 // Abort the process if |jni| has a Java exception pending, emitting |msg|.
119 #define CHECK_EXCEPTION(jni, msg) \
121 if (jni->ExceptionCheck()) { \
122 jni->ExceptionDescribe(); \
123 jni->ExceptionClear(); \
128 // 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) \
132 int count = (ptr)->Release(); \
134 LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr) \
137 CHECK(!count, "Unexpected refcount"); \
142 static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
144 static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
145 static pthread_key_t g_jni_ptr; // Key for per-thread JNIEnv* data.
147 // Return thread ID as a string.
148 static 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);
155 // Return the current thread's name.
156 static std::string GetThreadName() {
158 CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
160 return std::string(name);
163 static void ThreadDestructor(void* unused) {
164 jint status = g_jvm->DetachCurrentThread();
165 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
168 static void CreateJNIPtrKey() {
169 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
170 "pthread_key_create");
173 // Deal with difference in signatures between Oracle's jni.h and Android's.
174 static JNIEnv* AttachCurrentThreadIfNeeded() {
175 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
177 JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
179 #ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
184 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
185 JavaVMAttachArgs args;
186 args.version = JNI_VERSION_1_6;
189 CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
191 CHECK(env, "AttachCurrentThread handed back NULL!");
192 jni = reinterpret_cast<JNIEnv*>(env);
193 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
198 // 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.
201 static jlong jlongFromPointer(void* ptr) {
202 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
203 Time_to_rethink_the_use_of_jlongs);
204 // 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);
212 // 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
216 class ClassReferenceHolder {
218 explicit ClassReferenceHolder(JNIEnv* jni) {
219 LoadClass(jni, "java/nio/ByteBuffer");
220 LoadClass(jni, "org/webrtc/AudioTrack");
221 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");
225 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");
240 ~ClassReferenceHolder() {
241 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
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);
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);
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);
270 std::map<std::string, jclass> classes_;
273 // Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
274 static ClassReferenceHolder* g_class_reference_holder = NULL;
276 // JNIEnv-helper methods that CHECK success: no Java exception thrown and found
277 // object/class/method/field is non-null.
278 jmethodID GetMethodID(
279 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
280 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
282 "error during GetMethodID: " << name << ", " << signature);
283 CHECK(m, name << ", " << signature);
287 jmethodID GetStaticMethodID(
288 JNIEnv* jni, jclass c, const char* name, const char* signature) {
289 jmethodID m = jni->GetStaticMethodID(c, name, signature);
291 "error during GetStaticMethodID: "
292 << name << ", " << signature);
293 CHECK(m, name << ", " << signature);
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);
305 jclass FindClass(JNIEnv* jni, const char* name) {
306 return g_class_reference_holder->GetClass(name);
309 jclass GetObjectClass(JNIEnv* jni, jobject object) {
310 jclass c = jni->GetObjectClass(object);
311 CHECK_EXCEPTION(jni, "error during GetObjectClass");
316 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
317 jobject o = jni->GetObjectField(object, id);
318 CHECK_EXCEPTION(jni, "error during GetObjectField");
323 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
324 return static_cast<jstring>(GetObjectField(jni, object, id));
327 jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
328 jlong l = jni->GetLongField(object, id);
329 CHECK_EXCEPTION(jni, "error during GetLongField");
333 jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
334 jint i = jni->GetIntField(object, id);
335 CHECK_EXCEPTION(jni, "error during GetIntField");
339 bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
340 jboolean b = jni->GetBooleanField(object, id);
341 CHECK_EXCEPTION(jni, "error during GetBooleanField");
345 jobject NewGlobalRef(JNIEnv* jni, jobject o) {
346 jobject ret = jni->NewGlobalRef(o);
347 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
352 void DeleteGlobalRef(JNIEnv* jni, jobject o) {
353 jni->DeleteGlobalRef(o);
354 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
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
362 WeakRef(JNIEnv* jni, jweak ref)
363 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
364 CHECK_EXCEPTION(jni, "error during NewLocalRef");
368 jni_->DeleteLocalRef(obj_);
369 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
372 jobject obj() { return obj_; }
379 // 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).
382 class ScopedLocalRefFrame {
384 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
385 CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
387 ~ScopedLocalRefFrame() {
388 jni_->PopLocalFrame(NULL);
395 // Scoped holder for global Java refs.
396 template<class T> // T is jclass, jobject, jintArray, etc.
397 class ScopedGlobalRef {
399 explicit ScopedGlobalRef(JNIEnv* jni, T obj)
400 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
402 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
404 T operator*() const {
411 // Return the (singleton) Java Enum object corresponding to |index|;
412 // |state_class_fragment| is something like "MediaSource$State".
413 jobject 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());
419 jobjectArray state_values = static_cast<jobjectArray>(
420 jni->CallStaticObjectMethod(state_class, state_values_id));
421 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
422 jobject ret = jni->GetObjectArrayElement(state_values, index);
423 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
427 // Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
428 static 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");
435 // Given a (UTF-16) jstring return a new UTF-8 native string.
436 static 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");
444 return ustr.toUTF8String(ret);
447 static DataChannelInit JavaDataChannelInitToNative(
448 JNIEnv* jni, jobject j_init) {
449 DataChannelInit init;
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");
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);
473 class ConstraintsWrapper;
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.
478 class PCOJava : public PeerConnectionObserver {
480 PCOJava(JNIEnv* jni, jobject j_observer)
481 : j_observer_global_(jni, j_observer),
482 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")),
487 j_audio_track_ctor_(GetMethodID(
488 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")) {
497 virtual ~PCOJava() {}
499 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
500 ScopedLocalRefFrame local_ref_frame(jni());
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");
506 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);
510 CHECK_EXCEPTION(jni(), "error during NewObject");
511 jmethodID m = GetMethodID(jni(), *j_observer_class_,
512 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
513 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
514 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
517 virtual void OnError() OVERRIDE {
518 ScopedLocalRefFrame local_ref_frame(jni());
519 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
520 jni()->CallVoidMethod(*j_observer_global_, m);
521 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
524 virtual void OnSignalingChange(
525 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
526 ScopedLocalRefFrame local_ref_frame(jni());
527 jmethodID m = GetMethodID(
528 jni(), *j_observer_class_, "onSignalingChange",
529 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
530 jobject new_state_enum =
531 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
532 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
533 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
536 virtual void OnIceConnectionChange(
537 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
538 ScopedLocalRefFrame local_ref_frame(jni());
539 jmethodID m = GetMethodID(
540 jni(), *j_observer_class_, "onIceConnectionChange",
541 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
542 jobject new_state_enum = JavaEnumFromIndex(
543 jni(), "PeerConnection$IceConnectionState", new_state);
544 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
545 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
548 virtual void OnIceGatheringChange(
549 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
550 ScopedLocalRefFrame local_ref_frame(jni());
551 jmethodID m = GetMethodID(
552 jni(), *j_observer_class_, "onIceGatheringChange",
553 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
554 jobject new_state_enum = JavaEnumFromIndex(
555 jni(), "PeerConnection$IceGatheringState", new_state);
556 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
557 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
560 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
561 ScopedLocalRefFrame local_ref_frame(jni());
562 jobject j_stream = jni()->NewObject(
563 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
564 CHECK_EXCEPTION(jni(), "error during NewObject");
566 AudioTrackVector audio_tracks = stream->GetAudioTracks();
567 for (size_t i = 0; i < audio_tracks.size(); ++i) {
568 AudioTrackInterface* track = audio_tracks[i];
569 jstring id = JavaStringFromStdString(jni(), track->id());
570 jobject j_track = jni()->NewObject(
571 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
572 CHECK_EXCEPTION(jni(), "error during NewObject");
573 jfieldID audio_tracks_id = GetFieldID(jni(),
574 *j_media_stream_class_,
576 "Ljava/util/LinkedList;");
577 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
578 jmethodID add = GetMethodID(jni(),
579 GetObjectClass(jni(), audio_tracks),
581 "(Ljava/lang/Object;)Z");
582 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
583 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
587 VideoTrackVector video_tracks = stream->GetVideoTracks();
588 for (size_t i = 0; i < video_tracks.size(); ++i) {
589 VideoTrackInterface* track = video_tracks[i];
590 jstring id = JavaStringFromStdString(jni(), track->id());
591 jobject j_track = jni()->NewObject(
592 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
593 CHECK_EXCEPTION(jni(), "error during NewObject");
594 jfieldID video_tracks_id = GetFieldID(jni(),
595 *j_media_stream_class_,
597 "Ljava/util/LinkedList;");
598 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
599 jmethodID add = GetMethodID(jni(),
600 GetObjectClass(jni(), video_tracks),
602 "(Ljava/lang/Object;)Z");
603 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
604 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
607 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
608 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
610 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
611 "(Lorg/webrtc/MediaStream;)V");
612 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
613 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
616 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
617 ScopedLocalRefFrame local_ref_frame(jni());
618 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
619 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
621 WeakRef s(jni(), it->second);
626 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
627 "(Lorg/webrtc/MediaStream;)V");
628 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
629 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
632 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
633 ScopedLocalRefFrame local_ref_frame(jni());
634 jobject j_channel = jni()->NewObject(
635 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
636 CHECK_EXCEPTION(jni(), "error during NewObject");
638 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
639 "(Lorg/webrtc/DataChannel;)V");
640 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
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");
649 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
652 virtual void OnRenegotiationNeeded() OVERRIDE {
653 ScopedLocalRefFrame local_ref_frame(jni());
655 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
656 jni()->CallVoidMethod(*j_observer_global_, m);
657 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
660 void SetConstraints(ConstraintsWrapper* constraints) {
661 CHECK(!constraints_.get(), "constraints already set!");
662 constraints_.reset(constraints);
665 const ConstraintsWrapper* constraints() { return constraints_.get(); }
669 return AttachCurrentThreadIfNeeded();
672 const ScopedGlobalRef<jobject> j_observer_global_;
673 const ScopedGlobalRef<jclass> j_observer_class_;
674 const ScopedGlobalRef<jclass> j_media_stream_class_;
675 const jmethodID j_media_stream_ctor_;
676 const ScopedGlobalRef<jclass> j_audio_track_class_;
677 const jmethodID j_audio_track_ctor_;
678 const ScopedGlobalRef<jclass> j_video_track_class_;
679 const jmethodID j_video_track_ctor_;
680 const ScopedGlobalRef<jclass> j_data_channel_class_;
681 const jmethodID j_data_channel_ctor_;
682 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
683 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
684 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
687 // Wrapper for a Java MediaConstraints object. Copies all needed data so when
688 // the constructor returns the Java object is no longer needed.
689 class ConstraintsWrapper : public MediaConstraintsInterface {
691 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
692 PopulateConstraintsFromJavaPairList(
693 jni, j_constraints, "mandatory", &mandatory_);
694 PopulateConstraintsFromJavaPairList(
695 jni, j_constraints, "optional", &optional_);
698 virtual ~ConstraintsWrapper() {}
700 // MediaConstraintsInterface.
701 virtual const Constraints& GetMandatory() const OVERRIDE {
705 virtual const Constraints& GetOptional() const OVERRIDE {
710 // Helper for translating a List<Pair<String, String>> to a Constraints.
711 static void PopulateConstraintsFromJavaPairList(
712 JNIEnv* jni, jobject j_constraints,
713 const char* field_name, Constraints* field) {
714 jfieldID j_id = GetFieldID(jni,
715 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
716 jobject j_list = GetObjectField(jni, j_constraints, j_id);
717 jmethodID j_iterator_id = GetMethodID(jni,
718 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
719 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
720 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
721 jmethodID j_has_next = GetMethodID(jni,
722 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
723 jmethodID j_next = GetMethodID(jni,
724 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
725 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
726 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
727 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
728 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
729 jmethodID get_key = GetMethodID(jni,
730 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
731 jstring j_key = reinterpret_cast<jstring>(
732 jni->CallObjectMethod(entry, get_key));
733 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
734 jmethodID get_value = GetMethodID(jni,
735 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
736 jstring j_value = reinterpret_cast<jstring>(
737 jni->CallObjectMethod(entry, get_value));
738 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
739 field->push_back(Constraint(JavaToStdString(jni, j_key),
740 JavaToStdString(jni, j_value)));
742 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
745 Constraints mandatory_;
746 Constraints optional_;
749 static jobject JavaSdpFromNativeSdp(
750 JNIEnv* jni, const SessionDescriptionInterface* desc) {
752 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
753 jstring j_description = JavaStringFromStdString(jni, sdp);
755 jclass j_type_class = FindClass(
756 jni, "org/webrtc/SessionDescription$Type");
757 jmethodID j_type_from_canonical = GetStaticMethodID(
758 jni, j_type_class, "fromCanonicalForm",
759 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
760 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
761 jobject j_type = jni->CallStaticObjectMethod(
762 j_type_class, j_type_from_canonical, j_type_string);
763 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
765 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
766 jmethodID j_sdp_ctor = GetMethodID(
767 jni, j_sdp_class, "<init>",
768 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
769 jobject j_sdp = jni->NewObject(
770 j_sdp_class, j_sdp_ctor, j_type, j_description);
771 CHECK_EXCEPTION(jni, "error during NewObject");
775 template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
776 class SdpObserverWrapper : public T {
778 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
779 ConstraintsWrapper* constraints)
780 : constraints_(constraints),
781 j_observer_global_(jni, j_observer),
782 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
785 virtual ~SdpObserverWrapper() {}
787 // Can't mark OVERRIDE because of templating.
788 virtual void OnSuccess() {
789 ScopedLocalRefFrame local_ref_frame(jni());
790 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
791 jni()->CallVoidMethod(*j_observer_global_, m);
792 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
795 // Can't mark OVERRIDE because of templating.
796 virtual void OnSuccess(SessionDescriptionInterface* desc) {
797 ScopedLocalRefFrame local_ref_frame(jni());
798 jmethodID m = GetMethodID(
799 jni(), *j_observer_class_, "onCreateSuccess",
800 "(Lorg/webrtc/SessionDescription;)V");
801 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
802 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
803 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
807 // Common implementation for failure of Set & Create types, distinguished by
808 // |op| being "Set" or "Create".
809 void OnFailure(const std::string& op, const std::string& error) {
810 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
811 "(Ljava/lang/String;)V");
812 jstring j_error_string = JavaStringFromStdString(jni(), error);
813 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
814 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
818 return AttachCurrentThreadIfNeeded();
822 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
823 const ScopedGlobalRef<jobject> j_observer_global_;
824 const ScopedGlobalRef<jclass> j_observer_class_;
827 class CreateSdpObserverWrapper
828 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
830 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
831 ConstraintsWrapper* constraints)
832 : SdpObserverWrapper(jni, j_observer, constraints) {}
834 virtual void OnFailure(const std::string& error) OVERRIDE {
835 ScopedLocalRefFrame local_ref_frame(jni());
836 SdpObserverWrapper::OnFailure(std::string("Create"), error);
840 class SetSdpObserverWrapper
841 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
843 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
844 ConstraintsWrapper* constraints)
845 : SdpObserverWrapper(jni, j_observer, constraints) {}
847 virtual void OnFailure(const std::string& error) OVERRIDE {
848 ScopedLocalRefFrame local_ref_frame(jni());
849 SdpObserverWrapper::OnFailure(std::string("Set"), error);
853 // Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
854 // and dispatching the callback from C++ back to Java.
855 class DataChannelObserverWrapper : public DataChannelObserver {
857 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
858 : j_observer_global_(jni, j_observer),
859 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
860 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
861 "onStateChange", "()V")),
862 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
863 "(Lorg/webrtc/DataChannel$Buffer;)V")),
864 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
865 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
866 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
869 virtual ~DataChannelObserverWrapper() {}
871 virtual void OnStateChange() OVERRIDE {
872 ScopedLocalRefFrame local_ref_frame(jni());
873 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
874 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
877 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
878 ScopedLocalRefFrame local_ref_frame(jni());
879 jobject byte_buffer =
880 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
881 buffer.data.length());
882 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
883 byte_buffer, buffer.binary);
884 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
885 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
890 return AttachCurrentThreadIfNeeded();
893 const ScopedGlobalRef<jobject> j_observer_global_;
894 const ScopedGlobalRef<jclass> j_observer_class_;
895 const ScopedGlobalRef<jclass> j_buffer_class_;
896 const jmethodID j_on_state_change_mid_;
897 const jmethodID j_on_message_mid_;
898 const jmethodID j_buffer_ctor_;
901 // Adapter for a Java StatsObserver presenting a C++ StatsObserver and
902 // dispatching the callback from C++ back to Java.
903 class StatsObserverWrapper : public StatsObserver {
905 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
906 : j_observer_global_(jni, j_observer),
907 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
908 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
909 j_stats_report_ctor_(GetMethodID(
910 jni, *j_stats_report_class_, "<init>",
911 "(Ljava/lang/String;Ljava/lang/String;D"
912 "[Lorg/webrtc/StatsReport$Value;)V")),
913 j_value_class_(jni, FindClass(
914 jni, "org/webrtc/StatsReport$Value")),
915 j_value_ctor_(GetMethodID(
916 jni, *j_value_class_, "<init>",
917 "(Ljava/lang/String;Ljava/lang/String;)V")) {
920 virtual ~StatsObserverWrapper() {}
922 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
923 ScopedLocalRefFrame local_ref_frame(jni());
924 jobjectArray j_reports = ReportsToJava(jni(), reports);
925 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
926 "([Lorg/webrtc/StatsReport;)V");
927 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
928 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
932 jobjectArray ReportsToJava(
933 JNIEnv* jni, const std::vector<StatsReport>& reports) {
934 jobjectArray reports_array = jni->NewObjectArray(
935 reports.size(), *j_stats_report_class_, NULL);
936 for (int i = 0; i < reports.size(); ++i) {
937 ScopedLocalRefFrame local_ref_frame(jni);
938 const StatsReport& report = reports[i];
939 jstring j_id = JavaStringFromStdString(jni, report.id);
940 jstring j_type = JavaStringFromStdString(jni, report.type);
941 jobjectArray j_values = ValuesToJava(jni, report.values);
942 jobject j_report = jni->NewObject(*j_stats_report_class_,
943 j_stats_report_ctor_,
948 jni->SetObjectArrayElement(reports_array, i, j_report);
950 return reports_array;
953 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
954 jobjectArray j_values = jni->NewObjectArray(
955 values.size(), *j_value_class_, NULL);
956 for (int i = 0; i < values.size(); ++i) {
957 ScopedLocalRefFrame local_ref_frame(jni);
958 const StatsReport::Value& value = values[i];
959 jstring j_name = JavaStringFromStdString(jni, value.name);
960 jstring j_value = JavaStringFromStdString(jni, value.value);
961 jobject j_element_value =
962 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
963 jni->SetObjectArrayElement(j_values, i, j_element_value);
969 return AttachCurrentThreadIfNeeded();
972 const ScopedGlobalRef<jobject> j_observer_global_;
973 const ScopedGlobalRef<jclass> j_observer_class_;
974 const ScopedGlobalRef<jclass> j_stats_report_class_;
975 const jmethodID j_stats_report_ctor_;
976 const ScopedGlobalRef<jclass> j_value_class_;
977 const jmethodID j_value_ctor_;
980 // Adapter presenting a cricket::VideoRenderer as a
981 // webrtc::VideoRendererInterface.
982 class VideoRendererWrapper : public VideoRendererInterface {
984 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
986 return new VideoRendererWrapper(renderer);
990 virtual ~VideoRendererWrapper() {}
992 virtual void SetSize(int width, int height) OVERRIDE {
993 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
994 const bool kNotReserved = false; // What does this param mean??
995 renderer_->SetSize(width, height, kNotReserved);
998 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
999 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
1000 renderer_->RenderFrame(frame);
1004 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1005 : renderer_(renderer) {}
1007 talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
1010 // Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1012 class JavaVideoRendererWrapper : public VideoRendererInterface {
1014 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
1015 : j_callbacks_(jni, j_callbacks),
1016 j_set_size_id_(GetMethodID(
1017 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1018 j_render_frame_id_(GetMethodID(
1019 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1020 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1022 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1023 j_frame_ctor_id_(GetMethodID(
1024 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1025 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
1026 CHECK_EXCEPTION(jni, "");
1029 virtual ~JavaVideoRendererWrapper() {}
1031 virtual void SetSize(int width, int height) OVERRIDE {
1032 ScopedLocalRefFrame local_ref_frame(jni());
1033 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1034 CHECK_EXCEPTION(jni(), "");
1037 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
1038 ScopedLocalRefFrame local_ref_frame(jni());
1039 jobject j_frame = CricketToJavaFrame(frame);
1040 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1041 CHECK_EXCEPTION(jni(), "");
1045 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1046 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
1047 jintArray strides = jni()->NewIntArray(3);
1048 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
1049 strides_array[0] = frame->GetYPitch();
1050 strides_array[1] = frame->GetUPitch();
1051 strides_array[2] = frame->GetVPitch();
1052 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1053 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1054 jobject y_buffer = jni()->NewDirectByteBuffer(
1055 const_cast<uint8*>(frame->GetYPlane()),
1056 frame->GetYPitch() * frame->GetHeight());
1057 jobject u_buffer = jni()->NewDirectByteBuffer(
1058 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1059 jobject v_buffer = jni()->NewDirectByteBuffer(
1060 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1061 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1062 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1063 jni()->SetObjectArrayElement(planes, 2, v_buffer);
1064 return jni()->NewObject(
1065 *j_frame_class_, j_frame_ctor_id_,
1066 frame->GetWidth(), frame->GetHeight(), strides, planes);
1070 return AttachCurrentThreadIfNeeded();
1073 ScopedGlobalRef<jobject> j_callbacks_;
1074 jmethodID j_set_size_id_;
1075 jmethodID j_render_frame_id_;
1076 ScopedGlobalRef<jclass> j_frame_class_;
1077 jmethodID j_frame_ctor_id_;
1078 ScopedGlobalRef<jclass> j_byte_buffer_class_;
1081 } // anonymous namespace
1084 // Convenience macro defining JNI-accessible methods in the org.webrtc package.
1085 // Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1086 #define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1087 Java_org_webrtc_##name
1089 extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1090 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1092 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1094 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1097 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1099 g_class_reference_holder = new ClassReferenceHolder(jni);
1101 return JNI_VERSION_1_6;
1104 extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
1105 delete g_class_reference_holder;
1106 g_class_reference_holder = NULL;
1107 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
1110 static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
1111 jfieldID native_dc_id = GetFieldID(jni,
1112 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1113 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
1114 return reinterpret_cast<DataChannelInterface*>(j_d);
1117 JOW(jlong, DataChannel_registerObserverNative)(
1118 JNIEnv* jni, jobject j_dc, jobject j_observer) {
1119 talk_base::scoped_ptr<DataChannelObserverWrapper> observer(
1120 new DataChannelObserverWrapper(jni, j_observer));
1121 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
1122 return jlongFromPointer(observer.release());
1125 JOW(void, DataChannel_unregisterObserverNative)(
1126 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1127 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1128 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1131 JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1132 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1135 JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1136 return JavaEnumFromIndex(
1137 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1140 JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1141 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1142 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1143 "buffered_amount overflowed jlong!");
1144 return static_cast<jlong>(buffered_amount);
1147 JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1148 ExtractNativeDC(jni, j_dc)->Close();
1151 JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1152 jbyteArray data, jboolean binary) {
1153 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1154 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1155 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1157 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1161 JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
1162 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
1165 JOW(void, Logging_nativeEnableTracing)(
1166 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1167 jint nativeSeverity) {
1168 std::string path = JavaToStdString(jni, j_path);
1169 if (nativeLevels != webrtc::kTraceNone) {
1170 webrtc::Trace::set_level_filter(nativeLevels);
1172 if (path != "logcat:") {
1174 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1175 "SetTraceFile failed");
1178 // Intentionally leak this to avoid needing to reason about its lifecycle.
1179 // It keeps no state and functions only as a dispatch point.
1180 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1184 talk_base::LogMessage::LogToDebug(nativeSeverity);
1187 JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
1188 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
1191 JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1192 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1196 JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
1197 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
1200 JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1201 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1204 JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1205 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1208 JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
1209 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1212 JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1213 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1214 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
1215 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1218 JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1219 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1220 return reinterpret_cast<MediaStreamInterface*>(pointer)
1221 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1224 JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1225 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1226 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
1227 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1230 JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1231 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1232 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
1233 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1236 JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1237 return JavaStringFromStdString(
1238 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1241 JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
1242 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
1245 JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1246 JNIEnv * jni, jclass, jobject j_observer) {
1247 return (jlong)new PCOJava(jni, j_observer);
1251 JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1252 JNIEnv* jni, jclass, jobject context) {
1253 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1254 bool failure = false;
1255 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm);
1256 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1261 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1262 JNIEnv* jni, jclass) {
1263 webrtc::Trace::CreateTrace();
1264 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1265 webrtc::CreatePeerConnectionFactory());
1266 return (jlong)factory.release();
1269 JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
1270 CHECK_RELEASE(reinterpret_cast<PeerConnectionFactoryInterface*>(j_p));
1271 webrtc::Trace::ReturnTrace();
1274 JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1275 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1276 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1277 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1278 talk_base::scoped_refptr<MediaStreamInterface> stream(
1279 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1280 return (jlong)stream.release();
1283 JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1284 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1285 jobject j_constraints) {
1286 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1287 new ConstraintsWrapper(jni, j_constraints));
1288 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1289 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1290 talk_base::scoped_refptr<VideoSourceInterface> source(
1291 factory->CreateVideoSource(
1292 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1293 constraints.get()));
1294 return (jlong)source.release();
1297 JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1298 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1299 jlong native_source) {
1300 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1301 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1302 talk_base::scoped_refptr<VideoTrackInterface> track(
1303 factory->CreateVideoTrack(
1304 JavaToStdString(jni, id),
1305 reinterpret_cast<VideoSourceInterface*>(native_source)));
1306 return (jlong)track.release();
1309 JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1310 JNIEnv* jni, jclass, jlong native_factory, jstring id) {
1311 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1312 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1313 talk_base::scoped_refptr<AudioTrackInterface> track(
1314 factory->CreateAudioTrack(JavaToStdString(jni, id), NULL));
1315 return (jlong)track.release();
1318 static void JavaIceServersToJsepIceServers(
1319 JNIEnv* jni, jobject j_ice_servers,
1320 PeerConnectionInterface::IceServers* ice_servers) {
1321 jclass list_class = GetObjectClass(jni, j_ice_servers);
1322 jmethodID iterator_id = GetMethodID(
1323 jni, list_class, "iterator", "()Ljava/util/Iterator;");
1324 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
1325 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1326 jmethodID iterator_has_next = GetMethodID(
1327 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
1328 jmethodID iterator_next = GetMethodID(
1329 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
1330 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
1331 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1332 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
1333 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1334 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
1335 jfieldID j_ice_server_uri_id =
1336 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
1337 jfieldID j_ice_server_username_id =
1338 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
1339 jfieldID j_ice_server_password_id =
1340 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
1341 jstring uri = reinterpret_cast<jstring>(
1342 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
1343 jstring username = reinterpret_cast<jstring>(
1344 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
1345 jstring password = reinterpret_cast<jstring>(
1346 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
1347 PeerConnectionInterface::IceServer server;
1348 server.uri = JavaToStdString(jni, uri);
1349 server.username = JavaToStdString(jni, username);
1350 server.password = JavaToStdString(jni, password);
1351 ice_servers->push_back(server);
1353 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1356 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
1357 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
1358 jobject j_constraints, jlong observer_p) {
1359 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
1360 reinterpret_cast<PeerConnectionFactoryInterface*>(factory));
1361 PeerConnectionInterface::IceServers servers;
1362 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
1363 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
1364 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
1365 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
1366 servers, observer->constraints(), NULL, observer));
1367 return (jlong)pc.release();
1370 static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
1371 JNIEnv* jni, jobject j_pc) {
1372 jfieldID native_pc_id = GetFieldID(jni,
1373 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
1374 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
1375 return talk_base::scoped_refptr<PeerConnectionInterface>(
1376 reinterpret_cast<PeerConnectionInterface*>(j_p));
1379 JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
1380 const SessionDescriptionInterface* sdp =
1381 ExtractNativePC(jni, j_pc)->local_description();
1382 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1385 JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
1386 const SessionDescriptionInterface* sdp =
1387 ExtractNativePC(jni, j_pc)->remote_description();
1388 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1391 JOW(jobject, PeerConnection_createDataChannel)(
1392 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
1393 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
1394 talk_base::scoped_refptr<DataChannelInterface> channel(
1395 ExtractNativePC(jni, j_pc)->CreateDataChannel(
1396 JavaToStdString(jni, j_label), &init));
1397 // Mustn't pass channel.get() directly through NewObject to avoid reading its
1398 // vararg parameter as 64-bit and reading memory that doesn't belong to the
1399 // 32-bit parameter.
1400 jlong nativeChannelPtr = jlongFromPointer(channel.get());
1401 CHECK(nativeChannelPtr, "Failed to create DataChannel");
1402 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
1403 jmethodID j_data_channel_ctor = GetMethodID(
1404 jni, j_data_channel_class, "<init>", "(J)V");
1405 jobject j_channel = jni->NewObject(
1406 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
1407 CHECK_EXCEPTION(jni, "error during NewObject");
1408 // Channel is now owned by Java object, and will be freed from there.
1409 int bumped_count = channel->AddRef();
1410 CHECK(bumped_count == 2, "Unexpected refcount");
1414 JOW(void, PeerConnection_createOffer)(
1415 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1416 ConstraintsWrapper* constraints =
1417 new ConstraintsWrapper(jni, j_constraints);
1418 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1419 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1420 jni, j_observer, constraints));
1421 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
1424 JOW(void, PeerConnection_createAnswer)(
1425 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1426 ConstraintsWrapper* constraints =
1427 new ConstraintsWrapper(jni, j_constraints);
1428 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1429 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1430 jni, j_observer, constraints));
1431 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
1434 // Helper to create a SessionDescriptionInterface from a SessionDescription.
1435 static SessionDescriptionInterface* JavaSdpToNativeSdp(
1436 JNIEnv* jni, jobject j_sdp) {
1437 jfieldID j_type_id = GetFieldID(
1438 jni, GetObjectClass(jni, j_sdp), "type",
1439 "Lorg/webrtc/SessionDescription$Type;");
1440 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
1441 jmethodID j_canonical_form_id = GetMethodID(
1442 jni, GetObjectClass(jni, j_type), "canonicalForm",
1443 "()Ljava/lang/String;");
1444 jstring j_type_string = (jstring)jni->CallObjectMethod(
1445 j_type, j_canonical_form_id);
1446 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1447 std::string std_type = JavaToStdString(jni, j_type_string);
1449 jfieldID j_description_id = GetFieldID(
1450 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
1451 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
1452 std::string std_description = JavaToStdString(jni, j_description);
1454 return webrtc::CreateSessionDescription(
1455 std_type, std_description, NULL);
1458 JOW(void, PeerConnection_setLocalDescription)(
1459 JNIEnv* jni, jobject j_pc,
1460 jobject j_observer, jobject j_sdp) {
1461 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1462 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1463 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1464 ExtractNativePC(jni, j_pc)->SetLocalDescription(
1465 observer, JavaSdpToNativeSdp(jni, j_sdp));
1468 JOW(void, PeerConnection_setRemoteDescription)(
1469 JNIEnv* jni, jobject j_pc,
1470 jobject j_observer, jobject j_sdp) {
1471 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1472 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1473 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1474 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
1475 observer, JavaSdpToNativeSdp(jni, j_sdp));
1478 JOW(jboolean, PeerConnection_updateIce)(
1479 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
1480 PeerConnectionInterface::IceServers ice_servers;
1481 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
1482 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1483 new ConstraintsWrapper(jni, j_constraints));
1484 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
1487 JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
1488 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
1489 jint j_sdp_mline_index, jstring j_candidate_sdp) {
1490 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
1491 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
1492 talk_base::scoped_ptr<IceCandidateInterface> candidate(
1493 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
1494 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
1497 JOW(jboolean, PeerConnection_nativeAddLocalStream)(
1498 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
1499 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1500 new ConstraintsWrapper(jni, j_constraints));
1501 return ExtractNativePC(jni, j_pc)->AddStream(
1502 reinterpret_cast<MediaStreamInterface*>(native_stream),
1506 JOW(void, PeerConnection_nativeRemoveLocalStream)(
1507 JNIEnv* jni, jobject j_pc, jlong native_stream) {
1508 ExtractNativePC(jni, j_pc)->RemoveStream(
1509 reinterpret_cast<MediaStreamInterface*>(native_stream));
1512 JOW(bool, PeerConnection_nativeGetStats)(
1513 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
1514 talk_base::scoped_refptr<StatsObserverWrapper> observer(
1515 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
1516 return ExtractNativePC(jni, j_pc)->GetStats(
1517 observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
1520 JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
1521 PeerConnectionInterface::SignalingState state =
1522 ExtractNativePC(jni, j_pc)->signaling_state();
1523 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
1526 JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
1527 PeerConnectionInterface::IceConnectionState state =
1528 ExtractNativePC(jni, j_pc)->ice_connection_state();
1529 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
1532 JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
1533 PeerConnectionInterface::IceGatheringState state =
1534 ExtractNativePC(jni, j_pc)->ice_gathering_state();
1535 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
1538 JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1539 ExtractNativePC(jni, j_pc)->Close();
1543 JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1544 talk_base::scoped_refptr<MediaSourceInterface> p(
1545 reinterpret_cast<MediaSourceInterface*>(j_p));
1546 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
1549 JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
1550 JNIEnv* jni, jclass, jstring j_device_name) {
1551 std::string device_name = JavaToStdString(jni, j_device_name);
1552 talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
1553 cricket::DeviceManagerFactory::Create());
1554 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
1555 cricket::Device device;
1556 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
1557 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
1560 talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1561 device_manager->CreateVideoCapturer(device));
1562 return (jlong)capturer.release();
1565 JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
1566 JNIEnv* jni, jclass, int x, int y) {
1567 talk_base::scoped_ptr<VideoRendererWrapper> renderer(
1568 VideoRendererWrapper::Create(
1569 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
1570 return (jlong)renderer.release();
1573 JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
1574 JNIEnv* jni, jclass, jobject j_callbacks) {
1575 talk_base::scoped_ptr<JavaVideoRendererWrapper> renderer(
1576 new JavaVideoRendererWrapper(jni, j_callbacks));
1577 return (jlong)renderer.release();
1580 JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
1581 cricket::VideoCapturer* capturer =
1582 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
1583 talk_base::scoped_ptr<cricket::VideoFormatPod> format(
1584 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
1586 return jlongFromPointer(format.release());
1589 JOW(void, VideoSource_restart)(
1590 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
1591 talk_base::scoped_ptr<cricket::VideoFormatPod> format(
1592 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
1593 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
1594 StartCapturing(cricket::VideoFormat(*format));
1597 JOW(void, VideoSource_freeNativeVideoFormat)(
1598 JNIEnv* jni, jclass, jlong j_p) {
1599 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
1602 JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
1603 return JavaStringFromStdString(
1604 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
1607 JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
1608 return JavaStringFromStdString(
1609 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
1612 JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
1613 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
1616 JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1617 return JavaEnumFromIndex(
1619 "MediaStreamTrack$State",
1620 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
1623 JOW(jboolean, MediaStreamTrack_nativeSetState)(
1624 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
1625 MediaStreamTrackInterface::TrackState new_state =
1626 (MediaStreamTrackInterface::TrackState)j_new_state;
1627 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1628 ->set_state(new_state);
1631 JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
1632 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
1633 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1634 ->set_enabled(enabled);
1637 JOW(void, VideoTrack_nativeAddRenderer)(
1638 JNIEnv* jni, jclass,
1639 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1640 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
1641 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1644 JOW(void, VideoTrack_nativeRemoveRenderer)(
1645 JNIEnv* jni, jclass,
1646 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1647 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
1648 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));