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