Upstream version 7.36.149.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/bind.h"
70 #include "talk/base/logging.h"
71 #include "talk/base/messagequeue.h"
72 #include "talk/base/ssladapter.h"
73 #include "talk/media/base/videocapturer.h"
74 #include "talk/media/base/videorenderer.h"
75 #include "talk/media/devices/videorendererfactory.h"
76 #include "talk/media/webrtc/webrtcvideocapturer.h"
77 #include "talk/media/webrtc/webrtcvideoencoderfactory.h"
78 #include "third_party/icu/source/common/unicode/unistr.h"
79 #include "third_party/libyuv/include/libyuv/convert.h"
80 #include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
81 #include "webrtc/system_wrappers/interface/compile_assert.h"
82 #include "webrtc/system_wrappers/interface/trace.h"
83 #include "webrtc/video_engine/include/vie_base.h"
84 #include "webrtc/voice_engine/include/voe_base.h"
85
86 #ifdef ANDROID
87 #include "webrtc/system_wrappers/interface/logcat_trace_context.h"
88 using webrtc::LogcatTraceContext;
89 #endif
90
91 using icu::UnicodeString;
92 using talk_base::Bind;
93 using talk_base::Thread;
94 using talk_base::ThreadManager;
95 using talk_base::scoped_ptr;
96 using webrtc::AudioSourceInterface;
97 using webrtc::AudioTrackInterface;
98 using webrtc::AudioTrackVector;
99 using webrtc::CreateSessionDescriptionObserver;
100 using webrtc::DataBuffer;
101 using webrtc::DataChannelInit;
102 using webrtc::DataChannelInterface;
103 using webrtc::DataChannelObserver;
104 using webrtc::IceCandidateInterface;
105 using webrtc::MediaConstraintsInterface;
106 using webrtc::MediaSourceInterface;
107 using webrtc::MediaStreamInterface;
108 using webrtc::MediaStreamTrackInterface;
109 using webrtc::PeerConnectionFactoryInterface;
110 using webrtc::PeerConnectionInterface;
111 using webrtc::PeerConnectionObserver;
112 using webrtc::SessionDescriptionInterface;
113 using webrtc::SetSessionDescriptionObserver;
114 using webrtc::StatsObserver;
115 using webrtc::StatsReport;
116 using webrtc::VideoRendererInterface;
117 using webrtc::VideoSourceInterface;
118 using webrtc::VideoTrackInterface;
119 using webrtc::VideoTrackVector;
120 using webrtc::kVideoCodecVP8;
121
122 // Abort the process if |x| is false, emitting |msg|.
123 #define CHECK(x, msg)                                                          \
124   if (x) {} else {                                                             \
125     LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg;               \
126     abort();                                                                   \
127   }
128 // Abort the process if |jni| has a Java exception pending, emitting |msg|.
129 #define CHECK_EXCEPTION(jni, msg)                                              \
130   if (0) {} else {                                                             \
131     if (jni->ExceptionCheck()) {                                               \
132       jni->ExceptionDescribe();                                                \
133       jni->ExceptionClear();                                                   \
134       CHECK(0, msg);                                                           \
135     }                                                                          \
136   }
137
138 // Helper that calls ptr->Release() and logs a useful message if that didn't
139 // actually delete *ptr because of extra refcounts.
140 #define CHECK_RELEASE(ptr)                                        \
141   do {                                                            \
142     int count = (ptr)->Release();                                 \
143     if (count != 0) {                                             \
144       LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr)   \
145                     << ": " << count;                             \
146     }                                                             \
147     CHECK(!count, "Unexpected refcount");                         \
148   } while (0)
149
150 namespace {
151
152 static JavaVM* g_jvm = NULL;  // Set in JNI_OnLoad().
153
154 static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
155 // Key for per-thread JNIEnv* data.  Non-NULL in threads attached to |g_jvm| by
156 // AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
157 // were attached by the JVM because of a Java->native call.
158 static pthread_key_t g_jni_ptr;
159
160 // Return thread ID as a string.
161 static std::string GetThreadId() {
162   char buf[21];  // Big enough to hold a kuint64max plus terminating NULL.
163   CHECK(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)) <= sizeof(buf),
164         "Thread id is bigger than uint64??");
165   return std::string(buf);
166 }
167
168 // Return the current thread's name.
169 static std::string GetThreadName() {
170   char name[17];
171   CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
172   name[16] = '\0';
173   return std::string(name);
174 }
175
176 // Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
177 static JNIEnv* GetEnv() {
178   void* env = NULL;
179   jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
180   CHECK(((env != NULL) && (status == JNI_OK)) ||
181             ((env == NULL) && (status == JNI_EDETACHED)),
182         "Unexpected GetEnv return: " << status << ":" << env);
183   return reinterpret_cast<JNIEnv*>(env);
184 }
185
186 static void ThreadDestructor(void* prev_jni_ptr) {
187   // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
188   // we were responsible for originally attaching the thread, so are responsible
189   // for detaching it now.  However, because some JVM implementations (notably
190   // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
191   // the JVMs accounting info for this thread may already be wiped out by the
192   // time this is called. Thus it may appear we are already detached even though
193   // it was our responsibility to detach!  Oh well.
194   if (!GetEnv())
195     return;
196
197   CHECK(GetEnv() == prev_jni_ptr,
198         "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv());
199   jint status = g_jvm->DetachCurrentThread();
200   CHECK(status == JNI_OK, "Failed to detach thread: " << status);
201   CHECK(!GetEnv(), "Detaching was a successful no-op???");
202 }
203
204 static void CreateJNIPtrKey() {
205   CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
206         "pthread_key_create");
207 }
208
209 // Return a |JNIEnv*| usable on this thread.  Attaches to |g_jvm| if necessary.
210 static JNIEnv* AttachCurrentThreadIfNeeded() {
211   JNIEnv* jni = GetEnv();
212   if (jni)
213     return jni;
214   CHECK(!pthread_getspecific(g_jni_ptr), "TLS has a JNIEnv* but not attached?");
215
216   char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
217   JavaVMAttachArgs args;
218   args.version = JNI_VERSION_1_6;
219   args.name = name;
220   args.group = NULL;
221   // Deal with difference in signatures between Oracle's jni.h and Android's.
222 #ifdef _JAVASOFT_JNI_H_  // Oracle's jni.h violates the JNI spec!
223   void* env = NULL;
224 #else
225   JNIEnv* env = NULL;
226 #endif
227   CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
228   free(name);
229   CHECK(env, "AttachCurrentThread handed back NULL!");
230   jni = reinterpret_cast<JNIEnv*>(env);
231   CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
232   return jni;
233 }
234
235 // Return a |jlong| that will correctly convert back to |ptr|.  This is needed
236 // because the alternative (of silently passing a 32-bit pointer to a vararg
237 // function expecting a 64-bit param) picks up garbage in the high 32 bits.
238 static jlong jlongFromPointer(void* ptr) {
239   COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
240                  Time_to_rethink_the_use_of_jlongs);
241   // Going through intptr_t to be obvious about the definedness of the
242   // conversion from pointer to integral type.  intptr_t to jlong is a standard
243   // widening by the COMPILE_ASSERT above.
244   jlong ret = reinterpret_cast<intptr_t>(ptr);
245   assert(reinterpret_cast<void*>(ret) == ptr);
246   return ret;
247 }
248
249 // Android's FindClass() is trickier than usual because the app-specific
250 // ClassLoader is not consulted when there is no app-specific frame on the
251 // stack.  Consequently, we only look up classes once in JNI_OnLoad.
252 // http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
253 class ClassReferenceHolder {
254  public:
255   explicit ClassReferenceHolder(JNIEnv* jni) {
256     LoadClass(jni, "java/nio/ByteBuffer");
257     LoadClass(jni, "org/webrtc/AudioTrack");
258     LoadClass(jni, "org/webrtc/DataChannel");
259     LoadClass(jni, "org/webrtc/DataChannel$Buffer");
260     LoadClass(jni, "org/webrtc/DataChannel$Init");
261     LoadClass(jni, "org/webrtc/DataChannel$State");
262     LoadClass(jni, "org/webrtc/IceCandidate");
263 #ifdef ANDROID
264     LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
265     LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
266 #endif
267     LoadClass(jni, "org/webrtc/MediaSource$State");
268     LoadClass(jni, "org/webrtc/MediaStream");
269     LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
270     LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
271     LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
272     LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
273     LoadClass(jni, "org/webrtc/SessionDescription");
274     LoadClass(jni, "org/webrtc/SessionDescription$Type");
275     LoadClass(jni, "org/webrtc/StatsReport");
276     LoadClass(jni, "org/webrtc/StatsReport$Value");
277     LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
278     LoadClass(jni, "org/webrtc/VideoTrack");
279   }
280
281   ~ClassReferenceHolder() {
282     CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
283   }
284
285   void FreeReferences(JNIEnv* jni) {
286     for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
287          it != classes_.end(); ++it) {
288       jni->DeleteGlobalRef(it->second);
289     }
290     classes_.clear();
291   }
292
293   jclass GetClass(const std::string& name) {
294     std::map<std::string, jclass>::iterator it = classes_.find(name);
295     CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
296     return it->second;
297   }
298
299  private:
300   void LoadClass(JNIEnv* jni, const std::string& name) {
301     jclass localRef = jni->FindClass(name.c_str());
302     CHECK_EXCEPTION(jni, "error during FindClass: " << name);
303     CHECK(localRef, name);
304     jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
305     CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
306     CHECK(globalRef, name);
307     bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
308     CHECK(inserted, "Duplicate class name: " << name);
309   }
310
311   std::map<std::string, jclass> classes_;
312 };
313
314 // Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
315 static ClassReferenceHolder* g_class_reference_holder = NULL;
316
317 // JNIEnv-helper methods that CHECK success: no Java exception thrown and found
318 // object/class/method/field is non-null.
319 jmethodID GetMethodID(
320     JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
321   jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
322   CHECK_EXCEPTION(jni,
323                   "error during GetMethodID: " << name << ", " << signature);
324   CHECK(m, name << ", " << signature);
325   return m;
326 }
327
328 jmethodID GetStaticMethodID(
329     JNIEnv* jni, jclass c, const char* name, const char* signature) {
330   jmethodID m = jni->GetStaticMethodID(c, name, signature);
331   CHECK_EXCEPTION(jni,
332                   "error during GetStaticMethodID: "
333                   << name << ", " << signature);
334   CHECK(m, name << ", " << signature);
335   return m;
336 }
337
338 jfieldID GetFieldID(
339     JNIEnv* jni, jclass c, const char* name, const char* signature) {
340   jfieldID f = jni->GetFieldID(c, name, signature);
341   CHECK_EXCEPTION(jni, "error during GetFieldID");
342   CHECK(f, name << ", " << signature);
343   return f;
344 }
345
346 // Returns a global reference guaranteed to be valid for the lifetime of the
347 // process.
348 jclass FindClass(JNIEnv* jni, const char* name) {
349   return g_class_reference_holder->GetClass(name);
350 }
351
352 jclass GetObjectClass(JNIEnv* jni, jobject object) {
353   jclass c = jni->GetObjectClass(object);
354   CHECK_EXCEPTION(jni, "error during GetObjectClass");
355   CHECK(c, "");
356   return c;
357 }
358
359 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
360   jobject o = jni->GetObjectField(object, id);
361   CHECK_EXCEPTION(jni, "error during GetObjectField");
362   CHECK(o, "");
363   return o;
364 }
365
366 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
367   return static_cast<jstring>(GetObjectField(jni, object, id));
368 }
369
370 jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
371   jlong l = jni->GetLongField(object, id);
372   CHECK_EXCEPTION(jni, "error during GetLongField");
373   return l;
374 }
375
376 jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
377   jint i = jni->GetIntField(object, id);
378   CHECK_EXCEPTION(jni, "error during GetIntField");
379   return i;
380 }
381
382 bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
383   jboolean b = jni->GetBooleanField(object, id);
384   CHECK_EXCEPTION(jni, "error during GetBooleanField");
385   return b;
386 }
387
388 jobject NewGlobalRef(JNIEnv* jni, jobject o) {
389   jobject ret = jni->NewGlobalRef(o);
390   CHECK_EXCEPTION(jni, "error during NewGlobalRef");
391   CHECK(ret, "");
392   return ret;
393 }
394
395 void DeleteGlobalRef(JNIEnv* jni, jobject o) {
396   jni->DeleteGlobalRef(o);
397   CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
398 }
399
400 // Given a jweak reference, allocate a (strong) local reference scoped to the
401 // lifetime of this object if the weak reference is still valid, or NULL
402 // otherwise.
403 class WeakRef {
404  public:
405   WeakRef(JNIEnv* jni, jweak ref)
406       : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
407     CHECK_EXCEPTION(jni, "error during NewLocalRef");
408   }
409   ~WeakRef() {
410     if (obj_) {
411       jni_->DeleteLocalRef(obj_);
412       CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
413     }
414   }
415   jobject obj() { return obj_; }
416
417  private:
418   JNIEnv* const jni_;
419   jobject const obj_;
420 };
421
422 // Scope Java local references to the lifetime of this object.  Use in all C++
423 // callbacks (i.e. entry points that don't originate in a Java callstack
424 // through a "native" method call).
425 class ScopedLocalRefFrame {
426  public:
427   explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
428     CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
429   }
430   ~ScopedLocalRefFrame() {
431     jni_->PopLocalFrame(NULL);
432   }
433
434  private:
435   JNIEnv* jni_;
436 };
437
438 // Scoped holder for global Java refs.
439 template<class T>  // T is jclass, jobject, jintArray, etc.
440 class ScopedGlobalRef {
441  public:
442   ScopedGlobalRef(JNIEnv* jni, T obj)
443       : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
444   ~ScopedGlobalRef() {
445     DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
446   }
447   T operator*() const {
448     return obj_;
449   }
450  private:
451   T obj_;
452 };
453
454 // Java references to "null" can only be distinguished as such in C++ by
455 // creating a local reference, so this helper wraps that logic.
456 static bool IsNull(JNIEnv* jni, jobject obj) {
457   ScopedLocalRefFrame local_ref_frame(jni);
458   return jni->NewLocalRef(obj) == NULL;
459 }
460
461 // Return the (singleton) Java Enum object corresponding to |index|;
462 // |state_class_fragment| is something like "MediaSource$State".
463 jobject JavaEnumFromIndex(
464     JNIEnv* jni, const std::string& state_class_fragment, int index) {
465   std::string state_class_name = "org/webrtc/" + state_class_fragment;
466   jclass state_class = FindClass(jni, state_class_name.c_str());
467   jmethodID state_values_id = GetStaticMethodID(
468       jni, state_class, "values", ("()[L" + state_class_name  + ";").c_str());
469   jobjectArray state_values = static_cast<jobjectArray>(
470       jni->CallStaticObjectMethod(state_class, state_values_id));
471   CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
472   jobject ret = jni->GetObjectArrayElement(state_values, index);
473   CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
474   return ret;
475 }
476
477 // Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
478 static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
479   UnicodeString ustr(UnicodeString::fromUTF8(native));
480   jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
481   CHECK_EXCEPTION(jni, "error during NewString");
482   return jstr;
483 }
484
485 // Given a (UTF-16) jstring return a new UTF-8 native string.
486 static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
487   const jchar* jchars = jni->GetStringChars(j_string, NULL);
488   CHECK_EXCEPTION(jni, "Error during GetStringChars");
489   UnicodeString ustr(jchars, jni->GetStringLength(j_string));
490   CHECK_EXCEPTION(jni, "Error during GetStringLength");
491   jni->ReleaseStringChars(j_string, jchars);
492   CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
493   std::string ret;
494   return ustr.toUTF8String(ret);
495 }
496
497 static DataChannelInit JavaDataChannelInitToNative(
498     JNIEnv* jni, jobject j_init) {
499   DataChannelInit init;
500
501   jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
502   jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
503   jfieldID max_retransmit_time_id =
504       GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
505   jfieldID max_retransmits_id =
506       GetFieldID(jni, j_init_class, "maxRetransmits", "I");
507   jfieldID protocol_id =
508       GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
509   jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
510   jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
511
512   init.ordered = GetBooleanField(jni, j_init, ordered_id);
513   init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
514   init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
515   init.protocol = JavaToStdString(
516       jni, GetStringField(jni, j_init, protocol_id));
517   init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
518   init.id = GetIntField(jni, j_init, id_id);
519
520   return init;
521 }
522
523 class ConstraintsWrapper;
524
525 // Adapter between the C++ PeerConnectionObserver interface and the Java
526 // PeerConnection.Observer interface.  Wraps an instance of the Java interface
527 // and dispatches C++ callbacks to Java.
528 class PCOJava : public PeerConnectionObserver {
529  public:
530   PCOJava(JNIEnv* jni, jobject j_observer)
531       : j_observer_global_(jni, j_observer),
532         j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
533         j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
534         j_media_stream_ctor_(GetMethodID(
535             jni, *j_media_stream_class_, "<init>", "(J)V")),
536         j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
537         j_audio_track_ctor_(GetMethodID(
538             jni, *j_audio_track_class_, "<init>", "(J)V")),
539         j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
540         j_video_track_ctor_(GetMethodID(
541             jni, *j_video_track_class_, "<init>", "(J)V")),
542         j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
543         j_data_channel_ctor_(GetMethodID(
544             jni, *j_data_channel_class_, "<init>", "(J)V")) {
545   }
546
547   virtual ~PCOJava() {}
548
549   virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
550     ScopedLocalRefFrame local_ref_frame(jni());
551     std::string sdp;
552     CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
553     jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
554     jmethodID ctor = GetMethodID(jni(), candidate_class,
555         "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
556     jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
557     jstring j_sdp = JavaStringFromStdString(jni(), sdp);
558     jobject j_candidate = jni()->NewObject(
559         candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
560     CHECK_EXCEPTION(jni(), "error during NewObject");
561     jmethodID m = GetMethodID(jni(), *j_observer_class_,
562                               "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
563     jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
564     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
565   }
566
567   virtual void OnError() OVERRIDE {
568     ScopedLocalRefFrame local_ref_frame(jni());
569     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
570     jni()->CallVoidMethod(*j_observer_global_, m);
571     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
572   }
573
574   virtual void OnSignalingChange(
575       PeerConnectionInterface::SignalingState new_state) OVERRIDE {
576     ScopedLocalRefFrame local_ref_frame(jni());
577     jmethodID m = GetMethodID(
578         jni(), *j_observer_class_, "onSignalingChange",
579         "(Lorg/webrtc/PeerConnection$SignalingState;)V");
580     jobject new_state_enum =
581         JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
582     jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
583     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
584   }
585
586   virtual void OnIceConnectionChange(
587       PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
588     ScopedLocalRefFrame local_ref_frame(jni());
589     jmethodID m = GetMethodID(
590         jni(), *j_observer_class_, "onIceConnectionChange",
591         "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
592     jobject new_state_enum = JavaEnumFromIndex(
593         jni(), "PeerConnection$IceConnectionState", new_state);
594     jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
595     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
596   }
597
598   virtual void OnIceGatheringChange(
599       PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
600     ScopedLocalRefFrame local_ref_frame(jni());
601     jmethodID m = GetMethodID(
602         jni(), *j_observer_class_, "onIceGatheringChange",
603         "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
604     jobject new_state_enum = JavaEnumFromIndex(
605         jni(), "PeerConnection$IceGatheringState", new_state);
606     jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
607     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
608   }
609
610   virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
611     ScopedLocalRefFrame local_ref_frame(jni());
612     jobject j_stream = jni()->NewObject(
613         *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
614     CHECK_EXCEPTION(jni(), "error during NewObject");
615
616     AudioTrackVector audio_tracks = stream->GetAudioTracks();
617     for (size_t i = 0; i < audio_tracks.size(); ++i) {
618       AudioTrackInterface* track = audio_tracks[i];
619       jstring id = JavaStringFromStdString(jni(), track->id());
620       jobject j_track = jni()->NewObject(
621           *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
622       CHECK_EXCEPTION(jni(), "error during NewObject");
623       jfieldID audio_tracks_id = GetFieldID(jni(),
624                                             *j_media_stream_class_,
625                                             "audioTracks",
626                                             "Ljava/util/LinkedList;");
627       jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
628       jmethodID add = GetMethodID(jni(),
629                                   GetObjectClass(jni(), audio_tracks),
630                                   "add",
631                                   "(Ljava/lang/Object;)Z");
632       jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
633       CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
634       CHECK(added, "");
635     }
636
637     VideoTrackVector video_tracks = stream->GetVideoTracks();
638     for (size_t i = 0; i < video_tracks.size(); ++i) {
639       VideoTrackInterface* track = video_tracks[i];
640       jstring id = JavaStringFromStdString(jni(), track->id());
641       jobject j_track = jni()->NewObject(
642           *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
643       CHECK_EXCEPTION(jni(), "error during NewObject");
644       jfieldID video_tracks_id = GetFieldID(jni(),
645                                             *j_media_stream_class_,
646                                             "videoTracks",
647                                             "Ljava/util/LinkedList;");
648       jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
649       jmethodID add = GetMethodID(jni(),
650                                   GetObjectClass(jni(), video_tracks),
651                                   "add",
652                                   "(Ljava/lang/Object;)Z");
653       jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
654       CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
655       CHECK(added, "");
656     }
657     streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
658     CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
659
660     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
661                               "(Lorg/webrtc/MediaStream;)V");
662     jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
663     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
664   }
665
666   virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
667     ScopedLocalRefFrame local_ref_frame(jni());
668     NativeToJavaStreamsMap::iterator it = streams_.find(stream);
669     CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
670
671     WeakRef s(jni(), it->second);
672     streams_.erase(it);
673     if (!s.obj())
674       return;
675
676     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
677                               "(Lorg/webrtc/MediaStream;)V");
678     jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
679     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
680   }
681
682   virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
683     ScopedLocalRefFrame local_ref_frame(jni());
684     jobject j_channel = jni()->NewObject(
685         *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
686     CHECK_EXCEPTION(jni(), "error during NewObject");
687
688     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
689                               "(Lorg/webrtc/DataChannel;)V");
690     jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
691
692     // Channel is now owned by Java object, and will be freed from
693     // DataChannel.dispose().  Important that this be done _after_ the
694     // CallVoidMethod above as Java code might call back into native code and be
695     // surprised to see a refcount of 2.
696     int bumped_count = channel->AddRef();
697     CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
698
699     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
700   }
701
702   virtual void OnRenegotiationNeeded() OVERRIDE {
703     ScopedLocalRefFrame local_ref_frame(jni());
704     jmethodID m =
705         GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
706     jni()->CallVoidMethod(*j_observer_global_, m);
707     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
708   }
709
710   void SetConstraints(ConstraintsWrapper* constraints) {
711     CHECK(!constraints_.get(), "constraints already set!");
712     constraints_.reset(constraints);
713   }
714
715   const ConstraintsWrapper* constraints() { return constraints_.get(); }
716
717  private:
718   JNIEnv* jni() {
719     return AttachCurrentThreadIfNeeded();
720   }
721
722   const ScopedGlobalRef<jobject> j_observer_global_;
723   const ScopedGlobalRef<jclass> j_observer_class_;
724   const ScopedGlobalRef<jclass> j_media_stream_class_;
725   const jmethodID j_media_stream_ctor_;
726   const ScopedGlobalRef<jclass> j_audio_track_class_;
727   const jmethodID j_audio_track_ctor_;
728   const ScopedGlobalRef<jclass> j_video_track_class_;
729   const jmethodID j_video_track_ctor_;
730   const ScopedGlobalRef<jclass> j_data_channel_class_;
731   const jmethodID j_data_channel_ctor_;
732   typedef std::map<void*, jweak> NativeToJavaStreamsMap;
733   NativeToJavaStreamsMap streams_;  // C++ -> Java streams.
734   scoped_ptr<ConstraintsWrapper> constraints_;
735 };
736
737 // Wrapper for a Java MediaConstraints object.  Copies all needed data so when
738 // the constructor returns the Java object is no longer needed.
739 class ConstraintsWrapper : public MediaConstraintsInterface {
740  public:
741   ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
742     PopulateConstraintsFromJavaPairList(
743         jni, j_constraints, "mandatory", &mandatory_);
744     PopulateConstraintsFromJavaPairList(
745         jni, j_constraints, "optional", &optional_);
746   }
747
748   virtual ~ConstraintsWrapper() {}
749
750   // MediaConstraintsInterface.
751   virtual const Constraints& GetMandatory() const OVERRIDE {
752     return mandatory_;
753   }
754
755   virtual const Constraints& GetOptional() const OVERRIDE {
756     return optional_;
757   }
758
759  private:
760   // Helper for translating a List<Pair<String, String>> to a Constraints.
761   static void PopulateConstraintsFromJavaPairList(
762       JNIEnv* jni, jobject j_constraints,
763       const char* field_name, Constraints* field) {
764     jfieldID j_id = GetFieldID(jni,
765         GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
766     jobject j_list = GetObjectField(jni, j_constraints, j_id);
767     jmethodID j_iterator_id = GetMethodID(jni,
768         GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
769     jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
770     CHECK_EXCEPTION(jni, "error during CallObjectMethod");
771     jmethodID j_has_next = GetMethodID(jni,
772         GetObjectClass(jni, j_iterator), "hasNext", "()Z");
773     jmethodID j_next = GetMethodID(jni,
774         GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
775     while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
776       CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
777       jobject entry = jni->CallObjectMethod(j_iterator, j_next);
778       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
779       jmethodID get_key = GetMethodID(jni,
780           GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
781       jstring j_key = reinterpret_cast<jstring>(
782           jni->CallObjectMethod(entry, get_key));
783       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
784       jmethodID get_value = GetMethodID(jni,
785           GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
786       jstring j_value = reinterpret_cast<jstring>(
787           jni->CallObjectMethod(entry, get_value));
788       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
789       field->push_back(Constraint(JavaToStdString(jni, j_key),
790                                   JavaToStdString(jni, j_value)));
791     }
792     CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
793   }
794
795   Constraints mandatory_;
796   Constraints optional_;
797 };
798
799 static jobject JavaSdpFromNativeSdp(
800     JNIEnv* jni, const SessionDescriptionInterface* desc) {
801   std::string sdp;
802   CHECK(desc->ToString(&sdp), "got so far: " << sdp);
803   jstring j_description = JavaStringFromStdString(jni, sdp);
804
805   jclass j_type_class = FindClass(
806       jni, "org/webrtc/SessionDescription$Type");
807   jmethodID j_type_from_canonical = GetStaticMethodID(
808       jni, j_type_class, "fromCanonicalForm",
809       "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
810   jstring j_type_string = JavaStringFromStdString(jni, desc->type());
811   jobject j_type = jni->CallStaticObjectMethod(
812       j_type_class, j_type_from_canonical, j_type_string);
813   CHECK_EXCEPTION(jni, "error during CallObjectMethod");
814
815   jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
816   jmethodID j_sdp_ctor = GetMethodID(
817       jni, j_sdp_class, "<init>",
818       "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
819   jobject j_sdp = jni->NewObject(
820       j_sdp_class, j_sdp_ctor, j_type, j_description);
821   CHECK_EXCEPTION(jni, "error during NewObject");
822   return j_sdp;
823 }
824
825 template <class T>  // T is one of {Create,Set}SessionDescriptionObserver.
826 class SdpObserverWrapper : public T {
827  public:
828   SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
829                      ConstraintsWrapper* constraints)
830       : constraints_(constraints),
831         j_observer_global_(jni, j_observer),
832         j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
833   }
834
835   virtual ~SdpObserverWrapper() {}
836
837   // Can't mark OVERRIDE because of templating.
838   virtual void OnSuccess() {
839     ScopedLocalRefFrame local_ref_frame(jni());
840     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
841     jni()->CallVoidMethod(*j_observer_global_, m);
842     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
843   }
844
845   // Can't mark OVERRIDE because of templating.
846   virtual void OnSuccess(SessionDescriptionInterface* desc) {
847     ScopedLocalRefFrame local_ref_frame(jni());
848     jmethodID m = GetMethodID(
849         jni(), *j_observer_class_, "onCreateSuccess",
850         "(Lorg/webrtc/SessionDescription;)V");
851     jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
852     jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
853     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
854   }
855
856  protected:
857   // Common implementation for failure of Set & Create types, distinguished by
858   // |op| being "Set" or "Create".
859   void OnFailure(const std::string& op, const std::string& error) {
860     jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
861                               "(Ljava/lang/String;)V");
862     jstring j_error_string = JavaStringFromStdString(jni(), error);
863     jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
864     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
865   }
866
867   JNIEnv* jni() {
868     return AttachCurrentThreadIfNeeded();
869   }
870
871  private:
872   scoped_ptr<ConstraintsWrapper> constraints_;
873   const ScopedGlobalRef<jobject> j_observer_global_;
874   const ScopedGlobalRef<jclass> j_observer_class_;
875 };
876
877 class CreateSdpObserverWrapper
878     : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
879  public:
880   CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
881                            ConstraintsWrapper* constraints)
882       : SdpObserverWrapper(jni, j_observer, constraints) {}
883
884   virtual void OnFailure(const std::string& error) OVERRIDE {
885     ScopedLocalRefFrame local_ref_frame(jni());
886     SdpObserverWrapper::OnFailure(std::string("Create"), error);
887   }
888 };
889
890 class SetSdpObserverWrapper
891     : public SdpObserverWrapper<SetSessionDescriptionObserver> {
892  public:
893   SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
894                         ConstraintsWrapper* constraints)
895       : SdpObserverWrapper(jni, j_observer, constraints) {}
896
897   virtual void OnFailure(const std::string& error) OVERRIDE {
898     ScopedLocalRefFrame local_ref_frame(jni());
899     SdpObserverWrapper::OnFailure(std::string("Set"), error);
900   }
901 };
902
903 // Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
904 // and dispatching the callback from C++ back to Java.
905 class DataChannelObserverWrapper : public DataChannelObserver {
906  public:
907   DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
908       : j_observer_global_(jni, j_observer),
909         j_observer_class_(jni, GetObjectClass(jni, j_observer)),
910         j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
911                                            "onStateChange", "()V")),
912         j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
913                                       "(Lorg/webrtc/DataChannel$Buffer;)V")),
914         j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
915         j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
916                                    "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
917   }
918
919   virtual ~DataChannelObserverWrapper() {}
920
921   virtual void OnStateChange() OVERRIDE {
922     ScopedLocalRefFrame local_ref_frame(jni());
923     jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
924     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
925   }
926
927   virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
928     ScopedLocalRefFrame local_ref_frame(jni());
929     jobject byte_buffer =
930         jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
931                                    buffer.data.length());
932     jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
933                                         byte_buffer, buffer.binary);
934     jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
935     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
936   }
937
938  private:
939   JNIEnv* jni() {
940     return AttachCurrentThreadIfNeeded();
941   }
942
943   const ScopedGlobalRef<jobject> j_observer_global_;
944   const ScopedGlobalRef<jclass> j_observer_class_;
945   const ScopedGlobalRef<jclass> j_buffer_class_;
946   const jmethodID j_on_state_change_mid_;
947   const jmethodID j_on_message_mid_;
948   const jmethodID j_buffer_ctor_;
949 };
950
951 // Adapter for a Java StatsObserver presenting a C++ StatsObserver and
952 // dispatching the callback from C++ back to Java.
953 class StatsObserverWrapper : public StatsObserver {
954  public:
955   StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
956       : j_observer_global_(jni, j_observer),
957         j_observer_class_(jni, GetObjectClass(jni, j_observer)),
958         j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
959         j_stats_report_ctor_(GetMethodID(
960             jni, *j_stats_report_class_, "<init>",
961             "(Ljava/lang/String;Ljava/lang/String;D"
962             "[Lorg/webrtc/StatsReport$Value;)V")),
963         j_value_class_(jni, FindClass(
964             jni, "org/webrtc/StatsReport$Value")),
965         j_value_ctor_(GetMethodID(
966             jni, *j_value_class_, "<init>",
967             "(Ljava/lang/String;Ljava/lang/String;)V")) {
968   }
969
970   virtual ~StatsObserverWrapper() {}
971
972   virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
973     ScopedLocalRefFrame local_ref_frame(jni());
974     jobjectArray j_reports = ReportsToJava(jni(), reports);
975     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
976                               "([Lorg/webrtc/StatsReport;)V");
977     jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
978     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
979   }
980
981  private:
982   jobjectArray ReportsToJava(
983       JNIEnv* jni, const std::vector<StatsReport>& reports) {
984     jobjectArray reports_array = jni->NewObjectArray(
985         reports.size(), *j_stats_report_class_, NULL);
986     for (int i = 0; i < reports.size(); ++i) {
987       ScopedLocalRefFrame local_ref_frame(jni);
988       const StatsReport& report = reports[i];
989       jstring j_id = JavaStringFromStdString(jni, report.id);
990       jstring j_type = JavaStringFromStdString(jni, report.type);
991       jobjectArray j_values = ValuesToJava(jni, report.values);
992       jobject j_report = jni->NewObject(*j_stats_report_class_,
993                                         j_stats_report_ctor_,
994                                         j_id,
995                                         j_type,
996                                         report.timestamp,
997                                         j_values);
998       jni->SetObjectArrayElement(reports_array, i, j_report);
999     }
1000     return reports_array;
1001   }
1002
1003   jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1004     jobjectArray j_values = jni->NewObjectArray(
1005         values.size(), *j_value_class_, NULL);
1006     for (int i = 0; i < values.size(); ++i) {
1007       ScopedLocalRefFrame local_ref_frame(jni);
1008       const StatsReport::Value& value = values[i];
1009       jstring j_name = JavaStringFromStdString(jni, value.name);
1010       jstring j_value = JavaStringFromStdString(jni, value.value);
1011       jobject j_element_value =
1012           jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1013       jni->SetObjectArrayElement(j_values, i, j_element_value);
1014     }
1015     return j_values;
1016   }
1017
1018   JNIEnv* jni() {
1019     return AttachCurrentThreadIfNeeded();
1020   }
1021
1022   const ScopedGlobalRef<jobject> j_observer_global_;
1023   const ScopedGlobalRef<jclass> j_observer_class_;
1024   const ScopedGlobalRef<jclass> j_stats_report_class_;
1025   const jmethodID j_stats_report_ctor_;
1026   const ScopedGlobalRef<jclass> j_value_class_;
1027   const jmethodID j_value_ctor_;
1028 };
1029
1030 // Adapter presenting a cricket::VideoRenderer as a
1031 // webrtc::VideoRendererInterface.
1032 class VideoRendererWrapper : public VideoRendererInterface {
1033  public:
1034   static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1035     if (renderer)
1036       return new VideoRendererWrapper(renderer);
1037     return NULL;
1038   }
1039
1040   virtual ~VideoRendererWrapper() {}
1041
1042   virtual void SetSize(int width, int height) OVERRIDE {
1043     ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
1044     const bool kNotReserved = false;  // What does this param mean??
1045     renderer_->SetSize(width, height, kNotReserved);
1046   }
1047
1048   virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
1049     ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
1050     renderer_->RenderFrame(frame);
1051   }
1052
1053  private:
1054   explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1055       : renderer_(renderer) {}
1056
1057   scoped_ptr<cricket::VideoRenderer> renderer_;
1058 };
1059
1060 // Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1061 // instance.
1062 class JavaVideoRendererWrapper : public VideoRendererInterface {
1063  public:
1064   JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
1065       : j_callbacks_(jni, j_callbacks),
1066         j_set_size_id_(GetMethodID(
1067             jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1068         j_render_frame_id_(GetMethodID(
1069             jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1070             "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1071         j_frame_class_(jni,
1072                        FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1073         j_frame_ctor_id_(GetMethodID(
1074             jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1075         j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
1076     CHECK_EXCEPTION(jni, "");
1077   }
1078
1079   virtual ~JavaVideoRendererWrapper() {}
1080
1081   virtual void SetSize(int width, int height) OVERRIDE {
1082     ScopedLocalRefFrame local_ref_frame(jni());
1083     jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1084     CHECK_EXCEPTION(jni(), "");
1085   }
1086
1087   virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
1088     ScopedLocalRefFrame local_ref_frame(jni());
1089     jobject j_frame = CricketToJavaFrame(frame);
1090     jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1091     CHECK_EXCEPTION(jni(), "");
1092   }
1093
1094  private:
1095   // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1096   jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
1097     jintArray strides = jni()->NewIntArray(3);
1098     jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
1099     strides_array[0] = frame->GetYPitch();
1100     strides_array[1] = frame->GetUPitch();
1101     strides_array[2] = frame->GetVPitch();
1102     jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1103     jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1104     jobject y_buffer = jni()->NewDirectByteBuffer(
1105         const_cast<uint8*>(frame->GetYPlane()),
1106         frame->GetYPitch() * frame->GetHeight());
1107     jobject u_buffer = jni()->NewDirectByteBuffer(
1108         const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1109     jobject v_buffer = jni()->NewDirectByteBuffer(
1110         const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1111     jni()->SetObjectArrayElement(planes, 0, y_buffer);
1112     jni()->SetObjectArrayElement(planes, 1, u_buffer);
1113     jni()->SetObjectArrayElement(planes, 2, v_buffer);
1114     return jni()->NewObject(
1115         *j_frame_class_, j_frame_ctor_id_,
1116         frame->GetWidth(), frame->GetHeight(), strides, planes);
1117   }
1118
1119   JNIEnv* jni() {
1120     return AttachCurrentThreadIfNeeded();
1121   }
1122
1123   ScopedGlobalRef<jobject> j_callbacks_;
1124   jmethodID j_set_size_id_;
1125   jmethodID j_render_frame_id_;
1126   ScopedGlobalRef<jclass> j_frame_class_;
1127   jmethodID j_frame_ctor_id_;
1128   ScopedGlobalRef<jclass> j_byte_buffer_class_;
1129 };
1130
1131 #ifdef ANDROID
1132 // TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1133 // into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1134 // from this file.
1135
1136 // Arbitrary interval to poll the codec for new outputs.
1137 enum { kMediaCodecPollMs = 10 };
1138
1139 // MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1140 // Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1141 // HW-backed video encode.  This C++ class is implemented as a very thin shim,
1142 // delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1143 // MediaCodecVideoEncoder is created, operated, and destroyed on a single
1144 // thread, currently the libjingle Worker thread.
1145 class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
1146                                public talk_base::MessageHandler {
1147  public:
1148   virtual ~MediaCodecVideoEncoder();
1149   explicit MediaCodecVideoEncoder(JNIEnv* jni);
1150
1151   // webrtc::VideoEncoder implementation.  Everything trampolines to
1152   // |codec_thread_| for execution.
1153   virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1154                              int32_t /* number_of_cores */,
1155                              uint32_t /* max_payload_size */) OVERRIDE;
1156   virtual int32_t Encode(
1157       const webrtc::I420VideoFrame& input_image,
1158       const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1159       const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1160   virtual int32_t RegisterEncodeCompleteCallback(
1161       webrtc::EncodedImageCallback* callback) OVERRIDE;
1162   virtual int32_t Release() OVERRIDE;
1163   virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1164                                        int /* rtt */) OVERRIDE;
1165   virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1166
1167   // talk_base::MessageHandler implementation.
1168   virtual void OnMessage(talk_base::Message* msg) OVERRIDE;
1169
1170  private:
1171   // CHECK-fail if not running on |codec_thread_|.
1172   void CheckOnCodecThread();
1173
1174   // Release() and InitEncode() in an attempt to restore the codec to an
1175   // operable state.  Necessary after all manner of OMX-layer errors.
1176   void ResetCodec();
1177
1178   // Implementation of webrtc::VideoEncoder methods above, all running on the
1179   // codec thread exclusively.
1180   //
1181   // If width==0 then this is assumed to be a re-initialization and the
1182   // previously-current values are reused instead of the passed parameters
1183   // (makes it easier to reason about thread-safety).
1184   int32_t InitEncodeOnCodecThread(int width, int height, int kbps);
1185   int32_t EncodeOnCodecThread(
1186       const webrtc::I420VideoFrame& input_image,
1187       const std::vector<webrtc::VideoFrameType>* frame_types);
1188   int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1189       webrtc::EncodedImageCallback* callback);
1190   int32_t ReleaseOnCodecThread();
1191   int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1192
1193   // Reset parameters valid between InitEncode() & Release() (see below).
1194   void ResetParameters(JNIEnv* jni);
1195
1196   // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1197   int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1198   jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1199   bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1200   jlong GetOutputBufferInfoPresentationTimestampUs(
1201       JNIEnv* jni,
1202       jobject j_output_buffer_info);
1203
1204   // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1205   // true on success.
1206   bool DeliverPendingOutputs(JNIEnv* jni);
1207
1208   // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1209   // |codec_thread_| synchronously.
1210   webrtc::EncodedImageCallback* callback_;
1211
1212   // State that is constant for the lifetime of this object once the ctor
1213   // returns.
1214   scoped_ptr<Thread> codec_thread_;  // Thread on which to operate MediaCodec.
1215   ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1216   ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1217   jmethodID j_init_encode_method_;
1218   jmethodID j_dequeue_input_buffer_method_;
1219   jmethodID j_encode_method_;
1220   jmethodID j_release_method_;
1221   jmethodID j_set_rates_method_;
1222   jmethodID j_dequeue_output_buffer_method_;
1223   jmethodID j_release_output_buffer_method_;
1224   jfieldID j_info_index_field_;
1225   jfieldID j_info_buffer_field_;
1226   jfieldID j_info_is_key_frame_field_;
1227   jfieldID j_info_presentation_timestamp_us_field_;
1228
1229   // State that is valid only between InitEncode() and the next Release().
1230   // Touched only on codec_thread_ so no explicit synchronization necessary.
1231   int width_;   // Frame width in pixels.
1232   int height_;  // Frame height in pixels.
1233   int last_set_bitrate_kbps_;  // Last-requested bitrate in kbps.
1234   // Frame size in bytes fed to MediaCodec (stride==width, sliceHeight==height).
1235   int nv12_size_;
1236   // True only when between a callback_->Encoded() call return a positive value
1237   // and the next Encode() call being ignored.
1238   bool drop_next_input_frame_;
1239   // Global references; must be deleted in Release().
1240   std::vector<jobject> input_buffers_;
1241 };
1242
1243 enum { MSG_SET_RATES, MSG_POLL_FOR_READY_OUTPUTS, };
1244
1245 MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1246   // We depend on ResetParameters() to ensure no more callbacks to us after we
1247   // are deleted, so assert it here.
1248   CHECK(width_ == 0, "Release() should have been called");
1249 }
1250
1251 MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1252     : callback_(NULL),
1253       codec_thread_(new Thread()),
1254       j_media_codec_video_encoder_class_(
1255           jni,
1256           FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1257       j_media_codec_video_encoder_(
1258           jni,
1259           jni->NewObject(*j_media_codec_video_encoder_class_,
1260                          GetMethodID(jni,
1261                                      *j_media_codec_video_encoder_class_,
1262                                      "<init>",
1263                                      "()V"))) {
1264   ScopedLocalRefFrame local_ref_frame(jni);
1265   // It would be nice to avoid spinning up a new thread per MediaCodec, and
1266   // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1267   // 2732 means that deadlocks abound.  This class synchronously trampolines
1268   // to |codec_thread_|, so if anything else can be coming to _us_ from
1269   // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1270   // in the bug, we have a problem.  For now work around that with a dedicated
1271   // thread.
1272   codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
1273   CHECK(codec_thread_->Start(), "Failed to start MediaCodecVideoEncoder");
1274
1275   ResetParameters(jni);
1276
1277   jclass j_output_buffer_info_class =
1278       FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1279   j_init_encode_method_ = GetMethodID(jni,
1280                                       *j_media_codec_video_encoder_class_,
1281                                       "initEncode",
1282                                       "(III)[Ljava/nio/ByteBuffer;");
1283   j_dequeue_input_buffer_method_ = GetMethodID(
1284       jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1285   j_encode_method_ = GetMethodID(
1286       jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1287   j_release_method_ =
1288       GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1289   j_set_rates_method_ = GetMethodID(
1290       jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1291   j_dequeue_output_buffer_method_ =
1292       GetMethodID(jni,
1293                   *j_media_codec_video_encoder_class_,
1294                   "dequeueOutputBuffer",
1295                   "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1296   j_release_output_buffer_method_ = GetMethodID(
1297       jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1298
1299   j_info_index_field_ =
1300       GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1301   j_info_buffer_field_ = GetFieldID(
1302       jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1303   j_info_is_key_frame_field_ =
1304       GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1305   j_info_presentation_timestamp_us_field_ = GetFieldID(
1306       jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
1307   CHECK_EXCEPTION(jni, "MediaCodecVideoEncoder ctor failed");
1308 }
1309
1310 int32_t MediaCodecVideoEncoder::InitEncode(
1311     const webrtc::VideoCodec* codec_settings,
1312     int32_t /* number_of_cores */,
1313     uint32_t /* max_payload_size */) {
1314   // Factory should guard against other codecs being used with us.
1315   CHECK(codec_settings->codecType == kVideoCodecVP8, "Unsupported codec");
1316
1317   return codec_thread_->Invoke<int32_t>(
1318       Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1319            this,
1320            codec_settings->width,
1321            codec_settings->height,
1322            codec_settings->startBitrate));
1323 }
1324
1325 int32_t MediaCodecVideoEncoder::Encode(
1326     const webrtc::I420VideoFrame& frame,
1327     const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1328     const std::vector<webrtc::VideoFrameType>* frame_types) {
1329   return codec_thread_->Invoke<int32_t>(Bind(
1330       &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1331 }
1332
1333 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1334     webrtc::EncodedImageCallback* callback) {
1335   return codec_thread_->Invoke<int32_t>(
1336       Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1337            this,
1338            callback));
1339 }
1340
1341 int32_t MediaCodecVideoEncoder::Release() {
1342   return codec_thread_->Invoke<int32_t>(
1343       Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1344 }
1345
1346 int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1347                                                      int /* rtt */) {
1348   return WEBRTC_VIDEO_CODEC_OK;
1349 }
1350
1351 int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1352                                          uint32_t frame_rate) {
1353   return codec_thread_->Invoke<int32_t>(
1354       Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1355            this,
1356            new_bit_rate,
1357            frame_rate));
1358 }
1359
1360 void MediaCodecVideoEncoder::OnMessage(talk_base::Message* msg) {
1361   JNIEnv* jni = AttachCurrentThreadIfNeeded();
1362   ScopedLocalRefFrame local_ref_frame(jni);
1363
1364   // We only ever send one message to |this| directly (not through a Bind()'d
1365   // functor), so expect no ID/data.
1366   CHECK(!msg->message_id, "Unexpected message!");
1367   CHECK(!msg->pdata, "Unexpected message!");
1368   CheckOnCodecThread();
1369
1370   // It would be nice to recover from a failure here if one happened, but it's
1371   // unclear how to signal such a failure to the app, so instead we stay silent
1372   // about it and let the next app-called API method reveal the borkedness.
1373   DeliverPendingOutputs(jni);
1374   codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1375 }
1376
1377 void MediaCodecVideoEncoder::CheckOnCodecThread() {
1378   CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread(),
1379         "Running on wrong thread!");
1380 }
1381
1382 void MediaCodecVideoEncoder::ResetCodec() {
1383   if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1384       codec_thread_->Invoke<int32_t>(Bind(
1385           &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0)) !=
1386           WEBRTC_VIDEO_CODEC_OK) {
1387     // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1388     // degrade to a SW encoder at this point?  There isn't one AFAICT :(
1389     // https://code.google.com/p/webrtc/issues/detail?id=2920
1390   }
1391 }
1392
1393 int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
1394     int width, int height, int kbps) {
1395   CheckOnCodecThread();
1396   JNIEnv* jni = AttachCurrentThreadIfNeeded();
1397   ScopedLocalRefFrame local_ref_frame(jni);
1398
1399   if (width == 0) {
1400     width = width_;
1401     height = height_;
1402     kbps = last_set_bitrate_kbps_;
1403   }
1404
1405   width_ = width;
1406   height_ = height;
1407   last_set_bitrate_kbps_ = kbps;
1408   nv12_size_ = width_ * height_ * 3 / 2;
1409   // We enforce no extra stride/padding in the format creation step.
1410   jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1411       jni->CallObjectMethod(*j_media_codec_video_encoder_,
1412                             j_init_encode_method_,
1413                             width_,
1414                             height_,
1415                             kbps));
1416   CHECK_EXCEPTION(jni, "");
1417   if (IsNull(jni, input_buffers))
1418     return WEBRTC_VIDEO_CODEC_ERROR;
1419
1420   size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1421   CHECK(input_buffers_.empty(), "Unexpected double InitEncode without Release");
1422   input_buffers_.resize(num_input_buffers);
1423   for (size_t i = 0; i < num_input_buffers; ++i) {
1424     input_buffers_[i] =
1425         jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
1426     int64 nv12_buffer_capacity =
1427         jni->GetDirectBufferCapacity(input_buffers_[i]);
1428     CHECK_EXCEPTION(jni, "");
1429     CHECK(nv12_buffer_capacity >= nv12_size_, "Insufficient capacity");
1430   }
1431   CHECK_EXCEPTION(jni, "");
1432
1433   codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1434   return WEBRTC_VIDEO_CODEC_OK;
1435 }
1436
1437 int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1438     const webrtc::I420VideoFrame& frame,
1439     const std::vector<webrtc::VideoFrameType>* frame_types) {
1440   CheckOnCodecThread();
1441   JNIEnv* jni = AttachCurrentThreadIfNeeded();
1442   ScopedLocalRefFrame local_ref_frame(jni);
1443
1444   if (!DeliverPendingOutputs(jni)) {
1445     ResetCodec();
1446     // Continue as if everything's fine.
1447   }
1448
1449   if (drop_next_input_frame_) {
1450     drop_next_input_frame_ = false;
1451     return WEBRTC_VIDEO_CODEC_OK;
1452   }
1453
1454   CHECK(frame_types->size() == 1, "Unexpected stream count");
1455   bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1456
1457   CHECK(frame.width() == width_, "Unexpected resolution change");
1458   CHECK(frame.height() == height_, "Unexpected resolution change");
1459
1460   int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1461                                                 j_dequeue_input_buffer_method_);
1462   CHECK_EXCEPTION(jni, "");
1463   if (j_input_buffer_index == -1)
1464     return WEBRTC_VIDEO_CODEC_OK;  // TODO(fischman): see webrtc bug 2887.
1465   if (j_input_buffer_index == -2) {
1466     ResetCodec();
1467     return WEBRTC_VIDEO_CODEC_ERROR;
1468   }
1469
1470   jobject j_input_buffer = input_buffers_[j_input_buffer_index];
1471   uint8* nv12_buffer =
1472       reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
1473   CHECK_EXCEPTION(jni, "");
1474   CHECK(nv12_buffer, "Indirect buffer??");
1475   CHECK(!libyuv::I420ToNV12(
1476             frame.buffer(webrtc::kYPlane),
1477             frame.stride(webrtc::kYPlane),
1478             frame.buffer(webrtc::kUPlane),
1479             frame.stride(webrtc::kUPlane),
1480             frame.buffer(webrtc::kVPlane),
1481             frame.stride(webrtc::kVPlane),
1482             nv12_buffer,
1483             frame.width(),
1484             nv12_buffer + frame.stride(webrtc::kYPlane) * frame.height(),
1485             frame.width(),
1486             frame.width(),
1487             frame.height()),
1488         "I420ToNV12 failed");
1489   jlong timestamp_us = frame.render_time_ms() * 1000;
1490   int64_t start = talk_base::Time();
1491   bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1492                                               j_encode_method_,
1493                                               key_frame,
1494                                               j_input_buffer_index,
1495                                               nv12_size_,
1496                                               timestamp_us);
1497   CHECK_EXCEPTION(jni, "");
1498   if (!encode_status || !DeliverPendingOutputs(jni)) {
1499     ResetCodec();
1500     return WEBRTC_VIDEO_CODEC_ERROR;
1501   }
1502
1503   return WEBRTC_VIDEO_CODEC_OK;
1504 }
1505
1506 int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1507     webrtc::EncodedImageCallback* callback) {
1508   CheckOnCodecThread();
1509   JNIEnv* jni = AttachCurrentThreadIfNeeded();
1510   ScopedLocalRefFrame local_ref_frame(jni);
1511   callback_ = callback;
1512   return WEBRTC_VIDEO_CODEC_OK;
1513 }
1514
1515 int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
1516   CheckOnCodecThread();
1517   JNIEnv* jni = AttachCurrentThreadIfNeeded();
1518   ScopedLocalRefFrame local_ref_frame(jni);
1519   for (size_t i = 0; i < input_buffers_.size(); ++i)
1520     jni->DeleteGlobalRef(input_buffers_[i]);
1521   input_buffers_.clear();
1522   jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1523   ResetParameters(jni);
1524   CHECK_EXCEPTION(jni, "");
1525   return WEBRTC_VIDEO_CODEC_OK;
1526 }
1527
1528 int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1529                                                       uint32_t frame_rate) {
1530   CheckOnCodecThread();
1531   JNIEnv* jni = AttachCurrentThreadIfNeeded();
1532   ScopedLocalRefFrame local_ref_frame(jni);
1533   last_set_bitrate_kbps_ = new_bit_rate;
1534   bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1535                                        j_set_rates_method_,
1536                                        new_bit_rate,
1537                                        frame_rate);
1538   CHECK_EXCEPTION(jni, "");
1539   if (!ret) {
1540     ResetCodec();
1541     return WEBRTC_VIDEO_CODEC_ERROR;
1542   }
1543   return WEBRTC_VIDEO_CODEC_OK;
1544 }
1545
1546 void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
1547   talk_base::MessageQueueManager::Clear(this);
1548   width_ = 0;
1549   height_ = 0;
1550   nv12_size_ = 0;
1551   drop_next_input_frame_ = false;
1552   CHECK(input_buffers_.empty(),
1553         "ResetParameters called while holding input_buffers_!");
1554 }
1555
1556 int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1557     JNIEnv* jni,
1558     jobject j_output_buffer_info) {
1559   return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1560 }
1561
1562 jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1563     JNIEnv* jni,
1564     jobject j_output_buffer_info) {
1565   return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1566 }
1567
1568 bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1569     JNIEnv* jni,
1570     jobject j_output_buffer_info) {
1571   return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1572 }
1573
1574 jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1575     JNIEnv* jni,
1576     jobject j_output_buffer_info) {
1577   return GetLongField(
1578       jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1579 }
1580
1581 bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1582   while (true) {
1583     jobject j_output_buffer_info = jni->CallObjectMethod(
1584         *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
1585     CHECK_EXCEPTION(jni, "");
1586     if (IsNull(jni, j_output_buffer_info))
1587       break;
1588
1589     int output_buffer_index =
1590         GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1591     if (output_buffer_index == -1) {
1592       ResetCodec();
1593       return false;
1594     }
1595
1596     jlong capture_time_ms =
1597         GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1598         1000;
1599
1600     int32_t callback_status = 0;
1601     if (callback_) {
1602       jobject j_output_buffer =
1603           GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1604       bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1605       size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1606       uint8* payload = reinterpret_cast<uint8_t*>(
1607           jni->GetDirectBufferAddress(j_output_buffer));
1608       CHECK_EXCEPTION(jni, "");
1609       scoped_ptr<webrtc::EncodedImage> image(
1610           new webrtc::EncodedImage(payload, payload_size, payload_size));
1611       image->_encodedWidth = width_;
1612       image->_encodedHeight = height_;
1613       // Convert capture time to 90 kHz RTP timestamp.
1614       image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
1615       image->capture_time_ms_ = capture_time_ms;
1616       image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1617       image->_completeFrame = true;
1618
1619       webrtc::CodecSpecificInfo info;
1620       memset(&info, 0, sizeof(info));
1621       info.codecType = kVideoCodecVP8;
1622       info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1623       info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1624       info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1625
1626       // Generate a header describing a single fragment.
1627       webrtc::RTPFragmentationHeader header;
1628       memset(&header, 0, sizeof(header));
1629       header.VerifyAndAllocateFragmentationHeader(1);
1630       header.fragmentationOffset[0] = 0;
1631       header.fragmentationLength[0] = image->_length;
1632       header.fragmentationPlType[0] = 0;
1633       header.fragmentationTimeDiff[0] = 0;
1634
1635       callback_status = callback_->Encoded(*image, &info, &header);
1636     }
1637
1638     bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1639                                           j_release_output_buffer_method_,
1640                                           output_buffer_index);
1641     CHECK_EXCEPTION(jni, "");
1642     if (!success) {
1643       ResetCodec();
1644       return false;
1645     }
1646
1647     if (callback_status > 0)
1648       drop_next_input_frame_ = true;
1649     // Theoretically could handle callback_status<0 here, but unclear what that
1650     // would mean for us.
1651   }
1652
1653   return true;
1654 }
1655
1656 // Simplest-possible implementation of an encoder factory, churns out
1657 // MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1658 class MediaCodecVideoEncoderFactory
1659     : public cricket::WebRtcVideoEncoderFactory {
1660  public:
1661   MediaCodecVideoEncoderFactory();
1662   virtual ~MediaCodecVideoEncoderFactory();
1663
1664   // WebRtcVideoEncoderFactory implementation.
1665   virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1666       OVERRIDE;
1667   virtual void AddObserver(Observer* observer) OVERRIDE;
1668   virtual void RemoveObserver(Observer* observer) OVERRIDE;
1669   virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1670   virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1671
1672  private:
1673   // Empty if platform support is lacking, const after ctor returns.
1674   std::vector<VideoCodec> supported_codecs_;
1675 };
1676
1677 MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1678   JNIEnv* jni = AttachCurrentThreadIfNeeded();
1679   ScopedLocalRefFrame local_ref_frame(jni);
1680   jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1681   bool is_platform_supported = jni->CallStaticBooleanMethod(
1682       j_encoder_class,
1683       GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
1684   CHECK_EXCEPTION(jni, "");
1685   if (!is_platform_supported)
1686     return;
1687
1688   // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1689   // encoder?  Sure would be.  Too bad it doesn't.  So we hard-code some
1690   // reasonable defaults.
1691   supported_codecs_.push_back(
1692       VideoCodec(kVideoCodecVP8, "VP8", 1920, 1088, 30));
1693 }
1694
1695 MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1696
1697 webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1698     webrtc::VideoCodecType type) {
1699   if (type != kVideoCodecVP8 || supported_codecs_.empty())
1700     return NULL;
1701   return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1702 }
1703
1704 // Since the available codec list is never going to change, we ignore the
1705 // Observer-related interface here.
1706 void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1707 void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1708
1709 const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1710 MediaCodecVideoEncoderFactory::codecs() const {
1711   return supported_codecs_;
1712 }
1713
1714 void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1715     webrtc::VideoEncoder* encoder) {
1716   delete encoder;
1717 }
1718
1719 #endif  // ANDROID
1720
1721 }  // anonymous namespace
1722
1723 // Convenience macro defining JNI-accessible methods in the org.webrtc package.
1724 // Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1725 #define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1726   Java_org_webrtc_##name
1727
1728 extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1729   CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1730   g_jvm = jvm;
1731   CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1732
1733   CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey), "pthread_once");
1734
1735   CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1736
1737   JNIEnv* jni;
1738   if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1739     return -1;
1740   g_class_reference_holder = new ClassReferenceHolder(jni);
1741
1742   return JNI_VERSION_1_6;
1743 }
1744
1745 extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
1746   g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
1747   delete g_class_reference_holder;
1748   g_class_reference_holder = NULL;
1749   CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
1750   g_jvm = NULL;
1751 }
1752
1753 static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
1754   jfieldID native_dc_id = GetFieldID(jni,
1755       GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1756   jlong j_d = GetLongField(jni, j_dc, native_dc_id);
1757   return reinterpret_cast<DataChannelInterface*>(j_d);
1758 }
1759
1760 JOW(jlong, DataChannel_registerObserverNative)(
1761     JNIEnv* jni, jobject j_dc, jobject j_observer) {
1762   scoped_ptr<DataChannelObserverWrapper> observer(
1763       new DataChannelObserverWrapper(jni, j_observer));
1764   ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
1765   return jlongFromPointer(observer.release());
1766 }
1767
1768 JOW(void, DataChannel_unregisterObserverNative)(
1769     JNIEnv* jni, jobject j_dc, jlong native_observer) {
1770   ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1771   delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1772 }
1773
1774 JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1775   return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1776 }
1777
1778 JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1779   return JavaEnumFromIndex(
1780       jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1781 }
1782
1783 JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1784   uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1785   CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1786         "buffered_amount overflowed jlong!");
1787   return static_cast<jlong>(buffered_amount);
1788 }
1789
1790 JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1791   ExtractNativeDC(jni, j_dc)->Close();
1792 }
1793
1794 JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1795                                       jbyteArray data, jboolean binary) {
1796   jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1797   bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1798       talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1799       binary));
1800   jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1801   return ret;
1802 }
1803
1804 JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
1805   CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
1806 }
1807
1808 JOW(void, Logging_nativeEnableTracing)(
1809     JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1810     jint nativeSeverity) {
1811   std::string path = JavaToStdString(jni, j_path);
1812   if (nativeLevels != webrtc::kTraceNone) {
1813     webrtc::Trace::set_level_filter(nativeLevels);
1814 #ifdef ANDROID
1815     if (path != "logcat:") {
1816 #endif
1817       CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1818             "SetTraceFile failed");
1819 #ifdef ANDROID
1820     } else {
1821       // Intentionally leak this to avoid needing to reason about its lifecycle.
1822       // It keeps no state and functions only as a dispatch point.
1823       static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1824     }
1825 #endif
1826   }
1827   talk_base::LogMessage::LogToDebug(nativeSeverity);
1828 }
1829
1830 JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
1831   CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
1832 }
1833
1834 JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1835   PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1836   delete p;
1837 }
1838
1839 JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
1840   CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
1841 }
1842
1843 JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1844   delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1845 }
1846
1847 JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1848   delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1849 }
1850
1851 JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
1852   CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1853 }
1854
1855 JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1856     JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1857   return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
1858       reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1859 }
1860
1861 JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1862     JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1863   return reinterpret_cast<MediaStreamInterface*>(pointer)
1864       ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1865 }
1866
1867 JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1868     JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1869   return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
1870       reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1871 }
1872
1873 JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1874     JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1875   return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
1876       reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1877 }
1878
1879 JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1880   return JavaStringFromStdString(
1881       jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1882 }
1883
1884 JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
1885   CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
1886 }
1887
1888 JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1889     JNIEnv * jni, jclass, jobject j_observer) {
1890   return (jlong)new PCOJava(jni, j_observer);
1891 }
1892
1893 #ifdef ANDROID
1894 JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1895     JNIEnv* jni, jclass, jobject context) {
1896   CHECK(g_jvm, "JNI_OnLoad failed to run?");
1897   bool failure = false;
1898   failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm);
1899   failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1900   return !failure;
1901 }
1902 #endif  // ANDROID
1903
1904 // Helper struct for working around the fact that CreatePeerConnectionFactory()
1905 // comes in two flavors: either entirely automagical (constructing its own
1906 // threads and deleting them on teardown, but no external codec factory support)
1907 // or entirely manual (requires caller to delete threads after factory
1908 // teardown).  This struct takes ownership of its ctor's arguments to present a
1909 // single thing for Java to hold and eventually free.
1910 class OwnedFactoryAndThreads {
1911  public:
1912   OwnedFactoryAndThreads(Thread* worker_thread,
1913                          Thread* signaling_thread,
1914                          PeerConnectionFactoryInterface* factory)
1915       : worker_thread_(worker_thread),
1916         signaling_thread_(signaling_thread),
1917         factory_(factory) {}
1918
1919   ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
1920
1921   PeerConnectionFactoryInterface* factory() { return factory_; }
1922
1923  private:
1924   const scoped_ptr<Thread> worker_thread_;
1925   const scoped_ptr<Thread> signaling_thread_;
1926   PeerConnectionFactoryInterface* factory_;  // Const after ctor except dtor.
1927 };
1928
1929 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1930     JNIEnv* jni, jclass) {
1931   webrtc::Trace::CreateTrace();
1932   Thread* worker_thread = new Thread();
1933   worker_thread->SetName("worker_thread", NULL);
1934   Thread* signaling_thread = new Thread();
1935   signaling_thread->SetName("signaling_thread", NULL);
1936   CHECK(worker_thread->Start() && signaling_thread->Start(),
1937         "Failed to start threads");
1938   scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
1939 #ifdef ANDROID
1940   encoder_factory.reset(new MediaCodecVideoEncoderFactory());
1941 #endif
1942   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1943       webrtc::CreatePeerConnectionFactory(worker_thread,
1944                                           signaling_thread,
1945                                           NULL,
1946                                           encoder_factory.release(),
1947                                           NULL));
1948   OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
1949       worker_thread, signaling_thread, factory.release());
1950   return jlongFromPointer(owned_factory);
1951 }
1952
1953 JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
1954   delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
1955   webrtc::Trace::ReturnTrace();
1956 }
1957
1958 static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
1959   return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
1960 }
1961
1962 JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1963     JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1964   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1965       factoryFromJava(native_factory));
1966   talk_base::scoped_refptr<MediaStreamInterface> stream(
1967       factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1968   return (jlong)stream.release();
1969 }
1970
1971 JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1972     JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1973     jobject j_constraints) {
1974   scoped_ptr<ConstraintsWrapper> constraints(
1975       new ConstraintsWrapper(jni, j_constraints));
1976   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1977       factoryFromJava(native_factory));
1978   talk_base::scoped_refptr<VideoSourceInterface> source(
1979       factory->CreateVideoSource(
1980           reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1981           constraints.get()));
1982   return (jlong)source.release();
1983 }
1984
1985 JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1986     JNIEnv* jni, jclass, jlong native_factory, jstring id,
1987     jlong native_source) {
1988   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1989       factoryFromJava(native_factory));
1990   talk_base::scoped_refptr<VideoTrackInterface> track(
1991       factory->CreateVideoTrack(
1992           JavaToStdString(jni, id),
1993           reinterpret_cast<VideoSourceInterface*>(native_source)));
1994   return (jlong)track.release();
1995 }
1996
1997 JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
1998     JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
1999   scoped_ptr<ConstraintsWrapper> constraints(
2000       new ConstraintsWrapper(jni, j_constraints));
2001   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
2002       factoryFromJava(native_factory));
2003   talk_base::scoped_refptr<AudioSourceInterface> source(
2004       factory->CreateAudioSource(constraints.get()));
2005   return (jlong)source.release();
2006 }
2007
2008 JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2009     JNIEnv* jni, jclass, jlong native_factory, jstring id,
2010     jlong native_source) {
2011   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
2012       factoryFromJava(native_factory));
2013   talk_base::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
2014       JavaToStdString(jni, id),
2015       reinterpret_cast<AudioSourceInterface*>(native_source)));
2016   return (jlong)track.release();
2017 }
2018
2019 static void JavaIceServersToJsepIceServers(
2020     JNIEnv* jni, jobject j_ice_servers,
2021     PeerConnectionInterface::IceServers* ice_servers) {
2022   jclass list_class = GetObjectClass(jni, j_ice_servers);
2023   jmethodID iterator_id = GetMethodID(
2024       jni, list_class, "iterator", "()Ljava/util/Iterator;");
2025   jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
2026   CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2027   jmethodID iterator_has_next = GetMethodID(
2028       jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2029   jmethodID iterator_next = GetMethodID(
2030       jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2031   while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
2032     CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2033     jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
2034     CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2035     jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2036     jfieldID j_ice_server_uri_id =
2037         GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2038     jfieldID j_ice_server_username_id =
2039         GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2040     jfieldID j_ice_server_password_id =
2041         GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2042     jstring uri = reinterpret_cast<jstring>(
2043         GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2044     jstring username = reinterpret_cast<jstring>(
2045         GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2046     jstring password = reinterpret_cast<jstring>(
2047         GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2048     PeerConnectionInterface::IceServer server;
2049     server.uri = JavaToStdString(jni, uri);
2050     server.username = JavaToStdString(jni, username);
2051     server.password = JavaToStdString(jni, password);
2052     ice_servers->push_back(server);
2053   }
2054   CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2055 }
2056
2057 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2058     JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2059     jobject j_constraints, jlong observer_p) {
2060   talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
2061       reinterpret_cast<PeerConnectionFactoryInterface*>(
2062           factoryFromJava(factory)));
2063   PeerConnectionInterface::IceServers servers;
2064   JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2065   PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2066   observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
2067   talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
2068       servers, observer->constraints(), NULL, NULL, observer));
2069   return (jlong)pc.release();
2070 }
2071
2072 static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
2073     JNIEnv* jni, jobject j_pc) {
2074   jfieldID native_pc_id = GetFieldID(jni,
2075       GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2076   jlong j_p = GetLongField(jni, j_pc, native_pc_id);
2077   return talk_base::scoped_refptr<PeerConnectionInterface>(
2078       reinterpret_cast<PeerConnectionInterface*>(j_p));
2079 }
2080
2081 JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2082   const SessionDescriptionInterface* sdp =
2083       ExtractNativePC(jni, j_pc)->local_description();
2084   return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2085 }
2086
2087 JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2088   const SessionDescriptionInterface* sdp =
2089       ExtractNativePC(jni, j_pc)->remote_description();
2090   return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2091 }
2092
2093 JOW(jobject, PeerConnection_createDataChannel)(
2094     JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2095   DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
2096   talk_base::scoped_refptr<DataChannelInterface> channel(
2097       ExtractNativePC(jni, j_pc)->CreateDataChannel(
2098           JavaToStdString(jni, j_label), &init));
2099   // Mustn't pass channel.get() directly through NewObject to avoid reading its
2100   // vararg parameter as 64-bit and reading memory that doesn't belong to the
2101   // 32-bit parameter.
2102   jlong nativeChannelPtr = jlongFromPointer(channel.get());
2103   CHECK(nativeChannelPtr, "Failed to create DataChannel");
2104   jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2105   jmethodID j_data_channel_ctor = GetMethodID(
2106       jni, j_data_channel_class, "<init>", "(J)V");
2107   jobject j_channel = jni->NewObject(
2108       j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
2109   CHECK_EXCEPTION(jni, "error during NewObject");
2110   // Channel is now owned by Java object, and will be freed from there.
2111   int bumped_count = channel->AddRef();
2112   CHECK(bumped_count == 2, "Unexpected refcount");
2113   return j_channel;
2114 }
2115
2116 JOW(void, PeerConnection_createOffer)(
2117     JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2118   ConstraintsWrapper* constraints =
2119       new ConstraintsWrapper(jni, j_constraints);
2120   talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2121       new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2122           jni, j_observer, constraints));
2123   ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2124 }
2125
2126 JOW(void, PeerConnection_createAnswer)(
2127     JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2128   ConstraintsWrapper* constraints =
2129       new ConstraintsWrapper(jni, j_constraints);
2130   talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2131       new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2132           jni, j_observer, constraints));
2133   ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2134 }
2135
2136 // Helper to create a SessionDescriptionInterface from a SessionDescription.
2137 static SessionDescriptionInterface* JavaSdpToNativeSdp(
2138     JNIEnv* jni, jobject j_sdp) {
2139   jfieldID j_type_id = GetFieldID(
2140       jni, GetObjectClass(jni, j_sdp), "type",
2141       "Lorg/webrtc/SessionDescription$Type;");
2142   jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2143   jmethodID j_canonical_form_id = GetMethodID(
2144       jni, GetObjectClass(jni, j_type), "canonicalForm",
2145       "()Ljava/lang/String;");
2146   jstring j_type_string = (jstring)jni->CallObjectMethod(
2147       j_type, j_canonical_form_id);
2148   CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2149   std::string std_type = JavaToStdString(jni, j_type_string);
2150
2151   jfieldID j_description_id = GetFieldID(
2152       jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2153   jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2154   std::string std_description = JavaToStdString(jni, j_description);
2155
2156   return webrtc::CreateSessionDescription(
2157       std_type, std_description, NULL);
2158 }
2159
2160 JOW(void, PeerConnection_setLocalDescription)(
2161     JNIEnv* jni, jobject j_pc,
2162     jobject j_observer, jobject j_sdp) {
2163   talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2164       new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2165           jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2166   ExtractNativePC(jni, j_pc)->SetLocalDescription(
2167       observer, JavaSdpToNativeSdp(jni, j_sdp));
2168 }
2169
2170 JOW(void, PeerConnection_setRemoteDescription)(
2171     JNIEnv* jni, jobject j_pc,
2172     jobject j_observer, jobject j_sdp) {
2173   talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2174       new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2175           jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2176   ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2177       observer, JavaSdpToNativeSdp(jni, j_sdp));
2178 }
2179
2180 JOW(jboolean, PeerConnection_updateIce)(
2181     JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2182   PeerConnectionInterface::IceServers ice_servers;
2183   JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
2184   scoped_ptr<ConstraintsWrapper> constraints(
2185       new ConstraintsWrapper(jni, j_constraints));
2186   return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2187 }
2188
2189 JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2190     JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2191     jint j_sdp_mline_index, jstring j_candidate_sdp) {
2192   std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2193   std::string sdp = JavaToStdString(jni, j_candidate_sdp);
2194   scoped_ptr<IceCandidateInterface> candidate(
2195       webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2196   return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2197 }
2198
2199 JOW(jboolean, PeerConnection_nativeAddLocalStream)(
2200     JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
2201   scoped_ptr<ConstraintsWrapper> constraints(
2202       new ConstraintsWrapper(jni, j_constraints));
2203   return ExtractNativePC(jni, j_pc)->AddStream(
2204       reinterpret_cast<MediaStreamInterface*>(native_stream),
2205       constraints.get());
2206 }
2207
2208 JOW(void, PeerConnection_nativeRemoveLocalStream)(
2209     JNIEnv* jni, jobject j_pc, jlong native_stream) {
2210   ExtractNativePC(jni, j_pc)->RemoveStream(
2211       reinterpret_cast<MediaStreamInterface*>(native_stream));
2212 }
2213
2214 JOW(bool, PeerConnection_nativeGetStats)(
2215     JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
2216   talk_base::scoped_refptr<StatsObserverWrapper> observer(
2217       new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
2218   return ExtractNativePC(jni, j_pc)->GetStats(
2219       observer,
2220       reinterpret_cast<MediaStreamTrackInterface*>(native_track),
2221       PeerConnectionInterface::kStatsOutputLevelStandard);
2222 }
2223
2224 JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2225   PeerConnectionInterface::SignalingState state =
2226       ExtractNativePC(jni, j_pc)->signaling_state();
2227   return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2228 }
2229
2230 JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2231   PeerConnectionInterface::IceConnectionState state =
2232       ExtractNativePC(jni, j_pc)->ice_connection_state();
2233   return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2234 }
2235
2236 JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
2237   PeerConnectionInterface::IceGatheringState state =
2238       ExtractNativePC(jni, j_pc)->ice_gathering_state();
2239   return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
2240 }
2241
2242 JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2243   ExtractNativePC(jni, j_pc)->Close();
2244   return;
2245 }
2246
2247 JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
2248   talk_base::scoped_refptr<MediaSourceInterface> p(
2249       reinterpret_cast<MediaSourceInterface*>(j_p));
2250   return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2251 }
2252
2253 JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
2254     JNIEnv* jni, jclass, jstring j_device_name) {
2255   std::string device_name = JavaToStdString(jni, j_device_name);
2256   scoped_ptr<cricket::DeviceManagerInterface> device_manager(
2257       cricket::DeviceManagerFactory::Create());
2258   CHECK(device_manager->Init(), "DeviceManager::Init() failed");
2259   cricket::Device device;
2260   if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
2261     LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
2262     return 0;
2263   }
2264   scoped_ptr<cricket::VideoCapturer> capturer(
2265       device_manager->CreateVideoCapturer(device));
2266   return (jlong)capturer.release();
2267 }
2268
2269 JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2270     JNIEnv* jni, jclass, int x, int y) {
2271   scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2272       cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
2273   return (jlong)renderer.release();
2274 }
2275
2276 JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2277     JNIEnv* jni, jclass, jobject j_callbacks) {
2278   scoped_ptr<JavaVideoRendererWrapper> renderer(
2279       new JavaVideoRendererWrapper(jni, j_callbacks));
2280   return (jlong)renderer.release();
2281 }
2282
2283 JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2284   cricket::VideoCapturer* capturer =
2285       reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
2286   scoped_ptr<cricket::VideoFormatPod> format(
2287       new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2288   capturer->Stop();
2289   return jlongFromPointer(format.release());
2290 }
2291
2292 JOW(void, VideoSource_restart)(
2293     JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
2294   CHECK(j_p_source, "");
2295   CHECK(j_p_format, "");
2296   scoped_ptr<cricket::VideoFormatPod> format(
2297       reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2298   reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2299       StartCapturing(cricket::VideoFormat(*format));
2300 }
2301
2302 JOW(void, VideoSource_freeNativeVideoFormat)(
2303     JNIEnv* jni, jclass, jlong j_p) {
2304   delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2305 }
2306
2307 JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
2308   return JavaStringFromStdString(
2309       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
2310 }
2311
2312 JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
2313   return JavaStringFromStdString(
2314       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
2315 }
2316
2317 JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
2318   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
2319 }
2320
2321 JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
2322   return JavaEnumFromIndex(
2323       jni,
2324       "MediaStreamTrack$State",
2325       reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
2326 }
2327
2328 JOW(jboolean, MediaStreamTrack_nativeSetState)(
2329     JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
2330   MediaStreamTrackInterface::TrackState new_state =
2331       (MediaStreamTrackInterface::TrackState)j_new_state;
2332   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2333       ->set_state(new_state);
2334 }
2335
2336 JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2337     JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
2338   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2339       ->set_enabled(enabled);
2340 }
2341
2342 JOW(void, VideoTrack_nativeAddRenderer)(
2343     JNIEnv* jni, jclass,
2344     jlong j_video_track_pointer, jlong j_renderer_pointer) {
2345   reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
2346       reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2347 }
2348
2349 JOW(void, VideoTrack_nativeRemoveRenderer)(
2350     JNIEnv* jni, jclass,
2351     jlong j_video_track_pointer, jlong j_renderer_pointer) {
2352   reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
2353       reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2354 }