Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / app / webrtc / java / jni / peerconnection_jni.cc
1 /*
2  * libjingle
3  * Copyright 2013, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 // Hints for future visitors:
29 // This entire file is an implementation detail of the org.webrtc Java package,
30 // the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31 // The layout of this file is roughly:
32 // - various helper C++ functions & classes that wrap Java counterparts and
33 //   expose a C++ interface that can be passed to the C++ PeerConnection APIs
34 // - implementations of methods declared "static" in the Java package (named
35 //   things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36 //   the JNI spec).
37 //
38 // Lifecycle notes: objects are owned where they will be called; in other words
39 // FooObservers are owned by C++-land, and user-callable objects (e.g.
40 // PeerConnection and VideoTrack) are owned by Java-land.
41 // When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42 // ref simulating the jlong held in Java-land, and then Release()s the ref in
43 // the respective free call.  Sometimes this AddRef is implicit in the
44 // construction of a scoped_refptr<> which is then .release()d.
45 // Any persistent (non-local) references from C++ to Java must be global or weak
46 // (in which case they must be checked before use)!
47 //
48 // Exception notes: pretty much all JNI calls can throw Java exceptions, so each
49 // call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50 // call.  In this file this is done in CHECK_EXCEPTION, making for much easier
51 // debugging in case of failure (the alternative is to wait for control to
52 // return to the Java frame that called code in this file, at which point it's
53 // impossible to tell which JNI call broke).
54
55 #include <jni.h>
56 #undef JNIEXPORT
57 #define JNIEXPORT __attribute__((visibility("default")))
58
59 #include <asm/unistd.h>
60 #include <limits>
61 #include <map>
62 #include <sys/prctl.h>
63 #include <sys/syscall.h>
64 #include <unistd.h>
65
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"
80
81 #ifdef ANDROID
82 #include "webrtc/system_wrappers/interface/logcat_trace_context.h"
83 using webrtc::LogcatTraceContext;
84 #endif
85
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;
111
112 // Abort the process if |x| is false, emitting |msg|.
113 #define CHECK(x, msg)                                                          \
114   if (x) {} else {                                                             \
115     LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg;               \
116     abort();                                                                   \
117   }
118 // Abort the process if |jni| has a Java exception pending, emitting |msg|.
119 #define CHECK_EXCEPTION(jni, msg)                                              \
120   if (0) {} else {                                                             \
121     if (jni->ExceptionCheck()) {                                               \
122       jni->ExceptionDescribe();                                                \
123       jni->ExceptionClear();                                                   \
124       CHECK(0, msg);                                                           \
125     }                                                                          \
126   }
127
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)                                        \
131   do {                                                            \
132     int count = (ptr)->Release();                                 \
133     if (count != 0) {                                             \
134       LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr)   \
135                     << ": " << count;                             \
136     }                                                             \
137     CHECK(!count, "Unexpected refcount");                         \
138   } while (0)
139
140 namespace {
141
142 static JavaVM* g_jvm = NULL;  // Set in JNI_OnLoad().
143
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.
146
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);
153 }
154
155 // Return the current thread's name.
156 static std::string GetThreadName() {
157   char name[17];
158   CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
159   name[16] = '\0';
160   return std::string(name);
161 }
162
163 static void ThreadDestructor(void* unused) {
164   jint status = g_jvm->DetachCurrentThread();
165   CHECK(status == JNI_OK, "Failed to detach thread: " << status);
166 }
167
168 static void CreateJNIPtrKey() {
169   CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
170         "pthread_key_create");
171 }
172
173 // Deal with difference in signatures between Oracle's jni.h and Android's.
174 static JNIEnv* AttachCurrentThreadIfNeeded() {
175   CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
176         "pthread_once");
177   JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
178   if (jni == NULL) {
179 #ifdef _JAVASOFT_JNI_H_  // Oracle's jni.h violates the JNI spec!
180     void* env;
181 #else
182     JNIEnv* env;
183 #endif
184     char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
185     JavaVMAttachArgs args;
186     args.version = JNI_VERSION_1_6;
187     args.name = name;
188     args.group = NULL;
189     CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
190     free(name);
191     CHECK(env, "AttachCurrentThread handed back NULL!");
192     jni = reinterpret_cast<JNIEnv*>(env);
193     CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
194   }
195   return jni;
196 }
197
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);
209   return ret;
210 }
211
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 {
217  public:
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");
238   }
239
240   ~ClassReferenceHolder() {
241     CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
242   }
243
244   void FreeReferences(JNIEnv* jni) {
245     for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
246          it != classes_.end(); ++it) {
247       jni->DeleteGlobalRef(it->second);
248     }
249     classes_.clear();
250   }
251
252   jclass GetClass(const std::string& name) {
253     std::map<std::string, jclass>::iterator it = classes_.find(name);
254     CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
255     return it->second;
256   }
257
258  private:
259   void LoadClass(JNIEnv* jni, const std::string& name) {
260     jclass localRef = jni->FindClass(name.c_str());
261     CHECK_EXCEPTION(jni, "error during FindClass: " << name);
262     CHECK(localRef, name);
263     jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
264     CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
265     CHECK(globalRef, name);
266     bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
267     CHECK(inserted, "Duplicate class name: " << name);
268   }
269
270   std::map<std::string, jclass> classes_;
271 };
272
273 // Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
274 static ClassReferenceHolder* g_class_reference_holder = NULL;
275
276 // JNIEnv-helper methods that CHECK success: no Java exception thrown and found
277 // object/class/method/field is non-null.
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);
281   CHECK_EXCEPTION(jni,
282                   "error during GetMethodID: " << name << ", " << signature);
283   CHECK(m, name << ", " << signature);
284   return m;
285 }
286
287 jmethodID GetStaticMethodID(
288     JNIEnv* jni, jclass c, const char* name, const char* signature) {
289   jmethodID m = jni->GetStaticMethodID(c, name, signature);
290   CHECK_EXCEPTION(jni,
291                   "error during GetStaticMethodID: "
292                   << name << ", " << signature);
293   CHECK(m, name << ", " << signature);
294   return m;
295 }
296
297 jfieldID GetFieldID(
298     JNIEnv* jni, jclass c, const char* name, const char* signature) {
299   jfieldID f = jni->GetFieldID(c, name, signature);
300   CHECK_EXCEPTION(jni, "error during GetFieldID");
301   CHECK(f, name << ", " << signature);
302   return f;
303 }
304
305 jclass FindClass(JNIEnv* jni, const char* name) {
306   return g_class_reference_holder->GetClass(name);
307 }
308
309 jclass GetObjectClass(JNIEnv* jni, jobject object) {
310   jclass c = jni->GetObjectClass(object);
311   CHECK_EXCEPTION(jni, "error during GetObjectClass");
312   CHECK(c, "");
313   return c;
314 }
315
316 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
317   jobject o = jni->GetObjectField(object, id);
318   CHECK_EXCEPTION(jni, "error during GetObjectField");
319   CHECK(o, "");
320   return o;
321 }
322
323 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
324   return static_cast<jstring>(GetObjectField(jni, object, id));
325 }
326
327 jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
328   jlong l = jni->GetLongField(object, id);
329   CHECK_EXCEPTION(jni, "error during GetLongField");
330   return l;
331 }
332
333 jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
334   jint i = jni->GetIntField(object, id);
335   CHECK_EXCEPTION(jni, "error during GetIntField");
336   return i;
337 }
338
339 bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
340   jboolean b = jni->GetBooleanField(object, id);
341   CHECK_EXCEPTION(jni, "error during GetBooleanField");
342   return b;
343 }
344
345 jobject NewGlobalRef(JNIEnv* jni, jobject o) {
346   jobject ret = jni->NewGlobalRef(o);
347   CHECK_EXCEPTION(jni, "error during NewGlobalRef");
348   CHECK(ret, "");
349   return ret;
350 }
351
352 void DeleteGlobalRef(JNIEnv* jni, jobject o) {
353   jni->DeleteGlobalRef(o);
354   CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
355 }
356
357 // Given a jweak reference, allocate a (strong) local reference scoped to the
358 // lifetime of this object if the weak reference is still valid, or NULL
359 // otherwise.
360 class WeakRef {
361  public:
362   WeakRef(JNIEnv* jni, jweak ref)
363       : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
364     CHECK_EXCEPTION(jni, "error during NewLocalRef");
365   }
366   ~WeakRef() {
367     if (obj_) {
368       jni_->DeleteLocalRef(obj_);
369       CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
370     }
371   }
372   jobject obj() { return obj_; }
373
374  private:
375   JNIEnv* const jni_;
376   jobject const obj_;
377 };
378
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 {
383  public:
384   explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
385     CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
386   }
387   ~ScopedLocalRefFrame() {
388     jni_->PopLocalFrame(NULL);
389   }
390
391  private:
392   JNIEnv* jni_;
393 };
394
395 // Scoped holder for global Java refs.
396 template<class T>  // T is jclass, jobject, jintArray, etc.
397 class ScopedGlobalRef {
398  public:
399   explicit ScopedGlobalRef(JNIEnv* jni, T obj)
400       : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
401   ~ScopedGlobalRef() {
402     DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
403   }
404   T operator*() const {
405     return obj_;
406   }
407  private:
408   T obj_;
409 };
410
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");
424   return ret;
425 }
426
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");
432   return jstr;
433 }
434
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");
443   std::string ret;
444   return ustr.toUTF8String(ret);
445 }
446
447 static DataChannelInit JavaDataChannelInitToNative(
448     JNIEnv* jni, jobject j_init) {
449   DataChannelInit init;
450
451   jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
452   jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
453   jfieldID max_retransmit_time_id =
454       GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
455   jfieldID max_retransmits_id =
456       GetFieldID(jni, j_init_class, "maxRetransmits", "I");
457   jfieldID protocol_id =
458       GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
459   jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
460   jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
461
462   init.ordered = GetBooleanField(jni, j_init, ordered_id);
463   init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
464   init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
465   init.protocol = JavaToStdString(
466       jni, GetStringField(jni, j_init, protocol_id));
467   init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
468   init.id = GetIntField(jni, j_init, id_id);
469
470   return init;
471 }
472
473 class ConstraintsWrapper;
474
475 // Adapter between the C++ PeerConnectionObserver interface and the Java
476 // PeerConnection.Observer interface.  Wraps an instance of the Java interface
477 // and dispatches C++ callbacks to Java.
478 class PCOJava : public PeerConnectionObserver {
479  public:
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")) {
495   }
496
497   virtual ~PCOJava() {}
498
499   virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
500     ScopedLocalRefFrame local_ref_frame(jni());
501     std::string sdp;
502     CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
503     jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
504     jmethodID ctor = GetMethodID(jni(), candidate_class,
505         "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
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");
515   }
516
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");
522   }
523
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");
534   }
535
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");
546   }
547
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");
558   }
559
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");
565
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_,
575                                             "audioTracks",
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),
580                                   "add",
581                                   "(Ljava/lang/Object;)Z");
582       jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
583       CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
584       CHECK(added, "");
585     }
586
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_,
596                                             "videoTracks",
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),
601                                   "add",
602                                   "(Ljava/lang/Object;)Z");
603       jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
604       CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
605       CHECK(added, "");
606     }
607     streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
608     CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
609
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");
614   }
615
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);
620
621     WeakRef s(jni(), it->second);
622     streams_.erase(it);
623     if (!s.obj())
624       return;
625
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");
630   }
631
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");
637
638     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
639                               "(Lorg/webrtc/DataChannel;)V");
640     jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
641
642     // Channel is now owned by Java object, and will be freed from
643     // DataChannel.dispose().  Important that this be done _after_ the
644     // CallVoidMethod above as Java code might call back into native code and be
645     // surprised to see a refcount of 2.
646     int bumped_count = channel->AddRef();
647     CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
648
649     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
650   }
651
652   virtual void OnRenegotiationNeeded() OVERRIDE {
653     ScopedLocalRefFrame local_ref_frame(jni());
654     jmethodID m =
655         GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
656     jni()->CallVoidMethod(*j_observer_global_, m);
657     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
658   }
659
660   void SetConstraints(ConstraintsWrapper* constraints) {
661     CHECK(!constraints_.get(), "constraints already set!");
662     constraints_.reset(constraints);
663   }
664
665   const ConstraintsWrapper* constraints() { return constraints_.get(); }
666
667  private:
668   JNIEnv* jni() {
669     return AttachCurrentThreadIfNeeded();
670   }
671
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_;
685 };
686
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 {
690  public:
691   ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
692     PopulateConstraintsFromJavaPairList(
693         jni, j_constraints, "mandatory", &mandatory_);
694     PopulateConstraintsFromJavaPairList(
695         jni, j_constraints, "optional", &optional_);
696   }
697
698   virtual ~ConstraintsWrapper() {}
699
700   // MediaConstraintsInterface.
701   virtual const Constraints& GetMandatory() const OVERRIDE {
702     return mandatory_;
703   }
704
705   virtual const Constraints& GetOptional() const OVERRIDE {
706     return optional_;
707   }
708
709  private:
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)));
741     }
742     CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
743   }
744
745   Constraints mandatory_;
746   Constraints optional_;
747 };
748
749 static jobject JavaSdpFromNativeSdp(
750     JNIEnv* jni, const SessionDescriptionInterface* desc) {
751   std::string sdp;
752   CHECK(desc->ToString(&sdp), "got so far: " << sdp);
753   jstring j_description = JavaStringFromStdString(jni, sdp);
754
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");
764
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");
772   return j_sdp;
773 }
774
775 template <class T>  // T is one of {Create,Set}SessionDescriptionObserver.
776 class SdpObserverWrapper : public T {
777  public:
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)) {
783   }
784
785   virtual ~SdpObserverWrapper() {}
786
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");
793   }
794
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");
804   }
805
806  protected:
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");
815   }
816
817   JNIEnv* jni() {
818     return AttachCurrentThreadIfNeeded();
819   }
820
821  private:
822   talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
823   const ScopedGlobalRef<jobject> j_observer_global_;
824   const ScopedGlobalRef<jclass> j_observer_class_;
825 };
826
827 class CreateSdpObserverWrapper
828     : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
829  public:
830   CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
831                            ConstraintsWrapper* constraints)
832       : SdpObserverWrapper(jni, j_observer, constraints) {}
833
834   virtual void OnFailure(const std::string& error) OVERRIDE {
835     ScopedLocalRefFrame local_ref_frame(jni());
836     SdpObserverWrapper::OnFailure(std::string("Create"), error);
837   }
838 };
839
840 class SetSdpObserverWrapper
841     : public SdpObserverWrapper<SetSessionDescriptionObserver> {
842  public:
843   SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
844                         ConstraintsWrapper* constraints)
845       : SdpObserverWrapper(jni, j_observer, constraints) {}
846
847   virtual void OnFailure(const std::string& error) OVERRIDE {
848     ScopedLocalRefFrame local_ref_frame(jni());
849     SdpObserverWrapper::OnFailure(std::string("Set"), error);
850   }
851 };
852
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 {
856  public:
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")) {
867   }
868
869   virtual ~DataChannelObserverWrapper() {}
870
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");
875   }
876
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");
886   }
887
888  private:
889   JNIEnv* jni() {
890     return AttachCurrentThreadIfNeeded();
891   }
892
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_;
899 };
900
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 {
904  public:
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")) {
918   }
919
920   virtual ~StatsObserverWrapper() {}
921
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");
929   }
930
931  private:
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_,
944                                         j_id,
945                                         j_type,
946                                         report.timestamp,
947                                         j_values);
948       jni->SetObjectArrayElement(reports_array, i, j_report);
949     }
950     return reports_array;
951   }
952
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);
964     }
965     return j_values;
966   }
967
968   JNIEnv* jni() {
969     return AttachCurrentThreadIfNeeded();
970   }
971
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_;
978 };
979
980 // Adapter presenting a cricket::VideoRenderer as a
981 // webrtc::VideoRendererInterface.
982 class VideoRendererWrapper : public VideoRendererInterface {
983  public:
984   static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
985     if (renderer)
986       return new VideoRendererWrapper(renderer);
987     return NULL;
988   }
989
990   virtual ~VideoRendererWrapper() {}
991
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);
996   }
997
998   virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
999     ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
1000     renderer_->RenderFrame(frame);
1001   }
1002
1003  private:
1004   explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1005       : renderer_(renderer) {}
1006
1007   talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
1008 };
1009
1010 // Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1011 // instance.
1012 class JavaVideoRendererWrapper : public VideoRendererInterface {
1013  public:
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")),
1021         j_frame_class_(jni,
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, "");
1027   }
1028
1029   virtual ~JavaVideoRendererWrapper() {}
1030
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(), "");
1035   }
1036
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(), "");
1042   }
1043
1044  private:
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);
1067   }
1068
1069   JNIEnv* jni() {
1070     return AttachCurrentThreadIfNeeded();
1071   }
1072
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_;
1079 };
1080
1081 }  // anonymous namespace
1082
1083
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
1088
1089 extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1090   CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1091   g_jvm = jvm;
1092   CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1093
1094   CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1095
1096   JNIEnv* jni;
1097   if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1098     return -1;
1099   g_class_reference_holder = new ClassReferenceHolder(jni);
1100
1101   return JNI_VERSION_1_6;
1102 }
1103
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()");
1108 }
1109
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);
1115 }
1116
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());
1123 }
1124
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);
1129 }
1130
1131 JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1132   return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1133 }
1134
1135 JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1136   return JavaEnumFromIndex(
1137       jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1138 }
1139
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);
1145 }
1146
1147 JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1148   ExtractNativeDC(jni, j_dc)->Close();
1149 }
1150
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)),
1156       binary));
1157   jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1158   return ret;
1159 }
1160
1161 JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
1162   CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
1163 }
1164
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);
1171 #ifdef ANDROID
1172     if (path != "logcat:") {
1173 #endif
1174       CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1175             "SetTraceFile failed");
1176 #ifdef ANDROID
1177     } else {
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();
1181     }
1182 #endif
1183   }
1184   talk_base::LogMessage::LogToDebug(nativeSeverity);
1185 }
1186
1187 JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
1188   CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
1189 }
1190
1191 JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1192   PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1193   delete p;
1194 }
1195
1196 JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
1197   CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
1198 }
1199
1200 JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1201   delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1202 }
1203
1204 JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1205   delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1206 }
1207
1208 JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
1209   CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1210 }
1211
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));
1216 }
1217
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));
1222 }
1223
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));
1228 }
1229
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));
1234 }
1235
1236 JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1237   return JavaStringFromStdString(
1238       jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1239 }
1240
1241 JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
1242   CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
1243 }
1244
1245 JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1246     JNIEnv * jni, jclass, jobject j_observer) {
1247   return (jlong)new PCOJava(jni, j_observer);
1248 }
1249
1250 #ifdef ANDROID
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);
1257   return !failure;
1258 }
1259 #endif  // ANDROID
1260
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();
1267 }
1268
1269 JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
1270   CHECK_RELEASE(reinterpret_cast<PeerConnectionFactoryInterface*>(j_p));
1271   webrtc::Trace::ReturnTrace();
1272 }
1273
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();
1281 }
1282
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();
1295 }
1296
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();
1307 }
1308
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();
1316 }
1317
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);
1352   }
1353   CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1354 }
1355
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();
1368 }
1369
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));
1377 }
1378
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;
1383 }
1384
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;
1389 }
1390
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");
1411   return j_channel;
1412 }
1413
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);
1422 }
1423
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);
1432 }
1433
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);
1448
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);
1453
1454   return webrtc::CreateSessionDescription(
1455       std_type, std_description, NULL);
1456 }
1457
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));
1466 }
1467
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));
1476 }
1477
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());
1485 }
1486
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());
1495 }
1496
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),
1503       constraints.get());
1504 }
1505
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));
1510 }
1511
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));
1518 }
1519
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);
1524 }
1525
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);
1530 }
1531
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);
1536 }
1537
1538 JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1539   ExtractNativePC(jni, j_pc)->Close();
1540   return;
1541 }
1542
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());
1547 }
1548
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;
1558     return 0;
1559   }
1560   talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1561       device_manager->CreateVideoCapturer(device));
1562   return (jlong)capturer.release();
1563 }
1564
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();
1571 }
1572
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();
1578 }
1579
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()));
1585   capturer->Stop();
1586   return jlongFromPointer(format.release());
1587 }
1588
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));
1595 }
1596
1597 JOW(void, VideoSource_freeNativeVideoFormat)(
1598     JNIEnv* jni, jclass, jlong j_p) {
1599   delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
1600 }
1601
1602 JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
1603   return JavaStringFromStdString(
1604       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
1605 }
1606
1607 JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
1608   return JavaStringFromStdString(
1609       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
1610 }
1611
1612 JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
1613   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
1614 }
1615
1616 JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1617   return JavaEnumFromIndex(
1618       jni,
1619       "MediaStreamTrack$State",
1620       reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
1621 }
1622
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);
1629 }
1630
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);
1635 }
1636
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));
1642 }
1643
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));
1649 }