- add third_party src.
[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
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"
79
80 #ifdef ANDROID
81 #include "webrtc/system_wrappers/interface/logcat_trace_context.h"
82 using webrtc::LogcatTraceContext;
83 #endif
84
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;
110
111 // Abort the process if |x| is false, emitting |msg|.
112 #define CHECK(x, msg)                                                          \
113   if (x) {} else {                                                             \
114     LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg;               \
115     abort();                                                                   \
116   }
117 // Abort the process if |jni| has a Java exception pending, emitting |msg|.
118 #define CHECK_EXCEPTION(jni, msg)                                              \
119   if (0) {} else {                                                             \
120     if (jni->ExceptionCheck()) {                                               \
121       jni->ExceptionDescribe();                                                \
122       jni->ExceptionClear();                                                   \
123       CHECK(0, msg);                                                           \
124     }                                                                          \
125   }
126
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)                                        \
130   do {                                                            \
131     int count = (ptr)->Release();                                 \
132     if (count != 0) {                                             \
133       LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr)   \
134                     << ": " << count;                             \
135     }                                                             \
136     CHECK(!count, "Unexpected refcount");                         \
137   } while (0)
138
139 namespace {
140
141 static JavaVM* g_jvm = NULL;  // Set in JNI_OnLoad().
142
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.
145
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);
152 }
153
154 // Return the current thread's name.
155 static std::string GetThreadName() {
156   char name[17];
157   CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
158   name[16] = '\0';
159   return std::string(name);
160 }
161
162 static void ThreadDestructor(void* unused) {
163   jint status = g_jvm->DetachCurrentThread();
164   CHECK(status == JNI_OK, "Failed to detach thread: " << status);
165 }
166
167 static void CreateJNIPtrKey() {
168   CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
169         "pthread_key_create");
170 }
171
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),
175         "pthread_once");
176   JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
177   if (jni == NULL) {
178 #ifdef _JAVASOFT_JNI_H_  // Oracle's jni.h violates the JNI spec!
179     void* env;
180 #else
181     JNIEnv* env;
182 #endif
183     char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
184     JavaVMAttachArgs args;
185     args.version = JNI_VERSION_1_6;
186     args.name = name;
187     args.group = NULL;
188     CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
189     free(name);
190     CHECK(env, "AttachCurrentThread handed back NULL!");
191     jni = reinterpret_cast<JNIEnv*>(env);
192     CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
193   }
194   return jni;
195 }
196
197 // Return a |jlong| that will automatically convert back to |ptr| when assigned
198 // to a |uint64|
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())
206     return u64;
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.
212   return i64;
213 }
214
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 {
220  public:
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");
241   }
242
243   ~ClassReferenceHolder() {
244     CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
245   }
246
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);
251     }
252     classes_.clear();
253   }
254
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);
258     return it->second;
259   }
260
261  private:
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);
271   }
272
273   std::map<std::string, jclass> classes_;
274 };
275
276 // Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
277 static ClassReferenceHolder* g_class_reference_holder = NULL;
278
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);
284   CHECK_EXCEPTION(jni,
285                   "error during GetMethodID: " << name << ", " << signature);
286   CHECK(m, name << ", " << signature);
287   return m;
288 }
289
290 jmethodID GetStaticMethodID(
291     JNIEnv* jni, jclass c, const char* name, const char* signature) {
292   jmethodID m = jni->GetStaticMethodID(c, name, signature);
293   CHECK_EXCEPTION(jni,
294                   "error during GetStaticMethodID: "
295                   << name << ", " << signature);
296   CHECK(m, name << ", " << signature);
297   return m;
298 }
299
300 jfieldID GetFieldID(
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);
305   return f;
306 }
307
308 jclass FindClass(JNIEnv* jni, const char* name) {
309   return g_class_reference_holder->GetClass(name);
310 }
311
312 jclass GetObjectClass(JNIEnv* jni, jobject object) {
313   jclass c = jni->GetObjectClass(object);
314   CHECK_EXCEPTION(jni, "error during GetObjectClass");
315   CHECK(c, "");
316   return c;
317 }
318
319 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
320   jobject o = jni->GetObjectField(object, id);
321   CHECK_EXCEPTION(jni, "error during GetObjectField");
322   CHECK(o, "");
323   return o;
324 }
325
326 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
327   return static_cast<jstring>(GetObjectField(jni, object, id));
328 }
329
330 jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
331   jlong l = jni->GetLongField(object, id);
332   CHECK_EXCEPTION(jni, "error during GetLongField");
333   return l;
334 }
335
336 jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
337   jint i = jni->GetIntField(object, id);
338   CHECK_EXCEPTION(jni, "error during GetIntField");
339   return i;
340 }
341
342 bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
343   jboolean b = jni->GetBooleanField(object, id);
344   CHECK_EXCEPTION(jni, "error during GetBooleanField");
345   return b;
346 }
347
348 jobject NewGlobalRef(JNIEnv* jni, jobject o) {
349   jobject ret = jni->NewGlobalRef(o);
350   CHECK_EXCEPTION(jni, "error during NewGlobalRef");
351   CHECK(ret, "");
352   return ret;
353 }
354
355 void DeleteGlobalRef(JNIEnv* jni, jobject o) {
356   jni->DeleteGlobalRef(o);
357   CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
358 }
359
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
362 // otherwise.
363 class WeakRef {
364  public:
365   WeakRef(JNIEnv* jni, jweak ref)
366       : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
367     CHECK_EXCEPTION(jni, "error during NewLocalRef");
368   }
369   ~WeakRef() {
370     if (obj_) {
371       jni_->DeleteLocalRef(obj_);
372       CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
373     }
374   }
375   jobject obj() { return obj_; }
376
377  private:
378   JNIEnv* const jni_;
379   jobject const obj_;
380 };
381
382 // Given a local ref, take ownership of it and delete the ref when this goes out
383 // of scope.
384 template<class T>  // T is jclass, jobject, jintArray, etc.
385 class ScopedLocalRef {
386  public:
387   ScopedLocalRef(JNIEnv* jni, T obj)
388       : jni_(jni), obj_(obj) {}
389   ~ScopedLocalRef() {
390     jni_->DeleteLocalRef(obj_);
391   }
392   T operator*() const {
393     return obj_;
394   }
395  private:
396   JNIEnv* jni_;
397   T obj_;
398 };
399
400 // Scoped holder for global Java refs.
401 template<class T>  // T is jclass, jobject, jintArray, etc.
402 class ScopedGlobalRef {
403  public:
404   explicit ScopedGlobalRef(JNIEnv* jni, T obj)
405       : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
406   ~ScopedGlobalRef() {
407     DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
408   }
409   T operator*() const {
410     return obj_;
411   }
412  private:
413   T obj_;
414 };
415
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(
425       jni,
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");
430   return ret;
431 }
432
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");
438   return jstr;
439 }
440
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");
449   std::string ret;
450   return ustr.toUTF8String(ret);
451 }
452
453 static DataChannelInit JavaDataChannelInitToNative(
454     JNIEnv* jni, jobject j_init) {
455   DataChannelInit init;
456
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");
467
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);
475
476   return init;
477 }
478
479 class ConstraintsWrapper;
480
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 {
485  public:
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")) {
501   }
502
503   virtual ~PCOJava() {}
504
505   virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
506     std::string sdp;
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");
521   }
522
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");
527   }
528
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");
538   }
539
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");
549   }
550
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");
560   }
561
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");
566
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_,
577                                             "audioTracks",
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");
585       CHECK(added, "");
586     }
587
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_,
598                                             "videoTracks",
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");
606       CHECK(added, "");
607     }
608     streams_[stream] = jni()->NewWeakGlobalRef(*j_stream);
609     CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
610
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");
615   }
616
617   virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
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     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");
636
637     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
638                               "(Lorg/webrtc/DataChannel;)V");
639     jni()->CallVoidMethod(*j_observer_global_, m, *j_channel);
640
641     // Channel is now owned by Java object, and will be freed from
642     // DataChannel.dispose().  Important that this be done _after_ the
643     // CallVoidMethod above as Java code might call back into native code and be
644     // surprised to see a refcount of 2.
645     int bumped_count = channel->AddRef();
646     CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
647
648     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
649   }
650
651   void SetConstraints(ConstraintsWrapper* constraints) {
652     CHECK(!constraints_.get(), "constraints already set!");
653     constraints_.reset(constraints);
654   }
655
656   const ConstraintsWrapper* constraints() { return constraints_.get(); }
657
658  private:
659   JNIEnv* jni() {
660     return AttachCurrentThreadIfNeeded();
661   }
662
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_;
676 };
677
678 // Wrapper for a Java MediaConstraints object.  Copies all needed data so when
679 // the constructor returns the Java object is no longer needed.
680 class ConstraintsWrapper : public MediaConstraintsInterface {
681  public:
682   ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
683     PopulateConstraintsFromJavaPairList(
684         jni, j_constraints, "mandatory", &mandatory_);
685     PopulateConstraintsFromJavaPairList(
686         jni, j_constraints, "optional", &optional_);
687   }
688
689   virtual ~ConstraintsWrapper() {}
690
691   // MediaConstraintsInterface.
692   virtual const Constraints& GetMandatory() const OVERRIDE {
693     return mandatory_;
694   }
695
696   virtual const Constraints& GetOptional() const OVERRIDE {
697     return optional_;
698   }
699
700  private:
701   // Helper for translating a List<Pair<String, String>> to a Constraints.
702   static void PopulateConstraintsFromJavaPairList(
703       JNIEnv* jni, jobject j_constraints,
704       const char* field_name, Constraints* field) {
705     jfieldID j_id = GetFieldID(jni,
706         GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
707     jobject j_list = GetObjectField(jni, j_constraints, j_id);
708     jmethodID j_iterator_id = GetMethodID(jni,
709         GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
710     jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
711     CHECK_EXCEPTION(jni, "error during CallObjectMethod");
712     jmethodID j_has_next = GetMethodID(jni,
713         GetObjectClass(jni, j_iterator), "hasNext", "()Z");
714     jmethodID j_next = GetMethodID(jni,
715         GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
716     while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
717       CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
718       jobject entry = jni->CallObjectMethod(j_iterator, j_next);
719       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
720       jmethodID get_key = GetMethodID(jni,
721           GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
722       jstring j_key = reinterpret_cast<jstring>(
723           jni->CallObjectMethod(entry, get_key));
724       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
725       jmethodID get_value = GetMethodID(jni,
726           GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
727       jstring j_value = reinterpret_cast<jstring>(
728           jni->CallObjectMethod(entry, get_value));
729       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
730       field->push_back(Constraint(JavaToStdString(jni, j_key),
731                                   JavaToStdString(jni, j_value)));
732     }
733     CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
734   }
735
736   Constraints mandatory_;
737   Constraints optional_;
738 };
739
740 static jobject JavaSdpFromNativeSdp(
741     JNIEnv* jni, const SessionDescriptionInterface* desc) {
742   std::string sdp;
743   CHECK(desc->ToString(&sdp), "got so far: " << sdp);
744   ScopedLocalRef<jstring> j_description(jni, JavaStringFromStdString(jni, sdp));
745
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");
756
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");
764   return j_sdp;
765 }
766
767 template <class T>  // T is one of {Create,Set}SessionDescriptionObserver.
768 class SdpObserverWrapper : public T {
769  public:
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)) {
775   }
776
777   virtual ~SdpObserverWrapper() {}
778
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");
784   }
785
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");
794   }
795
796  protected:
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");
806   }
807
808  private:
809   JNIEnv* jni() {
810     return AttachCurrentThreadIfNeeded();
811   }
812
813   talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
814   const ScopedGlobalRef<jobject> j_observer_global_;
815   const ScopedGlobalRef<jclass> j_observer_class_;
816 };
817
818 class CreateSdpObserverWrapper
819     : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
820  public:
821   CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
822                            ConstraintsWrapper* constraints)
823       : SdpObserverWrapper(jni, j_observer, constraints) {}
824
825   virtual void OnFailure(const std::string& error) OVERRIDE {
826     SdpObserverWrapper::OnFailure(std::string("Create"), error);
827   }
828 };
829
830 class SetSdpObserverWrapper
831     : public SdpObserverWrapper<SetSessionDescriptionObserver> {
832  public:
833   SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
834                         ConstraintsWrapper* constraints)
835       : SdpObserverWrapper(jni, j_observer, constraints) {}
836
837   virtual void OnFailure(const std::string& error) OVERRIDE {
838     SdpObserverWrapper::OnFailure(std::string("Set"), error);
839   }
840 };
841
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 {
845  public:
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")) {
856   }
857
858   virtual ~DataChannelObserverWrapper() {}
859
860   virtual void OnStateChange() OVERRIDE {
861     jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
862     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
863   }
864
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");
873   }
874
875  private:
876   JNIEnv* jni() {
877     return AttachCurrentThreadIfNeeded();
878   }
879
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_;
886 };
887
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 {
891  public:
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")) {
905   }
906
907   virtual ~StatsObserverWrapper() {}
908
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");
916   }
917
918  private:
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);
935     }
936     return reports_array;
937   }
938
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);
951     }
952     return j_values;
953   }
954
955   JNIEnv* jni() {
956     return AttachCurrentThreadIfNeeded();
957   }
958
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_;
965 };
966
967 // Adapter presenting a cricket::VideoRenderer as a
968 // webrtc::VideoRendererInterface.
969 class VideoRendererWrapper : public VideoRendererInterface {
970  public:
971   static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
972     if (renderer)
973       return new VideoRendererWrapper(renderer);
974     return NULL;
975   }
976
977   virtual ~VideoRendererWrapper() {}
978
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);
982   }
983
984   virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
985     renderer_->RenderFrame(frame);
986   }
987
988  private:
989   explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
990       : renderer_(renderer) {}
991
992   talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
993 };
994
995 // Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
996 // instance.
997 class JavaVideoRendererWrapper : public VideoRendererInterface {
998  public:
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")),
1006         j_frame_class_(jni,
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, "");
1012   }
1013
1014   virtual ~JavaVideoRendererWrapper() {}
1015
1016   virtual void SetSize(int width, int height) OVERRIDE {
1017     jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1018     CHECK_EXCEPTION(jni(), "");
1019   }
1020
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(), "");
1025   }
1026
1027  private:
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);
1051   }
1052
1053   JNIEnv* jni() {
1054     return AttachCurrentThreadIfNeeded();
1055   }
1056
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_;
1063 };
1064
1065 }  // anonymous namespace
1066
1067
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
1072
1073 extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1074   CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1075   g_jvm = jvm;
1076   CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1077
1078   CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1079
1080   JNIEnv* jni;
1081   if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1082     return -1;
1083   g_class_reference_holder = new ClassReferenceHolder(jni);
1084
1085   return JNI_VERSION_1_6;
1086 }
1087
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()");
1092 }
1093
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);
1099 }
1100
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());
1107 }
1108
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);
1113 }
1114
1115 JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1116   return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1117 }
1118
1119 JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1120   return JavaEnumFromIndex(
1121       jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1122 }
1123
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);
1129 }
1130
1131 JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1132   ExtractNativeDC(jni, j_dc)->Close();
1133 }
1134
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)),
1140       binary));
1141   jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1142   return ret;
1143 }
1144
1145 JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
1146   CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
1147 }
1148
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);
1155 #ifdef ANDROID
1156     if (path != "logcat:") {
1157 #endif
1158       CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1159             "SetTraceFile failed");
1160 #ifdef ANDROID
1161     } else {
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();
1165     }
1166 #endif
1167   }
1168   talk_base::LogMessage::LogToDebug(nativeSeverity);
1169 }
1170
1171 JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
1172   CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
1173 }
1174
1175 JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1176   PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1177   delete p;
1178 }
1179
1180 JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
1181   CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
1182 }
1183
1184 JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1185   delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1186 }
1187
1188 JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1189   delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1190 }
1191
1192 JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
1193   CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1194 }
1195
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));
1200 }
1201
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));
1206 }
1207
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));
1212 }
1213
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));
1218 }
1219
1220 JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1221   return JavaStringFromStdString(
1222       jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1223 }
1224
1225 JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
1226   CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
1227 }
1228
1229 JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1230     JNIEnv * jni, jclass, jobject j_observer) {
1231   return (jlong)new PCOJava(jni, j_observer);
1232 }
1233
1234 #ifdef ANDROID
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);
1241   return !failure;
1242 }
1243 #endif  // ANDROID
1244
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();
1251 }
1252
1253 JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
1254   CHECK_RELEASE(reinterpret_cast<PeerConnectionFactoryInterface*>(j_p));
1255   webrtc::Trace::ReturnTrace();
1256 }
1257
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();
1265 }
1266
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();
1279 }
1280
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();
1291 }
1292
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();
1300 }
1301
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);
1336   }
1337   CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1338 }
1339
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();
1352 }
1353
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));
1361 }
1362
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;
1367 }
1368
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;
1373 }
1374
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");
1395   return j_channel;
1396 }
1397
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);
1406 }
1407
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);
1416 }
1417
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);
1432
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);
1437
1438   return webrtc::CreateSessionDescription(
1439       std_type, std_description, NULL);
1440 }
1441
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));
1450 }
1451
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));
1460 }
1461
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());
1469 }
1470
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());
1479 }
1480
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),
1487       constraints.get());
1488 }
1489
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));
1494 }
1495
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));
1502 }
1503
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);
1508 }
1509
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);
1514 }
1515
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);
1520 }
1521
1522 JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1523   ExtractNativePC(jni, j_pc)->Close();
1524   return;
1525 }
1526
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());
1531 }
1532
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;
1542     return 0;
1543   }
1544   talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1545       device_manager->CreateVideoCapturer(device));
1546   return (jlong)capturer.release();
1547 }
1548
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();
1555 }
1556
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();
1562 }
1563
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()));
1569   capturer->Stop();
1570   return jlongFromPointer(format.release());
1571 }
1572
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));
1579 }
1580
1581 JOW(void, VideoSource_freeNativeVideoFormat)(
1582     JNIEnv* jni, jclass, jlong j_p) {
1583   delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
1584 }
1585
1586 JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
1587   return JavaStringFromStdString(
1588       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
1589 }
1590
1591 JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
1592   return JavaStringFromStdString(
1593       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
1594 }
1595
1596 JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
1597   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
1598 }
1599
1600 JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1601   return JavaEnumFromIndex(
1602       jni,
1603       "MediaStreamTrack$State",
1604       reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
1605 }
1606
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);
1613 }
1614
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);
1619 }
1620
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));
1626 }
1627
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));
1633 }