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>
65 #include "talk/app/webrtc/mediaconstraintsinterface.h"
66 #include "talk/app/webrtc/peerconnectioninterface.h"
67 #include "talk/app/webrtc/videosourceinterface.h"
68 #include "talk/base/logging.h"
69 #include "talk/base/ssladapter.h"
70 #include "talk/media/base/videocapturer.h"
71 #include "talk/media/base/videorenderer.h"
72 #include "talk/media/devices/videorendererfactory.h"
73 #include "talk/media/webrtc/webrtcvideocapturer.h"
74 #include "third_party/icu/source/common/unicode/unistr.h"
75 #include "webrtc/system_wrappers/interface/compile_assert.h"
76 #include "webrtc/system_wrappers/interface/trace.h"
77 #include "webrtc/video_engine/include/vie_base.h"
78 #include "webrtc/voice_engine/include/voe_base.h"
81 #include "webrtc/system_wrappers/interface/logcat_trace_context.h"
82 using webrtc::LogcatTraceContext;
85 using icu::UnicodeString;
86 using webrtc::AudioSourceInterface;
87 using webrtc::AudioTrackInterface;
88 using webrtc::AudioTrackVector;
89 using webrtc::CreateSessionDescriptionObserver;
90 using webrtc::DataBuffer;
91 using webrtc::DataChannelInit;
92 using webrtc::DataChannelInterface;
93 using webrtc::DataChannelObserver;
94 using webrtc::IceCandidateInterface;
95 using webrtc::MediaConstraintsInterface;
96 using webrtc::MediaSourceInterface;
97 using webrtc::MediaStreamInterface;
98 using webrtc::MediaStreamTrackInterface;
99 using webrtc::PeerConnectionFactoryInterface;
100 using webrtc::PeerConnectionInterface;
101 using webrtc::PeerConnectionObserver;
102 using webrtc::SessionDescriptionInterface;
103 using webrtc::SetSessionDescriptionObserver;
104 using webrtc::StatsObserver;
105 using webrtc::StatsReport;
106 using webrtc::VideoRendererInterface;
107 using webrtc::VideoSourceInterface;
108 using webrtc::VideoTrackInterface;
109 using webrtc::VideoTrackVector;
111 // Abort the process if |x| is false, emitting |msg|.
112 #define CHECK(x, msg) \
114 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
117 // Abort the process if |jni| has a Java exception pending, emitting |msg|.
118 #define CHECK_EXCEPTION(jni, msg) \
120 if (jni->ExceptionCheck()) { \
121 jni->ExceptionDescribe(); \
122 jni->ExceptionClear(); \
127 // Helper that calls ptr->Release() and logs a useful message if that didn't
128 // actually delete *ptr because of extra refcounts.
129 #define CHECK_RELEASE(ptr) \
131 int count = (ptr)->Release(); \
133 LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr) \
136 CHECK(!count, "Unexpected refcount"); \
141 static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
143 static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
144 static pthread_key_t g_jni_ptr; // Key for per-thread JNIEnv* data.
146 // Return thread ID as a string.
147 static std::string GetThreadId() {
148 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
149 CHECK(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)) <= sizeof(buf),
150 "Thread id is bigger than uint64??");
151 return std::string(buf);
154 // Return the current thread's name.
155 static std::string GetThreadName() {
157 CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
159 return std::string(name);
162 static void ThreadDestructor(void* unused) {
163 jint status = g_jvm->DetachCurrentThread();
164 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
167 static void CreateJNIPtrKey() {
168 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
169 "pthread_key_create");
172 // Deal with difference in signatures between Oracle's jni.h and Android's.
173 static JNIEnv* AttachCurrentThreadIfNeeded() {
174 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
176 JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
178 #ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
183 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
184 JavaVMAttachArgs args;
185 args.version = JNI_VERSION_1_6;
188 CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
190 CHECK(env, "AttachCurrentThread handed back NULL!");
191 jni = reinterpret_cast<JNIEnv*>(env);
192 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
197 // Return a |jlong| that will automatically convert back to |ptr| when assigned
199 static jlong jlongFromPointer(void* ptr) {
200 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(uint64),
201 Time_to_rethink_the_use_of_jlongs);
202 // Guaranteed to fit by the COMPILE_ASSERT above.
203 uint64 u64 = reinterpret_cast<intptr_t>(ptr);
204 // If the unsigned value fits in the signed type, return it directly.
205 if (u64 <= std::numeric_limits<int64>::max())
207 // Otherwise, we need to get move u64 into the range of [int64min, -1] subject
208 // to the constraints of remaining equal to |u64| modulo |2^64|.
209 u64 = std::numeric_limits<uint64>::max() - u64; // In [0,int64max].
210 int64 i64 = -u64; // In [-int64max, 0].
211 i64 -= 1; // In [int64min, -1], and i64+2^64==u64.
215 // Android's FindClass() is trickier than usual because the app-specific
216 // ClassLoader is not consulted when there is no app-specific frame on the
217 // stack. Consequently, we only look up classes once in JNI_OnLoad.
218 // http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
219 class ClassReferenceHolder {
221 explicit ClassReferenceHolder(JNIEnv* jni) {
222 LoadClass(jni, "java/nio/ByteBuffer");
223 LoadClass(jni, "org/webrtc/AudioTrack");
224 LoadClass(jni, "org/webrtc/DataChannel");
225 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
226 LoadClass(jni, "org/webrtc/DataChannel$Init");
227 LoadClass(jni, "org/webrtc/DataChannel$State");
228 LoadClass(jni, "org/webrtc/IceCandidate");
229 LoadClass(jni, "org/webrtc/MediaSource$State");
230 LoadClass(jni, "org/webrtc/MediaStream");
231 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
232 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
233 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
234 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
235 LoadClass(jni, "org/webrtc/SessionDescription");
236 LoadClass(jni, "org/webrtc/SessionDescription$Type");
237 LoadClass(jni, "org/webrtc/StatsReport");
238 LoadClass(jni, "org/webrtc/StatsReport$Value");
239 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
240 LoadClass(jni, "org/webrtc/VideoTrack");
243 ~ClassReferenceHolder() {
244 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
247 void FreeReferences(JNIEnv* jni) {
248 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
249 it != classes_.end(); ++it) {
250 jni->DeleteGlobalRef(it->second);
255 jclass GetClass(const std::string& name) {
256 std::map<std::string, jclass>::iterator it = classes_.find(name);
257 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
262 void LoadClass(JNIEnv* jni, const std::string& name) {
263 jclass localRef = jni->FindClass(name.c_str());
264 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
265 CHECK(localRef, name);
266 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
267 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
268 CHECK(globalRef, name);
269 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
270 CHECK(inserted, "Duplicate class name: " << name);
273 std::map<std::string, jclass> classes_;
276 // Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
277 static ClassReferenceHolder* g_class_reference_holder = NULL;
279 // JNIEnv-helper methods that CHECK success: no Java exception thrown and found
280 // object/class/method/field is non-null.
281 jmethodID GetMethodID(
282 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
283 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
285 "error during GetMethodID: " << name << ", " << signature);
286 CHECK(m, name << ", " << signature);
290 jmethodID GetStaticMethodID(
291 JNIEnv* jni, jclass c, const char* name, const char* signature) {
292 jmethodID m = jni->GetStaticMethodID(c, name, signature);
294 "error during GetStaticMethodID: "
295 << name << ", " << signature);
296 CHECK(m, name << ", " << signature);
301 JNIEnv* jni, jclass c, const char* name, const char* signature) {
302 jfieldID f = jni->GetFieldID(c, name, signature);
303 CHECK_EXCEPTION(jni, "error during GetFieldID");
304 CHECK(f, name << ", " << signature);
308 jclass FindClass(JNIEnv* jni, const char* name) {
309 return g_class_reference_holder->GetClass(name);
312 jclass GetObjectClass(JNIEnv* jni, jobject object) {
313 jclass c = jni->GetObjectClass(object);
314 CHECK_EXCEPTION(jni, "error during GetObjectClass");
319 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
320 jobject o = jni->GetObjectField(object, id);
321 CHECK_EXCEPTION(jni, "error during GetObjectField");
326 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
327 return static_cast<jstring>(GetObjectField(jni, object, id));
330 jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
331 jlong l = jni->GetLongField(object, id);
332 CHECK_EXCEPTION(jni, "error during GetLongField");
336 jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
337 jint i = jni->GetIntField(object, id);
338 CHECK_EXCEPTION(jni, "error during GetIntField");
342 bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
343 jboolean b = jni->GetBooleanField(object, id);
344 CHECK_EXCEPTION(jni, "error during GetBooleanField");
348 jobject NewGlobalRef(JNIEnv* jni, jobject o) {
349 jobject ret = jni->NewGlobalRef(o);
350 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
355 void DeleteGlobalRef(JNIEnv* jni, jobject o) {
356 jni->DeleteGlobalRef(o);
357 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
360 // Given a jweak reference, allocate a (strong) local reference scoped to the
361 // lifetime of this object if the weak reference is still valid, or NULL
365 WeakRef(JNIEnv* jni, jweak ref)
366 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
367 CHECK_EXCEPTION(jni, "error during NewLocalRef");
371 jni_->DeleteLocalRef(obj_);
372 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
375 jobject obj() { return obj_; }
382 // Given a local ref, take ownership of it and delete the ref when this goes out
384 template<class T> // T is jclass, jobject, jintArray, etc.
385 class ScopedLocalRef {
387 ScopedLocalRef(JNIEnv* jni, T obj)
388 : jni_(jni), obj_(obj) {}
390 jni_->DeleteLocalRef(obj_);
392 T operator*() const {
400 // Scoped holder for global Java refs.
401 template<class T> // T is jclass, jobject, jintArray, etc.
402 class ScopedGlobalRef {
404 explicit ScopedGlobalRef(JNIEnv* jni, T obj)
405 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
407 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
409 T operator*() const {
416 // Return the (singleton) Java Enum object corresponding to |index|;
417 // |state_class_fragment| is something like "MediaSource$State".
418 jobject JavaEnumFromIndex(
419 JNIEnv* jni, const std::string& state_class_fragment, int index) {
420 std::string state_class_name = "org/webrtc/" + state_class_fragment;
421 jclass state_class = FindClass(jni, state_class_name.c_str());
422 jmethodID state_values_id = GetStaticMethodID(
423 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
424 ScopedLocalRef<jobjectArray> state_values(
426 (jobjectArray)jni->CallStaticObjectMethod(state_class, state_values_id));
427 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
428 jobject ret = jni->GetObjectArrayElement(*state_values, index);
429 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
433 // Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
434 static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
435 UnicodeString ustr(UnicodeString::fromUTF8(native));
436 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
437 CHECK_EXCEPTION(jni, "error during NewString");
441 // Given a (UTF-16) jstring return a new UTF-8 native string.
442 static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
443 const jchar* jchars = jni->GetStringChars(j_string, NULL);
444 CHECK_EXCEPTION(jni, "Error during GetStringChars");
445 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
446 CHECK_EXCEPTION(jni, "Error during GetStringLength");
447 jni->ReleaseStringChars(j_string, jchars);
448 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
450 return ustr.toUTF8String(ret);
453 static DataChannelInit JavaDataChannelInitToNative(
454 JNIEnv* jni, jobject j_init) {
455 DataChannelInit init;
457 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
458 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
459 jfieldID max_retransmit_time_id =
460 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
461 jfieldID max_retransmits_id =
462 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
463 jfieldID protocol_id =
464 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
465 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
466 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
468 init.ordered = GetBooleanField(jni, j_init, ordered_id);
469 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
470 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
471 init.protocol = JavaToStdString(
472 jni, GetStringField(jni, j_init, protocol_id));
473 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
474 init.id = GetIntField(jni, j_init, id_id);
479 class ConstraintsWrapper;
481 // Adapter between the C++ PeerConnectionObserver interface and the Java
482 // PeerConnection.Observer interface. Wraps an instance of the Java interface
483 // and dispatches C++ callbacks to Java.
484 class PCOJava : public PeerConnectionObserver {
486 PCOJava(JNIEnv* jni, jobject j_observer)
487 : j_observer_global_(jni, j_observer),
488 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
489 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
490 j_media_stream_ctor_(GetMethodID(
491 jni, *j_media_stream_class_, "<init>", "(J)V")),
492 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
493 j_audio_track_ctor_(GetMethodID(
494 jni, *j_audio_track_class_, "<init>", "(J)V")),
495 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
496 j_video_track_ctor_(GetMethodID(
497 jni, *j_video_track_class_, "<init>", "(J)V")),
498 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
499 j_data_channel_ctor_(GetMethodID(
500 jni, *j_data_channel_class_, "<init>", "(J)V")) {
503 virtual ~PCOJava() {}
505 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
507 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
508 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
509 jmethodID ctor = GetMethodID(jni(), candidate_class,
510 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
511 ScopedLocalRef<jstring> j_mid(
512 jni(), JavaStringFromStdString(jni(), candidate->sdp_mid()));
513 ScopedLocalRef<jstring> j_sdp(jni(), JavaStringFromStdString(jni(), sdp));
514 ScopedLocalRef<jobject> j_candidate(jni(), jni()->NewObject(
515 candidate_class, ctor, *j_mid, candidate->sdp_mline_index(), *j_sdp));
516 CHECK_EXCEPTION(jni(), "error during NewObject");
517 jmethodID m = GetMethodID(jni(), *j_observer_class_,
518 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
519 jni()->CallVoidMethod(*j_observer_global_, m, *j_candidate);
520 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
523 virtual void OnError() OVERRIDE {
524 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "(V)V");
525 jni()->CallVoidMethod(*j_observer_global_, m);
526 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
529 virtual void OnSignalingChange(
530 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
531 jmethodID m = GetMethodID(
532 jni(), *j_observer_class_, "onSignalingChange",
533 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
534 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
535 jni(), "PeerConnection$SignalingState", new_state));
536 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
537 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
540 virtual void OnIceConnectionChange(
541 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
542 jmethodID m = GetMethodID(
543 jni(), *j_observer_class_, "onIceConnectionChange",
544 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
545 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
546 jni(), "PeerConnection$IceConnectionState", new_state));
547 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
548 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
551 virtual void OnIceGatheringChange(
552 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
553 jmethodID m = GetMethodID(
554 jni(), *j_observer_class_, "onIceGatheringChange",
555 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
556 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
557 jni(), "PeerConnection$IceGatheringState", new_state));
558 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
559 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
562 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
563 ScopedLocalRef<jobject> j_stream(jni(), jni()->NewObject(
564 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream));
565 CHECK_EXCEPTION(jni(), "error during NewObject");
567 AudioTrackVector audio_tracks = stream->GetAudioTracks();
568 for (size_t i = 0; i < audio_tracks.size(); ++i) {
569 AudioTrackInterface* track = audio_tracks[i];
570 ScopedLocalRef<jstring> id(
571 jni(), JavaStringFromStdString(jni(), track->id()));
572 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
573 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
574 CHECK_EXCEPTION(jni(), "error during NewObject");
575 jfieldID audio_tracks_id = GetFieldID(jni(),
576 *j_media_stream_class_,
578 "Ljava/util/LinkedList;");
579 ScopedLocalRef<jobject> audio_tracks(jni(), GetObjectField(
580 jni(), *j_stream, audio_tracks_id));
581 jmethodID add = GetMethodID(jni(),
582 GetObjectClass(jni(), *audio_tracks), "add", "(Ljava/lang/Object;)Z");
583 jboolean added = jni()->CallBooleanMethod(*audio_tracks, add, *j_track);
584 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
588 VideoTrackVector video_tracks = stream->GetVideoTracks();
589 for (size_t i = 0; i < video_tracks.size(); ++i) {
590 VideoTrackInterface* track = video_tracks[i];
591 ScopedLocalRef<jstring> id(
592 jni(), JavaStringFromStdString(jni(), track->id()));
593 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
594 *j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
595 CHECK_EXCEPTION(jni(), "error during NewObject");
596 jfieldID video_tracks_id = GetFieldID(jni(),
597 *j_media_stream_class_,
599 "Ljava/util/LinkedList;");
600 ScopedLocalRef<jobject> video_tracks(jni(), GetObjectField(
601 jni(), *j_stream, video_tracks_id));
602 jmethodID add = GetMethodID(jni(),
603 GetObjectClass(jni(), *video_tracks), "add", "(Ljava/lang/Object;)Z");
604 jboolean added = jni()->CallBooleanMethod(*video_tracks, add, *j_track);
605 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
608 streams_[stream] = jni()->NewWeakGlobalRef(*j_stream);
609 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
611 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
612 "(Lorg/webrtc/MediaStream;)V");
613 jni()->CallVoidMethod(*j_observer_global_, m, *j_stream);
614 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
617 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
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 ScopedLocalRef<jobject> j_channel(jni(), jni()->NewObject(
634 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel));
635 CHECK_EXCEPTION(jni(), "error during NewObject");
637 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
638 "(Lorg/webrtc/DataChannel;)V");
639 jni()->CallVoidMethod(*j_observer_global_, m, *j_channel);
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");
648 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
651 void SetConstraints(ConstraintsWrapper* constraints) {
652 CHECK(!constraints_.get(), "constraints already set!");
653 constraints_.reset(constraints);
656 const ConstraintsWrapper* constraints() { return constraints_.get(); }
660 return AttachCurrentThreadIfNeeded();
663 const ScopedGlobalRef<jobject> j_observer_global_;
664 const ScopedGlobalRef<jclass> j_observer_class_;
665 const ScopedGlobalRef<jclass> j_media_stream_class_;
666 const jmethodID j_media_stream_ctor_;
667 const ScopedGlobalRef<jclass> j_audio_track_class_;
668 const jmethodID j_audio_track_ctor_;
669 const ScopedGlobalRef<jclass> j_video_track_class_;
670 const jmethodID j_video_track_ctor_;
671 const ScopedGlobalRef<jclass> j_data_channel_class_;
672 const jmethodID j_data_channel_ctor_;
673 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
674 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
675 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
678 // Wrapper for a Java MediaConstraints object. Copies all needed data so when
679 // the constructor returns the Java object is no longer needed.
680 class ConstraintsWrapper : public MediaConstraintsInterface {
682 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
683 PopulateConstraintsFromJavaPairList(
684 jni, j_constraints, "mandatory", &mandatory_);
685 PopulateConstraintsFromJavaPairList(
686 jni, j_constraints, "optional", &optional_);
689 virtual ~ConstraintsWrapper() {}
691 // MediaConstraintsInterface.
692 virtual const Constraints& GetMandatory() const OVERRIDE {
696 virtual const Constraints& GetOptional() const OVERRIDE {
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)));
733 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
736 Constraints mandatory_;
737 Constraints optional_;
740 static jobject JavaSdpFromNativeSdp(
741 JNIEnv* jni, const SessionDescriptionInterface* desc) {
743 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
744 ScopedLocalRef<jstring> j_description(jni, JavaStringFromStdString(jni, sdp));
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;");
751 ScopedLocalRef<jstring> j_type_string(
752 jni, JavaStringFromStdString(jni, desc->type()));
753 jobject j_type = jni->CallStaticObjectMethod(
754 j_type_class, j_type_from_canonical, *j_type_string);
755 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
757 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
758 jmethodID j_sdp_ctor = GetMethodID(
759 jni, j_sdp_class, "<init>",
760 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
761 jobject j_sdp = jni->NewObject(
762 j_sdp_class, j_sdp_ctor, j_type, *j_description);
763 CHECK_EXCEPTION(jni, "error during NewObject");
767 template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
768 class SdpObserverWrapper : public T {
770 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
771 ConstraintsWrapper* constraints)
772 : constraints_(constraints),
773 j_observer_global_(jni, j_observer),
774 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
777 virtual ~SdpObserverWrapper() {}
779 // Can't mark OVERRIDE because of templating.
780 virtual void OnSuccess() {
781 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
782 jni()->CallVoidMethod(*j_observer_global_, m);
783 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
786 // Can't mark OVERRIDE because of templating.
787 virtual void OnSuccess(SessionDescriptionInterface* desc) {
788 jmethodID m = GetMethodID(
789 jni(), *j_observer_class_, "onCreateSuccess",
790 "(Lorg/webrtc/SessionDescription;)V");
791 ScopedLocalRef<jobject> j_sdp(jni(), JavaSdpFromNativeSdp(jni(), desc));
792 jni()->CallVoidMethod(*j_observer_global_, m, *j_sdp);
793 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
797 // Common implementation for failure of Set & Create types, distinguished by
798 // |op| being "Set" or "Create".
799 void OnFailure(const std::string& op, const std::string& error) {
800 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
801 "(Ljava/lang/String;)V");
802 ScopedLocalRef<jstring> j_error_string(
803 jni(), JavaStringFromStdString(jni(), error));
804 jni()->CallVoidMethod(*j_observer_global_, m, *j_error_string);
805 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
810 return AttachCurrentThreadIfNeeded();
813 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
814 const ScopedGlobalRef<jobject> j_observer_global_;
815 const ScopedGlobalRef<jclass> j_observer_class_;
818 class CreateSdpObserverWrapper
819 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
821 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
822 ConstraintsWrapper* constraints)
823 : SdpObserverWrapper(jni, j_observer, constraints) {}
825 virtual void OnFailure(const std::string& error) OVERRIDE {
826 SdpObserverWrapper::OnFailure(std::string("Create"), error);
830 class SetSdpObserverWrapper
831 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
833 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
834 ConstraintsWrapper* constraints)
835 : SdpObserverWrapper(jni, j_observer, constraints) {}
837 virtual void OnFailure(const std::string& error) OVERRIDE {
838 SdpObserverWrapper::OnFailure(std::string("Set"), error);
842 // Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
843 // and dispatching the callback from C++ back to Java.
844 class DataChannelObserverWrapper : public DataChannelObserver {
846 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
847 : j_observer_global_(jni, j_observer),
848 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
849 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
850 "onStateChange", "()V")),
851 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
852 "(Lorg/webrtc/DataChannel$Buffer;)V")),
853 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
854 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
855 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
858 virtual ~DataChannelObserverWrapper() {}
860 virtual void OnStateChange() OVERRIDE {
861 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
862 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
865 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
866 jobject byte_buffer =
867 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
868 buffer.data.length());
869 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
870 byte_buffer, buffer.binary);
871 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
872 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
877 return AttachCurrentThreadIfNeeded();
880 const ScopedGlobalRef<jobject> j_observer_global_;
881 const ScopedGlobalRef<jclass> j_observer_class_;
882 const ScopedGlobalRef<jclass> j_buffer_class_;
883 const jmethodID j_on_state_change_mid_;
884 const jmethodID j_on_message_mid_;
885 const jmethodID j_buffer_ctor_;
888 // Adapter for a Java StatsObserver presenting a C++ StatsObserver and
889 // dispatching the callback from C++ back to Java.
890 class StatsObserverWrapper : public StatsObserver {
892 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
893 : j_observer_global_(jni, j_observer),
894 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
895 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
896 j_stats_report_ctor_(GetMethodID(
897 jni, *j_stats_report_class_, "<init>",
898 "(Ljava/lang/String;Ljava/lang/String;D"
899 "[Lorg/webrtc/StatsReport$Value;)V")),
900 j_value_class_(jni, FindClass(
901 jni, "org/webrtc/StatsReport$Value")),
902 j_value_ctor_(GetMethodID(
903 jni, *j_value_class_, "<init>",
904 "(Ljava/lang/String;Ljava/lang/String;)V")) {
907 virtual ~StatsObserverWrapper() {}
909 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
910 ScopedLocalRef<jobjectArray> j_reports(jni(),
911 ReportsToJava(jni(), reports));
912 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
913 "([Lorg/webrtc/StatsReport;)V");
914 jni()->CallVoidMethod(*j_observer_global_, m, *j_reports);
915 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
919 jobjectArray ReportsToJava(
920 JNIEnv* jni, const std::vector<StatsReport>& reports) {
921 jobjectArray reports_array = jni->NewObjectArray(
922 reports.size(), *j_stats_report_class_, NULL);
923 for (int i = 0; i < reports.size(); ++i) {
924 const StatsReport& report = reports[i];
925 ScopedLocalRef<jstring> j_id(
926 jni, JavaStringFromStdString(jni, report.id));
927 ScopedLocalRef<jstring> j_type(
928 jni, JavaStringFromStdString(jni, report.type));
929 ScopedLocalRef<jobjectArray> j_values(
930 jni, ValuesToJava(jni, report.values));
931 ScopedLocalRef<jobject> j_report(jni, jni->NewObject(
932 *j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type,
933 report.timestamp, *j_values));
934 jni->SetObjectArrayElement(reports_array, i, *j_report);
936 return reports_array;
939 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
940 jobjectArray j_values = jni->NewObjectArray(
941 values.size(), *j_value_class_, NULL);
942 for (int i = 0; i < values.size(); ++i) {
943 const StatsReport::Value& value = values[i];
944 ScopedLocalRef<jstring> j_name(
945 jni, JavaStringFromStdString(jni, value.name));
946 ScopedLocalRef<jstring> j_value(
947 jni, JavaStringFromStdString(jni, value.value));
948 ScopedLocalRef<jobject> j_element_value(jni, jni->NewObject(
949 *j_value_class_, j_value_ctor_, *j_name, *j_value));
950 jni->SetObjectArrayElement(j_values, i, *j_element_value);
956 return AttachCurrentThreadIfNeeded();
959 const ScopedGlobalRef<jobject> j_observer_global_;
960 const ScopedGlobalRef<jclass> j_observer_class_;
961 const ScopedGlobalRef<jclass> j_stats_report_class_;
962 const jmethodID j_stats_report_ctor_;
963 const ScopedGlobalRef<jclass> j_value_class_;
964 const jmethodID j_value_ctor_;
967 // Adapter presenting a cricket::VideoRenderer as a
968 // webrtc::VideoRendererInterface.
969 class VideoRendererWrapper : public VideoRendererInterface {
971 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
973 return new VideoRendererWrapper(renderer);
977 virtual ~VideoRendererWrapper() {}
979 virtual void SetSize(int width, int height) OVERRIDE {
980 const bool kNotReserved = false; // What does this param mean??
981 renderer_->SetSize(width, height, kNotReserved);
984 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
985 renderer_->RenderFrame(frame);
989 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
990 : renderer_(renderer) {}
992 talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
995 // Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
997 class JavaVideoRendererWrapper : public VideoRendererInterface {
999 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
1000 : j_callbacks_(jni, j_callbacks),
1001 j_set_size_id_(GetMethodID(
1002 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1003 j_render_frame_id_(GetMethodID(
1004 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1005 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1007 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1008 j_frame_ctor_id_(GetMethodID(
1009 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1010 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
1011 CHECK_EXCEPTION(jni, "");
1014 virtual ~JavaVideoRendererWrapper() {}
1016 virtual void SetSize(int width, int height) OVERRIDE {
1017 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1018 CHECK_EXCEPTION(jni(), "");
1021 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
1022 ScopedLocalRef<jobject> j_frame(jni(), CricketToJavaFrame(frame));
1023 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, *j_frame);
1024 CHECK_EXCEPTION(jni(), "");
1028 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1029 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
1030 ScopedLocalRef<jintArray> strides(jni(), jni()->NewIntArray(3));
1031 jint* strides_array = jni()->GetIntArrayElements(*strides, NULL);
1032 strides_array[0] = frame->GetYPitch();
1033 strides_array[1] = frame->GetUPitch();
1034 strides_array[2] = frame->GetVPitch();
1035 jni()->ReleaseIntArrayElements(*strides, strides_array, 0);
1036 ScopedLocalRef<jobjectArray> planes(
1037 jni(), jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL));
1038 ScopedLocalRef<jobject> y_buffer(jni(), jni()->NewDirectByteBuffer(
1039 const_cast<uint8*>(frame->GetYPlane()),
1040 frame->GetYPitch() * frame->GetHeight()));
1041 ScopedLocalRef<jobject> u_buffer(jni(), jni()->NewDirectByteBuffer(
1042 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize()));
1043 ScopedLocalRef<jobject> v_buffer(jni(), jni()->NewDirectByteBuffer(
1044 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize()));
1045 jni()->SetObjectArrayElement(*planes, 0, *y_buffer);
1046 jni()->SetObjectArrayElement(*planes, 1, *u_buffer);
1047 jni()->SetObjectArrayElement(*planes, 2, *v_buffer);
1048 return jni()->NewObject(
1049 *j_frame_class_, j_frame_ctor_id_,
1050 frame->GetWidth(), frame->GetHeight(), *strides, *planes);
1054 return AttachCurrentThreadIfNeeded();
1057 ScopedGlobalRef<jobject> j_callbacks_;
1058 jmethodID j_set_size_id_;
1059 jmethodID j_render_frame_id_;
1060 ScopedGlobalRef<jclass> j_frame_class_;
1061 jmethodID j_frame_ctor_id_;
1062 ScopedGlobalRef<jclass> j_byte_buffer_class_;
1065 } // anonymous namespace
1068 // Convenience macro defining JNI-accessible methods in the org.webrtc package.
1069 // Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1070 #define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1071 Java_org_webrtc_##name
1073 extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1074 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1076 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1078 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1081 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1083 g_class_reference_holder = new ClassReferenceHolder(jni);
1085 return JNI_VERSION_1_6;
1088 extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
1089 delete g_class_reference_holder;
1090 g_class_reference_holder = NULL;
1091 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
1094 static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
1095 jfieldID native_dc_id = GetFieldID(jni,
1096 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1097 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
1098 return reinterpret_cast<DataChannelInterface*>(j_d);
1101 JOW(jlong, DataChannel_registerObserverNative)(
1102 JNIEnv* jni, jobject j_dc, jobject j_observer) {
1103 talk_base::scoped_ptr<DataChannelObserverWrapper> observer(
1104 new DataChannelObserverWrapper(jni, j_observer));
1105 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
1106 return reinterpret_cast<jlong>(observer.release());
1109 JOW(void, DataChannel_unregisterObserverNative)(
1110 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1111 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1112 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1115 JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1116 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1119 JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1120 return JavaEnumFromIndex(
1121 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1124 JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1125 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1126 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1127 "buffered_amount overflowed jlong!");
1128 return static_cast<jlong>(buffered_amount);
1131 JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1132 ExtractNativeDC(jni, j_dc)->Close();
1135 JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1136 jbyteArray data, jboolean binary) {
1137 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1138 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1139 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1141 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1145 JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
1146 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
1149 JOW(void, Logging_nativeEnableTracing)(
1150 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1151 jint nativeSeverity) {
1152 std::string path = JavaToStdString(jni, j_path);
1153 if (nativeLevels != webrtc::kTraceNone) {
1154 webrtc::Trace::set_level_filter(nativeLevels);
1156 if (path != "logcat:") {
1158 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1159 "SetTraceFile failed");
1162 // Intentionally leak this to avoid needing to reason about its lifecycle.
1163 // It keeps no state and functions only as a dispatch point.
1164 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1168 talk_base::LogMessage::LogToDebug(nativeSeverity);
1171 JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
1172 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
1175 JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1176 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1180 JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
1181 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
1184 JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1185 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1188 JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1189 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1192 JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
1193 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1196 JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1197 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1198 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
1199 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1202 JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1203 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1204 return reinterpret_cast<MediaStreamInterface*>(pointer)
1205 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1208 JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1209 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1210 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
1211 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1214 JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1215 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1216 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
1217 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1220 JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1221 return JavaStringFromStdString(
1222 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1225 JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
1226 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
1229 JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1230 JNIEnv * jni, jclass, jobject j_observer) {
1231 return (jlong)new PCOJava(jni, j_observer);
1235 JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1236 JNIEnv* jni, jclass, jobject context) {
1237 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1238 bool failure = false;
1239 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm);
1240 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1245 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1246 JNIEnv* jni, jclass) {
1247 webrtc::Trace::CreateTrace();
1248 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1249 webrtc::CreatePeerConnectionFactory());
1250 return (jlong)factory.release();
1253 JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
1254 CHECK_RELEASE(reinterpret_cast<PeerConnectionFactoryInterface*>(j_p));
1255 webrtc::Trace::ReturnTrace();
1258 JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1259 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1260 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1261 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1262 talk_base::scoped_refptr<MediaStreamInterface> stream(
1263 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1264 return (jlong)stream.release();
1267 JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1268 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1269 jobject j_constraints) {
1270 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1271 new ConstraintsWrapper(jni, j_constraints));
1272 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1273 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1274 talk_base::scoped_refptr<VideoSourceInterface> source(
1275 factory->CreateVideoSource(
1276 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1277 constraints.get()));
1278 return (jlong)source.release();
1281 JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1282 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1283 jlong native_source) {
1284 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1285 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1286 talk_base::scoped_refptr<VideoTrackInterface> track(
1287 factory->CreateVideoTrack(
1288 JavaToStdString(jni, id),
1289 reinterpret_cast<VideoSourceInterface*>(native_source)));
1290 return (jlong)track.release();
1293 JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1294 JNIEnv* jni, jclass, jlong native_factory, jstring id) {
1295 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1296 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1297 talk_base::scoped_refptr<AudioTrackInterface> track(
1298 factory->CreateAudioTrack(JavaToStdString(jni, id), NULL));
1299 return (jlong)track.release();
1302 static void JavaIceServersToJsepIceServers(
1303 JNIEnv* jni, jobject j_ice_servers,
1304 PeerConnectionInterface::IceServers* ice_servers) {
1305 jclass list_class = GetObjectClass(jni, j_ice_servers);
1306 jmethodID iterator_id = GetMethodID(
1307 jni, list_class, "iterator", "()Ljava/util/Iterator;");
1308 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
1309 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1310 jmethodID iterator_has_next = GetMethodID(
1311 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
1312 jmethodID iterator_next = GetMethodID(
1313 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
1314 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
1315 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1316 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
1317 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1318 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
1319 jfieldID j_ice_server_uri_id =
1320 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
1321 jfieldID j_ice_server_username_id =
1322 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
1323 jfieldID j_ice_server_password_id =
1324 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
1325 jstring uri = reinterpret_cast<jstring>(
1326 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
1327 jstring username = reinterpret_cast<jstring>(
1328 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
1329 jstring password = reinterpret_cast<jstring>(
1330 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
1331 PeerConnectionInterface::IceServer server;
1332 server.uri = JavaToStdString(jni, uri);
1333 server.username = JavaToStdString(jni, username);
1334 server.password = JavaToStdString(jni, password);
1335 ice_servers->push_back(server);
1337 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1340 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
1341 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
1342 jobject j_constraints, jlong observer_p) {
1343 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
1344 reinterpret_cast<PeerConnectionFactoryInterface*>(factory));
1345 PeerConnectionInterface::IceServers servers;
1346 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
1347 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
1348 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
1349 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
1350 servers, observer->constraints(), NULL, observer));
1351 return (jlong)pc.release();
1354 static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
1355 JNIEnv* jni, jobject j_pc) {
1356 jfieldID native_pc_id = GetFieldID(jni,
1357 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
1358 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
1359 return talk_base::scoped_refptr<PeerConnectionInterface>(
1360 reinterpret_cast<PeerConnectionInterface*>(j_p));
1363 JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
1364 const SessionDescriptionInterface* sdp =
1365 ExtractNativePC(jni, j_pc)->local_description();
1366 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1369 JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
1370 const SessionDescriptionInterface* sdp =
1371 ExtractNativePC(jni, j_pc)->remote_description();
1372 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1375 JOW(jobject, PeerConnection_createDataChannel)(
1376 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
1377 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
1378 talk_base::scoped_refptr<DataChannelInterface> channel(
1379 ExtractNativePC(jni, j_pc)->CreateDataChannel(
1380 JavaToStdString(jni, j_label), &init));
1381 // Mustn't pass channel.get() directly through NewObject to avoid reading its
1382 // vararg parameter as 64-bit and reading memory that doesn't belong to the
1383 // 32-bit parameter.
1384 jlong nativeChannelPtr = jlongFromPointer(channel.get());
1385 CHECK(nativeChannelPtr, "Failed to create DataChannel");
1386 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
1387 jmethodID j_data_channel_ctor = GetMethodID(
1388 jni, j_data_channel_class, "<init>", "(J)V");
1389 jobject j_channel = jni->NewObject(
1390 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
1391 CHECK_EXCEPTION(jni, "error during NewObject");
1392 // Channel is now owned by Java object, and will be freed from there.
1393 int bumped_count = channel->AddRef();
1394 CHECK(bumped_count == 2, "Unexpected refcount");
1398 JOW(void, PeerConnection_createOffer)(
1399 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1400 ConstraintsWrapper* constraints =
1401 new ConstraintsWrapper(jni, j_constraints);
1402 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1403 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1404 jni, j_observer, constraints));
1405 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
1408 JOW(void, PeerConnection_createAnswer)(
1409 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1410 ConstraintsWrapper* constraints =
1411 new ConstraintsWrapper(jni, j_constraints);
1412 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1413 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1414 jni, j_observer, constraints));
1415 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
1418 // Helper to create a SessionDescriptionInterface from a SessionDescription.
1419 static SessionDescriptionInterface* JavaSdpToNativeSdp(
1420 JNIEnv* jni, jobject j_sdp) {
1421 jfieldID j_type_id = GetFieldID(
1422 jni, GetObjectClass(jni, j_sdp), "type",
1423 "Lorg/webrtc/SessionDescription$Type;");
1424 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
1425 jmethodID j_canonical_form_id = GetMethodID(
1426 jni, GetObjectClass(jni, j_type), "canonicalForm",
1427 "()Ljava/lang/String;");
1428 jstring j_type_string = (jstring)jni->CallObjectMethod(
1429 j_type, j_canonical_form_id);
1430 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1431 std::string std_type = JavaToStdString(jni, j_type_string);
1433 jfieldID j_description_id = GetFieldID(
1434 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
1435 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
1436 std::string std_description = JavaToStdString(jni, j_description);
1438 return webrtc::CreateSessionDescription(
1439 std_type, std_description, NULL);
1442 JOW(void, PeerConnection_setLocalDescription)(
1443 JNIEnv* jni, jobject j_pc,
1444 jobject j_observer, jobject j_sdp) {
1445 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1446 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1447 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1448 ExtractNativePC(jni, j_pc)->SetLocalDescription(
1449 observer, JavaSdpToNativeSdp(jni, j_sdp));
1452 JOW(void, PeerConnection_setRemoteDescription)(
1453 JNIEnv* jni, jobject j_pc,
1454 jobject j_observer, jobject j_sdp) {
1455 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1456 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1457 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1458 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
1459 observer, JavaSdpToNativeSdp(jni, j_sdp));
1462 JOW(jboolean, PeerConnection_updateIce)(
1463 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
1464 PeerConnectionInterface::IceServers ice_servers;
1465 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
1466 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1467 new ConstraintsWrapper(jni, j_constraints));
1468 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
1471 JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
1472 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
1473 jint j_sdp_mline_index, jstring j_candidate_sdp) {
1474 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
1475 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
1476 talk_base::scoped_ptr<IceCandidateInterface> candidate(
1477 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
1478 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
1481 JOW(jboolean, PeerConnection_nativeAddLocalStream)(
1482 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
1483 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1484 new ConstraintsWrapper(jni, j_constraints));
1485 return ExtractNativePC(jni, j_pc)->AddStream(
1486 reinterpret_cast<MediaStreamInterface*>(native_stream),
1490 JOW(void, PeerConnection_nativeRemoveLocalStream)(
1491 JNIEnv* jni, jobject j_pc, jlong native_stream) {
1492 ExtractNativePC(jni, j_pc)->RemoveStream(
1493 reinterpret_cast<MediaStreamInterface*>(native_stream));
1496 JOW(bool, PeerConnection_nativeGetStats)(
1497 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
1498 talk_base::scoped_refptr<StatsObserverWrapper> observer(
1499 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
1500 return ExtractNativePC(jni, j_pc)->GetStats(
1501 observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
1504 JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
1505 PeerConnectionInterface::SignalingState state =
1506 ExtractNativePC(jni, j_pc)->signaling_state();
1507 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
1510 JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
1511 PeerConnectionInterface::IceConnectionState state =
1512 ExtractNativePC(jni, j_pc)->ice_connection_state();
1513 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
1516 JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
1517 PeerConnectionInterface::IceGatheringState state =
1518 ExtractNativePC(jni, j_pc)->ice_gathering_state();
1519 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
1522 JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1523 ExtractNativePC(jni, j_pc)->Close();
1527 JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1528 talk_base::scoped_refptr<MediaSourceInterface> p(
1529 reinterpret_cast<MediaSourceInterface*>(j_p));
1530 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
1533 JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
1534 JNIEnv* jni, jclass, jstring j_device_name) {
1535 std::string device_name = JavaToStdString(jni, j_device_name);
1536 talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
1537 cricket::DeviceManagerFactory::Create());
1538 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
1539 cricket::Device device;
1540 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
1541 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
1544 talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1545 device_manager->CreateVideoCapturer(device));
1546 return (jlong)capturer.release();
1549 JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
1550 JNIEnv* jni, jclass, int x, int y) {
1551 talk_base::scoped_ptr<VideoRendererWrapper> renderer(
1552 VideoRendererWrapper::Create(
1553 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
1554 return (jlong)renderer.release();
1557 JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
1558 JNIEnv* jni, jclass, jobject j_callbacks) {
1559 talk_base::scoped_ptr<JavaVideoRendererWrapper> renderer(
1560 new JavaVideoRendererWrapper(jni, j_callbacks));
1561 return (jlong)renderer.release();
1564 JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
1565 cricket::VideoCapturer* capturer =
1566 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
1567 talk_base::scoped_ptr<cricket::VideoFormatPod> format(
1568 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
1570 return jlongFromPointer(format.release());
1573 JOW(void, VideoSource_restart)(
1574 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
1575 talk_base::scoped_ptr<cricket::VideoFormatPod> format(
1576 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
1577 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
1578 StartCapturing(cricket::VideoFormat(*format));
1581 JOW(void, VideoSource_freeNativeVideoFormat)(
1582 JNIEnv* jni, jclass, jlong j_p) {
1583 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
1586 JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
1587 return JavaStringFromStdString(
1588 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
1591 JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
1592 return JavaStringFromStdString(
1593 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
1596 JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
1597 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
1600 JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1601 return JavaEnumFromIndex(
1603 "MediaStreamTrack$State",
1604 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
1607 JOW(jboolean, MediaStreamTrack_nativeSetState)(
1608 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
1609 MediaStreamTrackInterface::TrackState new_state =
1610 (MediaStreamTrackInterface::TrackState)j_new_state;
1611 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1612 ->set_state(new_state);
1615 JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
1616 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
1617 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
1618 ->set_enabled(enabled);
1621 JOW(void, VideoTrack_nativeAddRenderer)(
1622 JNIEnv* jni, jclass,
1623 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1624 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
1625 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1628 JOW(void, VideoTrack_nativeRemoveRenderer)(
1629 JNIEnv* jni, jclass,
1630 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1631 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
1632 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));