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