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/logging.h"
     70 #include "talk/base/ssladapter.h"
     71 #include "talk/media/base/videocapturer.h"
     72 #include "talk/media/base/videorenderer.h"
     73 #include "talk/media/devices/videorendererfactory.h"
     74 #include "talk/media/webrtc/webrtcvideocapturer.h"
     75 #include "third_party/icu/source/common/unicode/unistr.h"
     76 #include "webrtc/system_wrappers/interface/compile_assert.h"
     77 #include "webrtc/system_wrappers/interface/trace.h"
     78 #include "webrtc/video_engine/include/vie_base.h"
     79 #include "webrtc/voice_engine/include/voe_base.h"
     80 
     81 #ifdef ANDROID
     82 #include "webrtc/system_wrappers/interface/logcat_trace_context.h"
     83 using webrtc::LogcatTraceContext;
     84 #endif
     85 
     86 using icu::UnicodeString;
     87 using webrtc::AudioSourceInterface;
     88 using webrtc::AudioTrackInterface;
     89 using webrtc::AudioTrackVector;
     90 using webrtc::CreateSessionDescriptionObserver;
     91 using webrtc::DataBuffer;
     92 using webrtc::DataChannelInit;
     93 using webrtc::DataChannelInterface;
     94 using webrtc::DataChannelObserver;
     95 using webrtc::IceCandidateInterface;
     96 using webrtc::MediaConstraintsInterface;
     97 using webrtc::MediaSourceInterface;
     98 using webrtc::MediaStreamInterface;
     99 using webrtc::MediaStreamTrackInterface;
    100 using webrtc::PeerConnectionFactoryInterface;
    101 using webrtc::PeerConnectionInterface;
    102 using webrtc::PeerConnectionObserver;
    103 using webrtc::SessionDescriptionInterface;
    104 using webrtc::SetSessionDescriptionObserver;
    105 using webrtc::StatsObserver;
    106 using webrtc::StatsReport;
    107 using webrtc::VideoRendererInterface;
    108 using webrtc::VideoSourceInterface;
    109 using webrtc::VideoTrackInterface;
    110 using webrtc::VideoTrackVector;
    111 
    112 // Abort the process if |x| is false, emitting |msg|.
    113 #define CHECK(x, msg)                                                          \
    114   if (x) {} else {                                                             \
    115     LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg;               \
    116     abort();                                                                   \
    117   }
    118 // Abort the process if |jni| has a Java exception pending, emitting |msg|.
    119 #define CHECK_EXCEPTION(jni, msg)                                              \
    120   if (0) {} else {                                                             \
    121     if (jni->ExceptionCheck()) {                                               \
    122       jni->ExceptionDescribe();                                                \
    123       jni->ExceptionClear();                                                   \
    124       CHECK(0, msg);                                                           \
    125     }                                                                          \
    126   }
    127 
    128 // Helper that calls ptr->Release() and logs a useful message if that didn't
    129 // actually delete *ptr because of extra refcounts.
    130 #define CHECK_RELEASE(ptr)                                        \
    131   do {                                                            \
    132     int count = (ptr)->Release();                                 \
    133     if (count != 0) {                                             \
    134       LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr)   \
    135                     << ": " << count;                             \
    136     }                                                             \
    137     CHECK(!count, "Unexpected refcount");                         \
    138   } while (0)
    139 
    140 namespace {
    141 
    142 static JavaVM* g_jvm = NULL;  // Set in JNI_OnLoad().
    143 
    144 static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
    145 static pthread_key_t g_jni_ptr;  // Key for per-thread JNIEnv* data.
    146 
    147 // Return thread ID as a string.
    148 static std::string GetThreadId() {
    149   char buf[21];  // Big enough to hold a kuint64max plus terminating NULL.
    150   CHECK(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)) <= sizeof(buf),
    151         "Thread id is bigger than uint64??");
    152   return std::string(buf);
    153 }
    154 
    155 // Return the current thread's name.
    156 static std::string GetThreadName() {
    157   char name[17];
    158   CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
    159   name[16] = '\0';
    160   return std::string(name);
    161 }
    162 
    163 static void ThreadDestructor(void* unused) {
    164   jint status = g_jvm->DetachCurrentThread();
    165   CHECK(status == JNI_OK, "Failed to detach thread: " << status);
    166 }
    167 
    168 static void CreateJNIPtrKey() {
    169   CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
    170         "pthread_key_create");
    171 }
    172 
    173 // Deal with difference in signatures between Oracle's jni.h and Android's.
    174 static JNIEnv* AttachCurrentThreadIfNeeded() {
    175   CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
    176         "pthread_once");
    177   JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
    178   if (jni == NULL) {
    179 #ifdef _JAVASOFT_JNI_H_  // Oracle's jni.h violates the JNI spec!
    180     void* env;
    181 #else
    182     JNIEnv* env;
    183 #endif
    184     char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
    185     JavaVMAttachArgs args;
    186     args.version = JNI_VERSION_1_6;
    187     args.name = name;
    188     args.group = NULL;
    189     CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
    190     free(name);
    191     CHECK(env, "AttachCurrentThread handed back NULL!");
    192     jni = reinterpret_cast<JNIEnv*>(env);
    193     CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
    194   }
    195   return jni;
    196 }
    197 
    198 // Return a |jlong| that will correctly convert back to |ptr|.  This is needed
    199 // because the alternative (of silently passing a 32-bit pointer to a vararg
    200 // function expecting a 64-bit param) picks up garbage in the high 32 bits.
    201 static jlong jlongFromPointer(void* ptr) {
    202   COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
    203                  Time_to_rethink_the_use_of_jlongs);
    204   // Going through intptr_t to be obvious about the definedness of the
    205   // conversion from pointer to integral type.  intptr_t to jlong is a standard
    206   // widening by the COMPILE_ASSERT above.
    207   jlong ret = reinterpret_cast<intptr_t>(ptr);
    208   assert(reinterpret_cast<void*>(ret) == ptr);
    209   return ret;
    210 }
    211 
    212 // Android's FindClass() is trickier than usual because the app-specific
    213 // ClassLoader is not consulted when there is no app-specific frame on the
    214 // stack.  Consequently, we only look up classes once in JNI_OnLoad.
    215 // http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
    216 class ClassReferenceHolder {
    217  public:
    218   explicit ClassReferenceHolder(JNIEnv* jni) {
    219     LoadClass(jni, "java/nio/ByteBuffer");
    220     LoadClass(jni, "org/webrtc/AudioTrack");
    221     LoadClass(jni, "org/webrtc/DataChannel");
    222     LoadClass(jni, "org/webrtc/DataChannel$Buffer");
    223     LoadClass(jni, "org/webrtc/DataChannel$Init");
    224     LoadClass(jni, "org/webrtc/DataChannel$State");
    225     LoadClass(jni, "org/webrtc/IceCandidate");
    226     LoadClass(jni, "org/webrtc/MediaSource$State");
    227     LoadClass(jni, "org/webrtc/MediaStream");
    228     LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
    229     LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
    230     LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
    231     LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
    232     LoadClass(jni, "org/webrtc/SessionDescription");
    233     LoadClass(jni, "org/webrtc/SessionDescription$Type");
    234     LoadClass(jni, "org/webrtc/StatsReport");
    235     LoadClass(jni, "org/webrtc/StatsReport$Value");
    236     LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
    237     LoadClass(jni, "org/webrtc/VideoTrack");
    238   }
    239 
    240   ~ClassReferenceHolder() {
    241     CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
    242   }
    243 
    244   void FreeReferences(JNIEnv* jni) {
    245     for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
    246          it != classes_.end(); ++it) {
    247       jni->DeleteGlobalRef(it->second);
    248     }
    249     classes_.clear();
    250   }
    251 
    252   jclass GetClass(const std::string& name) {
    253     std::map<std::string, jclass>::iterator it = classes_.find(name);
    254     CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
    255     return it->second;
    256   }
    257 
    258  private:
    259   void LoadClass(JNIEnv* jni, const std::string& name) {
    260     jclass localRef = jni->FindClass(name.c_str());
    261     CHECK_EXCEPTION(jni, "error during FindClass: " << name);
    262     CHECK(localRef, name);
    263     jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
    264     CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
    265     CHECK(globalRef, name);
    266     bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
    267     CHECK(inserted, "Duplicate class name: " << name);
    268   }
    269 
    270   std::map<std::string, jclass> classes_;
    271 };
    272 
    273 // Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
    274 static ClassReferenceHolder* g_class_reference_holder = NULL;
    275 
    276 // JNIEnv-helper methods that CHECK success: no Java exception thrown and found
    277 // object/class/method/field is non-null.
    278 jmethodID GetMethodID(
    279     JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
    280   jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
    281   CHECK_EXCEPTION(jni,
    282                   "error during GetMethodID: " << name << ", " << signature);
    283   CHECK(m, name << ", " << signature);
    284   return m;
    285 }
    286 
    287 jmethodID GetStaticMethodID(
    288     JNIEnv* jni, jclass c, const char* name, const char* signature) {
    289   jmethodID m = jni->GetStaticMethodID(c, name, signature);
    290   CHECK_EXCEPTION(jni,
    291                   "error during GetStaticMethodID: "
    292                   << name << ", " << signature);
    293   CHECK(m, name << ", " << signature);
    294   return m;
    295 }
    296 
    297 jfieldID GetFieldID(
    298     JNIEnv* jni, jclass c, const char* name, const char* signature) {
    299   jfieldID f = jni->GetFieldID(c, name, signature);
    300   CHECK_EXCEPTION(jni, "error during GetFieldID");
    301   CHECK(f, name << ", " << signature);
    302   return f;
    303 }
    304 
    305 jclass FindClass(JNIEnv* jni, const char* name) {
    306   return g_class_reference_holder->GetClass(name);
    307 }
    308 
    309 jclass GetObjectClass(JNIEnv* jni, jobject object) {
    310   jclass c = jni->GetObjectClass(object);
    311   CHECK_EXCEPTION(jni, "error during GetObjectClass");
    312   CHECK(c, "");
    313   return c;
    314 }
    315 
    316 jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
    317   jobject o = jni->GetObjectField(object, id);
    318   CHECK_EXCEPTION(jni, "error during GetObjectField");
    319   CHECK(o, "");
    320   return o;
    321 }
    322 
    323 jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
    324   return static_cast<jstring>(GetObjectField(jni, object, id));
    325 }
    326 
    327 jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
    328   jlong l = jni->GetLongField(object, id);
    329   CHECK_EXCEPTION(jni, "error during GetLongField");
    330   return l;
    331 }
    332 
    333 jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
    334   jint i = jni->GetIntField(object, id);
    335   CHECK_EXCEPTION(jni, "error during GetIntField");
    336   return i;
    337 }
    338 
    339 bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
    340   jboolean b = jni->GetBooleanField(object, id);
    341   CHECK_EXCEPTION(jni, "error during GetBooleanField");
    342   return b;
    343 }
    344 
    345 jobject NewGlobalRef(JNIEnv* jni, jobject o) {
    346   jobject ret = jni->NewGlobalRef(o);
    347   CHECK_EXCEPTION(jni, "error during NewGlobalRef");
    348   CHECK(ret, "");
    349   return ret;
    350 }
    351 
    352 void DeleteGlobalRef(JNIEnv* jni, jobject o) {
    353   jni->DeleteGlobalRef(o);
    354   CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
    355 }
    356 
    357 // Given a jweak reference, allocate a (strong) local reference scoped to the
    358 // lifetime of this object if the weak reference is still valid, or NULL
    359 // otherwise.
    360 class WeakRef {
    361  public:
    362   WeakRef(JNIEnv* jni, jweak ref)
    363       : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
    364     CHECK_EXCEPTION(jni, "error during NewLocalRef");
    365   }
    366   ~WeakRef() {
    367     if (obj_) {
    368       jni_->DeleteLocalRef(obj_);
    369       CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
    370     }
    371   }
    372   jobject obj() { return obj_; }
    373 
    374  private:
    375   JNIEnv* const jni_;
    376   jobject const obj_;
    377 };
    378 
    379 // Given a local ref, take ownership of it and delete the ref when this goes out
    380 // of scope.
    381 template<class T>  // T is jclass, jobject, jintArray, etc.
    382 class ScopedLocalRef {
    383  public:
    384   ScopedLocalRef(JNIEnv* jni, T obj)
    385       : jni_(jni), obj_(obj) {}
    386   ~ScopedLocalRef() {
    387     jni_->DeleteLocalRef(obj_);
    388   }
    389   T operator*() const {
    390     return obj_;
    391   }
    392  private:
    393   JNIEnv* jni_;
    394   T obj_;
    395 };
    396 
    397 // Scoped holder for global Java refs.
    398 template<class T>  // T is jclass, jobject, jintArray, etc.
    399 class ScopedGlobalRef {
    400  public:
    401   explicit ScopedGlobalRef(JNIEnv* jni, T obj)
    402       : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
    403   ~ScopedGlobalRef() {
    404     DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
    405   }
    406   T operator*() const {
    407     return obj_;
    408   }
    409  private:
    410   T obj_;
    411 };
    412 
    413 // Return the (singleton) Java Enum object corresponding to |index|;
    414 // |state_class_fragment| is something like "MediaSource$State".
    415 jobject JavaEnumFromIndex(
    416     JNIEnv* jni, const std::string& state_class_fragment, int index) {
    417   std::string state_class_name = "org/webrtc/" + state_class_fragment;
    418   jclass state_class = FindClass(jni, state_class_name.c_str());
    419   jmethodID state_values_id = GetStaticMethodID(
    420       jni, state_class, "values", ("()[L" + state_class_name  + ";").c_str());
    421   ScopedLocalRef<jobjectArray> state_values(
    422       jni,
    423       (jobjectArray)jni->CallStaticObjectMethod(state_class, state_values_id));
    424   CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
    425   jobject ret = jni->GetObjectArrayElement(*state_values, index);
    426   CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
    427   return ret;
    428 }
    429 
    430 // Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
    431 static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
    432   UnicodeString ustr(UnicodeString::fromUTF8(native));
    433   jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
    434   CHECK_EXCEPTION(jni, "error during NewString");
    435   return jstr;
    436 }
    437 
    438 // Given a (UTF-16) jstring return a new UTF-8 native string.
    439 static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
    440   const jchar* jchars = jni->GetStringChars(j_string, NULL);
    441   CHECK_EXCEPTION(jni, "Error during GetStringChars");
    442   UnicodeString ustr(jchars, jni->GetStringLength(j_string));
    443   CHECK_EXCEPTION(jni, "Error during GetStringLength");
    444   jni->ReleaseStringChars(j_string, jchars);
    445   CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
    446   std::string ret;
    447   return ustr.toUTF8String(ret);
    448 }
    449 
    450 static DataChannelInit JavaDataChannelInitToNative(
    451     JNIEnv* jni, jobject j_init) {
    452   DataChannelInit init;
    453 
    454   jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
    455   jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
    456   jfieldID max_retransmit_time_id =
    457       GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
    458   jfieldID max_retransmits_id =
    459       GetFieldID(jni, j_init_class, "maxRetransmits", "I");
    460   jfieldID protocol_id =
    461       GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
    462   jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
    463   jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
    464 
    465   init.ordered = GetBooleanField(jni, j_init, ordered_id);
    466   init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
    467   init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
    468   init.protocol = JavaToStdString(
    469       jni, GetStringField(jni, j_init, protocol_id));
    470   init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
    471   init.id = GetIntField(jni, j_init, id_id);
    472 
    473   return init;
    474 }
    475 
    476 class ConstraintsWrapper;
    477 
    478 // Adapter between the C++ PeerConnectionObserver interface and the Java
    479 // PeerConnection.Observer interface.  Wraps an instance of the Java interface
    480 // and dispatches C++ callbacks to Java.
    481 class PCOJava : public PeerConnectionObserver {
    482  public:
    483   PCOJava(JNIEnv* jni, jobject j_observer)
    484       : j_observer_global_(jni, j_observer),
    485         j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
    486         j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
    487         j_media_stream_ctor_(GetMethodID(
    488             jni, *j_media_stream_class_, "<init>", "(J)V")),
    489         j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
    490         j_audio_track_ctor_(GetMethodID(
    491             jni, *j_audio_track_class_, "<init>", "(J)V")),
    492         j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
    493         j_video_track_ctor_(GetMethodID(
    494             jni, *j_video_track_class_, "<init>", "(J)V")),
    495         j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
    496         j_data_channel_ctor_(GetMethodID(
    497             jni, *j_data_channel_class_, "<init>", "(J)V")) {
    498   }
    499 
    500   virtual ~PCOJava() {}
    501 
    502   virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
    503     std::string sdp;
    504     CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
    505     jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
    506     jmethodID ctor = GetMethodID(jni(), candidate_class,
    507         "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
    508     ScopedLocalRef<jstring> j_mid(
    509         jni(), JavaStringFromStdString(jni(), candidate->sdp_mid()));
    510     ScopedLocalRef<jstring> j_sdp(jni(), JavaStringFromStdString(jni(), sdp));
    511     ScopedLocalRef<jobject> j_candidate(jni(), jni()->NewObject(
    512         candidate_class, ctor, *j_mid, candidate->sdp_mline_index(), *j_sdp));
    513     CHECK_EXCEPTION(jni(), "error during NewObject");
    514     jmethodID m = GetMethodID(jni(), *j_observer_class_,
    515                               "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
    516     jni()->CallVoidMethod(*j_observer_global_, m, *j_candidate);
    517     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    518   }
    519 
    520   virtual void OnError() OVERRIDE {
    521     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "(V)V");
    522     jni()->CallVoidMethod(*j_observer_global_, m);
    523     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    524   }
    525 
    526   virtual void OnSignalingChange(
    527       PeerConnectionInterface::SignalingState new_state) OVERRIDE {
    528     jmethodID m = GetMethodID(
    529         jni(), *j_observer_class_, "onSignalingChange",
    530         "(Lorg/webrtc/PeerConnection$SignalingState;)V");
    531     ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
    532         jni(), "PeerConnection$SignalingState", new_state));
    533     jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
    534     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    535   }
    536 
    537   virtual void OnIceConnectionChange(
    538       PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
    539     jmethodID m = GetMethodID(
    540         jni(), *j_observer_class_, "onIceConnectionChange",
    541         "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
    542     ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
    543         jni(), "PeerConnection$IceConnectionState", new_state));
    544     jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
    545     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    546   }
    547 
    548   virtual void OnIceGatheringChange(
    549       PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
    550     jmethodID m = GetMethodID(
    551         jni(), *j_observer_class_, "onIceGatheringChange",
    552         "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
    553     ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
    554         jni(), "PeerConnection$IceGatheringState", new_state));
    555     jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
    556     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    557   }
    558 
    559   virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
    560     ScopedLocalRef<jobject> j_stream(jni(), jni()->NewObject(
    561         *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream));
    562     CHECK_EXCEPTION(jni(), "error during NewObject");
    563 
    564     AudioTrackVector audio_tracks = stream->GetAudioTracks();
    565     for (size_t i = 0; i < audio_tracks.size(); ++i) {
    566       AudioTrackInterface* track = audio_tracks[i];
    567       ScopedLocalRef<jstring> id(
    568           jni(), JavaStringFromStdString(jni(), track->id()));
    569       ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
    570           *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
    571       CHECK_EXCEPTION(jni(), "error during NewObject");
    572       jfieldID audio_tracks_id = GetFieldID(jni(),
    573                                             *j_media_stream_class_,
    574                                             "audioTracks",
    575                                             "Ljava/util/LinkedList;");
    576       ScopedLocalRef<jobject> audio_tracks(jni(), GetObjectField(
    577           jni(), *j_stream, audio_tracks_id));
    578       jmethodID add = GetMethodID(jni(),
    579           GetObjectClass(jni(), *audio_tracks), "add", "(Ljava/lang/Object;)Z");
    580       jboolean added = jni()->CallBooleanMethod(*audio_tracks, add, *j_track);
    581       CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
    582       CHECK(added, "");
    583     }
    584 
    585     VideoTrackVector video_tracks = stream->GetVideoTracks();
    586     for (size_t i = 0; i < video_tracks.size(); ++i) {
    587       VideoTrackInterface* track = video_tracks[i];
    588       ScopedLocalRef<jstring> id(
    589           jni(), JavaStringFromStdString(jni(), track->id()));
    590       ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
    591           *j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
    592       CHECK_EXCEPTION(jni(), "error during NewObject");
    593       jfieldID video_tracks_id = GetFieldID(jni(),
    594                                             *j_media_stream_class_,
    595                                             "videoTracks",
    596                                             "Ljava/util/LinkedList;");
    597       ScopedLocalRef<jobject> video_tracks(jni(), GetObjectField(
    598           jni(), *j_stream, video_tracks_id));
    599       jmethodID add = GetMethodID(jni(),
    600           GetObjectClass(jni(), *video_tracks), "add", "(Ljava/lang/Object;)Z");
    601       jboolean added = jni()->CallBooleanMethod(*video_tracks, add, *j_track);
    602       CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
    603       CHECK(added, "");
    604     }
    605     streams_[stream] = jni()->NewWeakGlobalRef(*j_stream);
    606     CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
    607 
    608     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
    609                               "(Lorg/webrtc/MediaStream;)V");
    610     jni()->CallVoidMethod(*j_observer_global_, m, *j_stream);
    611     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    612   }
    613 
    614   virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
    615     NativeToJavaStreamsMap::iterator it = streams_.find(stream);
    616     CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
    617 
    618     WeakRef s(jni(), it->second);
    619     streams_.erase(it);
    620     if (!s.obj())
    621       return;
    622 
    623     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
    624                               "(Lorg/webrtc/MediaStream;)V");
    625     jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
    626     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    627   }
    628 
    629   virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
    630     ScopedLocalRef<jobject> j_channel(jni(), jni()->NewObject(
    631         *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel));
    632     CHECK_EXCEPTION(jni(), "error during NewObject");
    633 
    634     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
    635                               "(Lorg/webrtc/DataChannel;)V");
    636     jni()->CallVoidMethod(*j_observer_global_, m, *j_channel);
    637 
    638     // Channel is now owned by Java object, and will be freed from
    639     // DataChannel.dispose().  Important that this be done _after_ the
    640     // CallVoidMethod above as Java code might call back into native code and be
    641     // surprised to see a refcount of 2.
    642     int bumped_count = channel->AddRef();
    643     CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
    644 
    645     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    646   }
    647 
    648   void SetConstraints(ConstraintsWrapper* constraints) {
    649     CHECK(!constraints_.get(), "constraints already set!");
    650     constraints_.reset(constraints);
    651   }
    652 
    653   const ConstraintsWrapper* constraints() { return constraints_.get(); }
    654 
    655  private:
    656   JNIEnv* jni() {
    657     return AttachCurrentThreadIfNeeded();
    658   }
    659 
    660   const ScopedGlobalRef<jobject> j_observer_global_;
    661   const ScopedGlobalRef<jclass> j_observer_class_;
    662   const ScopedGlobalRef<jclass> j_media_stream_class_;
    663   const jmethodID j_media_stream_ctor_;
    664   const ScopedGlobalRef<jclass> j_audio_track_class_;
    665   const jmethodID j_audio_track_ctor_;
    666   const ScopedGlobalRef<jclass> j_video_track_class_;
    667   const jmethodID j_video_track_ctor_;
    668   const ScopedGlobalRef<jclass> j_data_channel_class_;
    669   const jmethodID j_data_channel_ctor_;
    670   typedef std::map<void*, jweak> NativeToJavaStreamsMap;
    671   NativeToJavaStreamsMap streams_;  // C++ -> Java streams.
    672   talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
    673 };
    674 
    675 // Wrapper for a Java MediaConstraints object.  Copies all needed data so when
    676 // the constructor returns the Java object is no longer needed.
    677 class ConstraintsWrapper : public MediaConstraintsInterface {
    678  public:
    679   ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
    680     PopulateConstraintsFromJavaPairList(
    681         jni, j_constraints, "mandatory", &mandatory_);
    682     PopulateConstraintsFromJavaPairList(
    683         jni, j_constraints, "optional", &optional_);
    684   }
    685 
    686   virtual ~ConstraintsWrapper() {}
    687 
    688   // MediaConstraintsInterface.
    689   virtual const Constraints& GetMandatory() const OVERRIDE {
    690     return mandatory_;
    691   }
    692 
    693   virtual const Constraints& GetOptional() const OVERRIDE {
    694     return optional_;
    695   }
    696 
    697  private:
    698   // Helper for translating a List<Pair<String, String>> to a Constraints.
    699   static void PopulateConstraintsFromJavaPairList(
    700       JNIEnv* jni, jobject j_constraints,
    701       const char* field_name, Constraints* field) {
    702     jfieldID j_id = GetFieldID(jni,
    703         GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
    704     jobject j_list = GetObjectField(jni, j_constraints, j_id);
    705     jmethodID j_iterator_id = GetMethodID(jni,
    706         GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
    707     jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
    708     CHECK_EXCEPTION(jni, "error during CallObjectMethod");
    709     jmethodID j_has_next = GetMethodID(jni,
    710         GetObjectClass(jni, j_iterator), "hasNext", "()Z");
    711     jmethodID j_next = GetMethodID(jni,
    712         GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
    713     while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
    714       CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
    715       jobject entry = jni->CallObjectMethod(j_iterator, j_next);
    716       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
    717       jmethodID get_key = GetMethodID(jni,
    718           GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
    719       jstring j_key = reinterpret_cast<jstring>(
    720           jni->CallObjectMethod(entry, get_key));
    721       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
    722       jmethodID get_value = GetMethodID(jni,
    723           GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
    724       jstring j_value = reinterpret_cast<jstring>(
    725           jni->CallObjectMethod(entry, get_value));
    726       CHECK_EXCEPTION(jni, "error during CallObjectMethod");
    727       field->push_back(Constraint(JavaToStdString(jni, j_key),
    728                                   JavaToStdString(jni, j_value)));
    729     }
    730     CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
    731   }
    732 
    733   Constraints mandatory_;
    734   Constraints optional_;
    735 };
    736 
    737 static jobject JavaSdpFromNativeSdp(
    738     JNIEnv* jni, const SessionDescriptionInterface* desc) {
    739   std::string sdp;
    740   CHECK(desc->ToString(&sdp), "got so far: " << sdp);
    741   ScopedLocalRef<jstring> j_description(jni, JavaStringFromStdString(jni, sdp));
    742 
    743   jclass j_type_class = FindClass(
    744       jni, "org/webrtc/SessionDescription$Type");
    745   jmethodID j_type_from_canonical = GetStaticMethodID(
    746       jni, j_type_class, "fromCanonicalForm",
    747       "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
    748   ScopedLocalRef<jstring> j_type_string(
    749       jni, JavaStringFromStdString(jni, desc->type()));
    750   jobject j_type = jni->CallStaticObjectMethod(
    751       j_type_class, j_type_from_canonical, *j_type_string);
    752   CHECK_EXCEPTION(jni, "error during CallObjectMethod");
    753 
    754   jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
    755   jmethodID j_sdp_ctor = GetMethodID(
    756       jni, j_sdp_class, "<init>",
    757       "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
    758   jobject j_sdp = jni->NewObject(
    759       j_sdp_class, j_sdp_ctor, j_type, *j_description);
    760   CHECK_EXCEPTION(jni, "error during NewObject");
    761   return j_sdp;
    762 }
    763 
    764 template <class T>  // T is one of {Create,Set}SessionDescriptionObserver.
    765 class SdpObserverWrapper : public T {
    766  public:
    767   SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
    768                      ConstraintsWrapper* constraints)
    769       : constraints_(constraints),
    770         j_observer_global_(jni, j_observer),
    771         j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
    772   }
    773 
    774   virtual ~SdpObserverWrapper() {}
    775 
    776   // Can't mark OVERRIDE because of templating.
    777   virtual void OnSuccess() {
    778     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
    779     jni()->CallVoidMethod(*j_observer_global_, m);
    780     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    781   }
    782 
    783   // Can't mark OVERRIDE because of templating.
    784   virtual void OnSuccess(SessionDescriptionInterface* desc) {
    785     jmethodID m = GetMethodID(
    786         jni(), *j_observer_class_, "onCreateSuccess",
    787         "(Lorg/webrtc/SessionDescription;)V");
    788     ScopedLocalRef<jobject> j_sdp(jni(), JavaSdpFromNativeSdp(jni(), desc));
    789     jni()->CallVoidMethod(*j_observer_global_, m, *j_sdp);
    790     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    791   }
    792 
    793  protected:
    794   // Common implementation for failure of Set & Create types, distinguished by
    795   // |op| being "Set" or "Create".
    796   void OnFailure(const std::string& op, const std::string& error) {
    797     jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
    798                               "(Ljava/lang/String;)V");
    799     ScopedLocalRef<jstring> j_error_string(
    800         jni(), JavaStringFromStdString(jni(), error));
    801     jni()->CallVoidMethod(*j_observer_global_, m, *j_error_string);
    802     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    803   }
    804 
    805  private:
    806   JNIEnv* jni() {
    807     return AttachCurrentThreadIfNeeded();
    808   }
    809 
    810   talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
    811   const ScopedGlobalRef<jobject> j_observer_global_;
    812   const ScopedGlobalRef<jclass> j_observer_class_;
    813 };
    814 
    815 class CreateSdpObserverWrapper
    816     : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
    817  public:
    818   CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
    819                            ConstraintsWrapper* constraints)
    820       : SdpObserverWrapper(jni, j_observer, constraints) {}
    821 
    822   virtual void OnFailure(const std::string& error) OVERRIDE {
    823     SdpObserverWrapper::OnFailure(std::string("Create"), error);
    824   }
    825 };
    826 
    827 class SetSdpObserverWrapper
    828     : public SdpObserverWrapper<SetSessionDescriptionObserver> {
    829  public:
    830   SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
    831                         ConstraintsWrapper* constraints)
    832       : SdpObserverWrapper(jni, j_observer, constraints) {}
    833 
    834   virtual void OnFailure(const std::string& error) OVERRIDE {
    835     SdpObserverWrapper::OnFailure(std::string("Set"), error);
    836   }
    837 };
    838 
    839 // Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
    840 // and dispatching the callback from C++ back to Java.
    841 class DataChannelObserverWrapper : public DataChannelObserver {
    842  public:
    843   DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
    844       : j_observer_global_(jni, j_observer),
    845         j_observer_class_(jni, GetObjectClass(jni, j_observer)),
    846         j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
    847                                            "onStateChange", "()V")),
    848         j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
    849                                       "(Lorg/webrtc/DataChannel$Buffer;)V")),
    850         j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
    851         j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
    852                                    "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
    853   }
    854 
    855   virtual ~DataChannelObserverWrapper() {}
    856 
    857   virtual void OnStateChange() OVERRIDE {
    858     jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
    859     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    860   }
    861 
    862   virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
    863     jobject byte_buffer =
    864         jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
    865                                    buffer.data.length());
    866     jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
    867                                         byte_buffer, buffer.binary);
    868     jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
    869     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    870   }
    871 
    872  private:
    873   JNIEnv* jni() {
    874     return AttachCurrentThreadIfNeeded();
    875   }
    876 
    877   const ScopedGlobalRef<jobject> j_observer_global_;
    878   const ScopedGlobalRef<jclass> j_observer_class_;
    879   const ScopedGlobalRef<jclass> j_buffer_class_;
    880   const jmethodID j_on_state_change_mid_;
    881   const jmethodID j_on_message_mid_;
    882   const jmethodID j_buffer_ctor_;
    883 };
    884 
    885 // Adapter for a Java StatsObserver presenting a C++ StatsObserver and
    886 // dispatching the callback from C++ back to Java.
    887 class StatsObserverWrapper : public StatsObserver {
    888  public:
    889   StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
    890       : j_observer_global_(jni, j_observer),
    891         j_observer_class_(jni, GetObjectClass(jni, j_observer)),
    892         j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
    893         j_stats_report_ctor_(GetMethodID(
    894             jni, *j_stats_report_class_, "<init>",
    895             "(Ljava/lang/String;Ljava/lang/String;D"
    896             "[Lorg/webrtc/StatsReport$Value;)V")),
    897         j_value_class_(jni, FindClass(
    898             jni, "org/webrtc/StatsReport$Value")),
    899         j_value_ctor_(GetMethodID(
    900             jni, *j_value_class_, "<init>",
    901             "(Ljava/lang/String;Ljava/lang/String;)V")) {
    902   }
    903 
    904   virtual ~StatsObserverWrapper() {}
    905 
    906   virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
    907     ScopedLocalRef<jobjectArray> j_reports(jni(),
    908                                            ReportsToJava(jni(), reports));
    909     jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
    910                               "([Lorg/webrtc/StatsReport;)V");
    911     jni()->CallVoidMethod(*j_observer_global_, m, *j_reports);
    912     CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
    913   }
    914 
    915  private:
    916   jobjectArray ReportsToJava(
    917       JNIEnv* jni, const std::vector<StatsReport>& reports) {
    918     jobjectArray reports_array = jni->NewObjectArray(
    919         reports.size(), *j_stats_report_class_, NULL);
    920     for (int i = 0; i < reports.size(); ++i) {
    921       const StatsReport& report = reports[i];
    922       ScopedLocalRef<jstring> j_id(
    923           jni, JavaStringFromStdString(jni, report.id));
    924       ScopedLocalRef<jstring> j_type(
    925           jni, JavaStringFromStdString(jni, report.type));
    926       ScopedLocalRef<jobjectArray> j_values(
    927           jni, ValuesToJava(jni, report.values));
    928       ScopedLocalRef<jobject> j_report(jni, jni->NewObject(
    929           *j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type,
    930           report.timestamp, *j_values));
    931       jni->SetObjectArrayElement(reports_array, i, *j_report);
    932     }
    933     return reports_array;
    934   }
    935 
    936   jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
    937     jobjectArray j_values = jni->NewObjectArray(
    938         values.size(), *j_value_class_, NULL);
    939     for (int i = 0; i < values.size(); ++i) {
    940       const StatsReport::Value& value = values[i];
    941       ScopedLocalRef<jstring> j_name(
    942           jni, JavaStringFromStdString(jni, value.name));
    943       ScopedLocalRef<jstring> j_value(
    944           jni, JavaStringFromStdString(jni, value.value));
    945       ScopedLocalRef<jobject> j_element_value(jni, jni->NewObject(
    946           *j_value_class_, j_value_ctor_, *j_name, *j_value));
    947       jni->SetObjectArrayElement(j_values, i, *j_element_value);
    948     }
    949     return j_values;
    950   }
    951 
    952   JNIEnv* jni() {
    953     return AttachCurrentThreadIfNeeded();
    954   }
    955 
    956   const ScopedGlobalRef<jobject> j_observer_global_;
    957   const ScopedGlobalRef<jclass> j_observer_class_;
    958   const ScopedGlobalRef<jclass> j_stats_report_class_;
    959   const jmethodID j_stats_report_ctor_;
    960   const ScopedGlobalRef<jclass> j_value_class_;
    961   const jmethodID j_value_ctor_;
    962 };
    963 
    964 // Adapter presenting a cricket::VideoRenderer as a
    965 // webrtc::VideoRendererInterface.
    966 class VideoRendererWrapper : public VideoRendererInterface {
    967  public:
    968   static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
    969     if (renderer)
    970       return new VideoRendererWrapper(renderer);
    971     return NULL;
    972   }
    973 
    974   virtual ~VideoRendererWrapper() {}
    975 
    976   virtual void SetSize(int width, int height) OVERRIDE {
    977     const bool kNotReserved = false;  // What does this param mean??
    978     renderer_->SetSize(width, height, kNotReserved);
    979   }
    980 
    981   virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
    982     renderer_->RenderFrame(frame);
    983   }
    984 
    985  private:
    986   explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
    987       : renderer_(renderer) {}
    988 
    989   talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
    990 };
    991 
    992 // Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
    993 // instance.
    994 class JavaVideoRendererWrapper : public VideoRendererInterface {
    995  public:
    996   JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
    997       : j_callbacks_(jni, j_callbacks),
    998         j_set_size_id_(GetMethodID(
    999             jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
   1000         j_render_frame_id_(GetMethodID(
   1001             jni, GetObjectClass(jni, j_callbacks), "renderFrame",
   1002             "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
   1003         j_frame_class_(jni,
   1004                        FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
   1005         j_frame_ctor_id_(GetMethodID(
   1006             jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
   1007         j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
   1008     CHECK_EXCEPTION(jni, "");
   1009   }
   1010 
   1011   virtual ~JavaVideoRendererWrapper() {}
   1012 
   1013   virtual void SetSize(int width, int height) OVERRIDE {
   1014     jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
   1015     CHECK_EXCEPTION(jni(), "");
   1016   }
   1017 
   1018   virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
   1019     ScopedLocalRef<jobject> j_frame(jni(), CricketToJavaFrame(frame));
   1020     jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, *j_frame);
   1021     CHECK_EXCEPTION(jni(), "");
   1022   }
   1023 
   1024  private:
   1025   // Return a VideoRenderer.I420Frame referring to the data in |frame|.
   1026   jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
   1027     ScopedLocalRef<jintArray> strides(jni(), jni()->NewIntArray(3));
   1028     jint* strides_array = jni()->GetIntArrayElements(*strides, NULL);
   1029     strides_array[0] = frame->GetYPitch();
   1030     strides_array[1] = frame->GetUPitch();
   1031     strides_array[2] = frame->GetVPitch();
   1032     jni()->ReleaseIntArrayElements(*strides, strides_array, 0);
   1033     ScopedLocalRef<jobjectArray> planes(
   1034         jni(), jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL));
   1035     ScopedLocalRef<jobject> y_buffer(jni(), jni()->NewDirectByteBuffer(
   1036         const_cast<uint8*>(frame->GetYPlane()),
   1037         frame->GetYPitch() * frame->GetHeight()));
   1038     ScopedLocalRef<jobject> u_buffer(jni(), jni()->NewDirectByteBuffer(
   1039         const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize()));
   1040     ScopedLocalRef<jobject> v_buffer(jni(), jni()->NewDirectByteBuffer(
   1041         const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize()));
   1042     jni()->SetObjectArrayElement(*planes, 0, *y_buffer);
   1043     jni()->SetObjectArrayElement(*planes, 1, *u_buffer);
   1044     jni()->SetObjectArrayElement(*planes, 2, *v_buffer);
   1045     return jni()->NewObject(
   1046         *j_frame_class_, j_frame_ctor_id_,
   1047         frame->GetWidth(), frame->GetHeight(), *strides, *planes);
   1048   }
   1049 
   1050   JNIEnv* jni() {
   1051     return AttachCurrentThreadIfNeeded();
   1052   }
   1053 
   1054   ScopedGlobalRef<jobject> j_callbacks_;
   1055   jmethodID j_set_size_id_;
   1056   jmethodID j_render_frame_id_;
   1057   ScopedGlobalRef<jclass> j_frame_class_;
   1058   jmethodID j_frame_ctor_id_;
   1059   ScopedGlobalRef<jclass> j_byte_buffer_class_;
   1060 };
   1061 
   1062 }  // anonymous namespace
   1063 
   1064 
   1065 // Convenience macro defining JNI-accessible methods in the org.webrtc package.
   1066 // Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
   1067 #define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
   1068   Java_org_webrtc_##name
   1069 
   1070 extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
   1071   CHECK(!g_jvm, "JNI_OnLoad called more than once!");
   1072   g_jvm = jvm;
   1073   CHECK(g_jvm, "JNI_OnLoad handed NULL?");
   1074 
   1075   CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
   1076 
   1077   JNIEnv* jni;
   1078   if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
   1079     return -1;
   1080   g_class_reference_holder = new ClassReferenceHolder(jni);
   1081 
   1082   return JNI_VERSION_1_6;
   1083 }
   1084 
   1085 extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
   1086   delete g_class_reference_holder;
   1087   g_class_reference_holder = NULL;
   1088   CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
   1089 }
   1090 
   1091 static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
   1092   jfieldID native_dc_id = GetFieldID(jni,
   1093       GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
   1094   jlong j_d = GetLongField(jni, j_dc, native_dc_id);
   1095   return reinterpret_cast<DataChannelInterface*>(j_d);
   1096 }
   1097 
   1098 JOW(jlong, DataChannel_registerObserverNative)(
   1099     JNIEnv* jni, jobject j_dc, jobject j_observer) {
   1100   talk_base::scoped_ptr<DataChannelObserverWrapper> observer(
   1101       new DataChannelObserverWrapper(jni, j_observer));
   1102   ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
   1103   return jlongFromPointer(observer.release());
   1104 }
   1105 
   1106 JOW(void, DataChannel_unregisterObserverNative)(
   1107     JNIEnv* jni, jobject j_dc, jlong native_observer) {
   1108   ExtractNativeDC(jni, j_dc)->UnregisterObserver();
   1109   delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
   1110 }
   1111 
   1112 JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
   1113   return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
   1114 }
   1115 
   1116 JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
   1117   return JavaEnumFromIndex(
   1118       jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
   1119 }
   1120 
   1121 JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
   1122   uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
   1123   CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
   1124         "buffered_amount overflowed jlong!");
   1125   return static_cast<jlong>(buffered_amount);
   1126 }
   1127 
   1128 JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
   1129   ExtractNativeDC(jni, j_dc)->Close();
   1130 }
   1131 
   1132 JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
   1133                                       jbyteArray data, jboolean binary) {
   1134   jbyte* bytes = jni->GetByteArrayElements(data, NULL);
   1135   bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
   1136       talk_base::Buffer(bytes, jni->GetArrayLength(data)),
   1137       binary));
   1138   jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
   1139   return ret;
   1140 }
   1141 
   1142 JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
   1143   CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
   1144 }
   1145 
   1146 JOW(void, Logging_nativeEnableTracing)(
   1147     JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
   1148     jint nativeSeverity) {
   1149   std::string path = JavaToStdString(jni, j_path);
   1150   if (nativeLevels != webrtc::kTraceNone) {
   1151     webrtc::Trace::set_level_filter(nativeLevels);
   1152 #ifdef ANDROID
   1153     if (path != "logcat:") {
   1154 #endif
   1155       CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
   1156             "SetTraceFile failed");
   1157 #ifdef ANDROID
   1158     } else {
   1159       // Intentionally leak this to avoid needing to reason about its lifecycle.
   1160       // It keeps no state and functions only as a dispatch point.
   1161       static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
   1162     }
   1163 #endif
   1164   }
   1165   talk_base::LogMessage::LogToDebug(nativeSeverity);
   1166 }
   1167 
   1168 JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
   1169   CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
   1170 }
   1171 
   1172 JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
   1173   PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
   1174   delete p;
   1175 }
   1176 
   1177 JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
   1178   CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
   1179 }
   1180 
   1181 JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
   1182   delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
   1183 }
   1184 
   1185 JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
   1186   delete reinterpret_cast<VideoRendererWrapper*>(j_p);
   1187 }
   1188 
   1189 JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
   1190   CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
   1191 }
   1192 
   1193 JOW(jboolean, MediaStream_nativeAddAudioTrack)(
   1194     JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
   1195   return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
   1196       reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
   1197 }
   1198 
   1199 JOW(jboolean, MediaStream_nativeAddVideoTrack)(
   1200     JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
   1201   return reinterpret_cast<MediaStreamInterface*>(pointer)
   1202       ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
   1203 }
   1204 
   1205 JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
   1206     JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
   1207   return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
   1208       reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
   1209 }
   1210 
   1211 JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
   1212     JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
   1213   return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
   1214       reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
   1215 }
   1216 
   1217 JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
   1218   return JavaStringFromStdString(
   1219       jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
   1220 }
   1221 
   1222 JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
   1223   CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
   1224 }
   1225 
   1226 JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
   1227     JNIEnv * jni, jclass, jobject j_observer) {
   1228   return (jlong)new PCOJava(jni, j_observer);
   1229 }
   1230 
   1231 #ifdef ANDROID
   1232 JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
   1233     JNIEnv* jni, jclass, jobject context) {
   1234   CHECK(g_jvm, "JNI_OnLoad failed to run?");
   1235   bool failure = false;
   1236   failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm);
   1237   failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
   1238   return !failure;
   1239 }
   1240 #endif  // ANDROID
   1241 
   1242 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
   1243     JNIEnv* jni, jclass) {
   1244   webrtc::Trace::CreateTrace();
   1245   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
   1246       webrtc::CreatePeerConnectionFactory());
   1247   return (jlong)factory.release();
   1248 }
   1249 
   1250 JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
   1251   CHECK_RELEASE(reinterpret_cast<PeerConnectionFactoryInterface*>(j_p));
   1252   webrtc::Trace::ReturnTrace();
   1253 }
   1254 
   1255 JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
   1256     JNIEnv* jni, jclass, jlong native_factory, jstring label) {
   1257   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
   1258       reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
   1259   talk_base::scoped_refptr<MediaStreamInterface> stream(
   1260       factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
   1261   return (jlong)stream.release();
   1262 }
   1263 
   1264 JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
   1265     JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
   1266     jobject j_constraints) {
   1267   talk_base::scoped_ptr<ConstraintsWrapper> constraints(
   1268       new ConstraintsWrapper(jni, j_constraints));
   1269   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
   1270       reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
   1271   talk_base::scoped_refptr<VideoSourceInterface> source(
   1272       factory->CreateVideoSource(
   1273           reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
   1274           constraints.get()));
   1275   return (jlong)source.release();
   1276 }
   1277 
   1278 JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
   1279     JNIEnv* jni, jclass, jlong native_factory, jstring id,
   1280     jlong native_source) {
   1281   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
   1282       reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
   1283   talk_base::scoped_refptr<VideoTrackInterface> track(
   1284       factory->CreateVideoTrack(
   1285           JavaToStdString(jni, id),
   1286           reinterpret_cast<VideoSourceInterface*>(native_source)));
   1287   return (jlong)track.release();
   1288 }
   1289 
   1290 JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
   1291     JNIEnv* jni, jclass, jlong native_factory, jstring id) {
   1292   talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
   1293       reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
   1294   talk_base::scoped_refptr<AudioTrackInterface> track(
   1295       factory->CreateAudioTrack(JavaToStdString(jni, id), NULL));
   1296   return (jlong)track.release();
   1297 }
   1298 
   1299 static void JavaIceServersToJsepIceServers(
   1300     JNIEnv* jni, jobject j_ice_servers,
   1301     PeerConnectionInterface::IceServers* ice_servers) {
   1302   jclass list_class = GetObjectClass(jni, j_ice_servers);
   1303   jmethodID iterator_id = GetMethodID(
   1304       jni, list_class, "iterator", "()Ljava/util/Iterator;");
   1305   jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
   1306   CHECK_EXCEPTION(jni, "error during CallObjectMethod");
   1307   jmethodID iterator_has_next = GetMethodID(
   1308       jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
   1309   jmethodID iterator_next = GetMethodID(
   1310       jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
   1311   while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
   1312     CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
   1313     jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
   1314     CHECK_EXCEPTION(jni, "error during CallObjectMethod");
   1315     jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
   1316     jfieldID j_ice_server_uri_id =
   1317         GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
   1318     jfieldID j_ice_server_username_id =
   1319         GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
   1320     jfieldID j_ice_server_password_id =
   1321         GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
   1322     jstring uri = reinterpret_cast<jstring>(
   1323         GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
   1324     jstring username = reinterpret_cast<jstring>(
   1325         GetObjectField(jni, j_ice_server, j_ice_server_username_id));
   1326     jstring password = reinterpret_cast<jstring>(
   1327         GetObjectField(jni, j_ice_server, j_ice_server_password_id));
   1328     PeerConnectionInterface::IceServer server;
   1329     server.uri = JavaToStdString(jni, uri);
   1330     server.username = JavaToStdString(jni, username);
   1331     server.password = JavaToStdString(jni, password);
   1332     ice_servers->push_back(server);
   1333   }
   1334   CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
   1335 }
   1336 
   1337 JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
   1338     JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
   1339     jobject j_constraints, jlong observer_p) {
   1340   talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
   1341       reinterpret_cast<PeerConnectionFactoryInterface*>(factory));
   1342   PeerConnectionInterface::IceServers servers;
   1343   JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
   1344   PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
   1345   observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
   1346   talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
   1347       servers, observer->constraints(), NULL, observer));
   1348   return (jlong)pc.release();
   1349 }
   1350 
   1351 static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
   1352     JNIEnv* jni, jobject j_pc) {
   1353   jfieldID native_pc_id = GetFieldID(jni,
   1354       GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
   1355   jlong j_p = GetLongField(jni, j_pc, native_pc_id);
   1356   return talk_base::scoped_refptr<PeerConnectionInterface>(
   1357       reinterpret_cast<PeerConnectionInterface*>(j_p));
   1358 }
   1359 
   1360 JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
   1361   const SessionDescriptionInterface* sdp =
   1362       ExtractNativePC(jni, j_pc)->local_description();
   1363   return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
   1364 }
   1365 
   1366 JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
   1367   const SessionDescriptionInterface* sdp =
   1368       ExtractNativePC(jni, j_pc)->remote_description();
   1369   return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
   1370 }
   1371 
   1372 JOW(jobject, PeerConnection_createDataChannel)(
   1373     JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
   1374   DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
   1375   talk_base::scoped_refptr<DataChannelInterface> channel(
   1376       ExtractNativePC(jni, j_pc)->CreateDataChannel(
   1377           JavaToStdString(jni, j_label), &init));
   1378   // Mustn't pass channel.get() directly through NewObject to avoid reading its
   1379   // vararg parameter as 64-bit and reading memory that doesn't belong to the
   1380   // 32-bit parameter.
   1381   jlong nativeChannelPtr = jlongFromPointer(channel.get());
   1382   CHECK(nativeChannelPtr, "Failed to create DataChannel");
   1383   jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
   1384   jmethodID j_data_channel_ctor = GetMethodID(
   1385       jni, j_data_channel_class, "<init>", "(J)V");
   1386   jobject j_channel = jni->NewObject(
   1387       j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
   1388   CHECK_EXCEPTION(jni, "error during NewObject");
   1389   // Channel is now owned by Java object, and will be freed from there.
   1390   int bumped_count = channel->AddRef();
   1391   CHECK(bumped_count == 2, "Unexpected refcount");
   1392   return j_channel;
   1393 }
   1394 
   1395 JOW(void, PeerConnection_createOffer)(
   1396     JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
   1397   ConstraintsWrapper* constraints =
   1398       new ConstraintsWrapper(jni, j_constraints);
   1399   talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
   1400       new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
   1401           jni, j_observer, constraints));
   1402   ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
   1403 }
   1404 
   1405 JOW(void, PeerConnection_createAnswer)(
   1406     JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
   1407   ConstraintsWrapper* constraints =
   1408       new ConstraintsWrapper(jni, j_constraints);
   1409   talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
   1410       new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
   1411           jni, j_observer, constraints));
   1412   ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
   1413 }
   1414 
   1415 // Helper to create a SessionDescriptionInterface from a SessionDescription.
   1416 static SessionDescriptionInterface* JavaSdpToNativeSdp(
   1417     JNIEnv* jni, jobject j_sdp) {
   1418   jfieldID j_type_id = GetFieldID(
   1419       jni, GetObjectClass(jni, j_sdp), "type",
   1420       "Lorg/webrtc/SessionDescription$Type;");
   1421   jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
   1422   jmethodID j_canonical_form_id = GetMethodID(
   1423       jni, GetObjectClass(jni, j_type), "canonicalForm",
   1424       "()Ljava/lang/String;");
   1425   jstring j_type_string = (jstring)jni->CallObjectMethod(
   1426       j_type, j_canonical_form_id);
   1427   CHECK_EXCEPTION(jni, "error during CallObjectMethod");
   1428   std::string std_type = JavaToStdString(jni, j_type_string);
   1429 
   1430   jfieldID j_description_id = GetFieldID(
   1431       jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
   1432   jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
   1433   std::string std_description = JavaToStdString(jni, j_description);
   1434 
   1435   return webrtc::CreateSessionDescription(
   1436       std_type, std_description, NULL);
   1437 }
   1438 
   1439 JOW(void, PeerConnection_setLocalDescription)(
   1440     JNIEnv* jni, jobject j_pc,
   1441     jobject j_observer, jobject j_sdp) {
   1442   talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
   1443       new talk_base::RefCountedObject<SetSdpObserverWrapper>(
   1444           jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
   1445   ExtractNativePC(jni, j_pc)->SetLocalDescription(
   1446       observer, JavaSdpToNativeSdp(jni, j_sdp));
   1447 }
   1448 
   1449 JOW(void, PeerConnection_setRemoteDescription)(
   1450     JNIEnv* jni, jobject j_pc,
   1451     jobject j_observer, jobject j_sdp) {
   1452   talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
   1453       new talk_base::RefCountedObject<SetSdpObserverWrapper>(
   1454           jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
   1455   ExtractNativePC(jni, j_pc)->SetRemoteDescription(
   1456       observer, JavaSdpToNativeSdp(jni, j_sdp));
   1457 }
   1458 
   1459 JOW(jboolean, PeerConnection_updateIce)(
   1460     JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
   1461   PeerConnectionInterface::IceServers ice_servers;
   1462   JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
   1463   talk_base::scoped_ptr<ConstraintsWrapper> constraints(
   1464       new ConstraintsWrapper(jni, j_constraints));
   1465   return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
   1466 }
   1467 
   1468 JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
   1469     JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
   1470     jint j_sdp_mline_index, jstring j_candidate_sdp) {
   1471   std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
   1472   std::string sdp = JavaToStdString(jni, j_candidate_sdp);
   1473   talk_base::scoped_ptr<IceCandidateInterface> candidate(
   1474       webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
   1475   return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
   1476 }
   1477 
   1478 JOW(jboolean, PeerConnection_nativeAddLocalStream)(
   1479     JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
   1480   talk_base::scoped_ptr<ConstraintsWrapper> constraints(
   1481       new ConstraintsWrapper(jni, j_constraints));
   1482   return ExtractNativePC(jni, j_pc)->AddStream(
   1483       reinterpret_cast<MediaStreamInterface*>(native_stream),
   1484       constraints.get());
   1485 }
   1486 
   1487 JOW(void, PeerConnection_nativeRemoveLocalStream)(
   1488     JNIEnv* jni, jobject j_pc, jlong native_stream) {
   1489   ExtractNativePC(jni, j_pc)->RemoveStream(
   1490       reinterpret_cast<MediaStreamInterface*>(native_stream));
   1491 }
   1492 
   1493 JOW(bool, PeerConnection_nativeGetStats)(
   1494     JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
   1495   talk_base::scoped_refptr<StatsObserverWrapper> observer(
   1496       new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
   1497   return ExtractNativePC(jni, j_pc)->GetStats(
   1498       observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
   1499 }
   1500 
   1501 JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
   1502   PeerConnectionInterface::SignalingState state =
   1503       ExtractNativePC(jni, j_pc)->signaling_state();
   1504   return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
   1505 }
   1506 
   1507 JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
   1508   PeerConnectionInterface::IceConnectionState state =
   1509       ExtractNativePC(jni, j_pc)->ice_connection_state();
   1510   return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
   1511 }
   1512 
   1513 JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
   1514   PeerConnectionInterface::IceGatheringState state =
   1515       ExtractNativePC(jni, j_pc)->ice_gathering_state();
   1516   return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
   1517 }
   1518 
   1519 JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
   1520   ExtractNativePC(jni, j_pc)->Close();
   1521   return;
   1522 }
   1523 
   1524 JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
   1525   talk_base::scoped_refptr<MediaSourceInterface> p(
   1526       reinterpret_cast<MediaSourceInterface*>(j_p));
   1527   return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
   1528 }
   1529 
   1530 JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
   1531     JNIEnv* jni, jclass, jstring j_device_name) {
   1532   std::string device_name = JavaToStdString(jni, j_device_name);
   1533   talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
   1534       cricket::DeviceManagerFactory::Create());
   1535   CHECK(device_manager->Init(), "DeviceManager::Init() failed");
   1536   cricket::Device device;
   1537   if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
   1538     LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
   1539     return 0;
   1540   }
   1541   talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
   1542       device_manager->CreateVideoCapturer(device));
   1543   return (jlong)capturer.release();
   1544 }
   1545 
   1546 JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
   1547     JNIEnv* jni, jclass, int x, int y) {
   1548   talk_base::scoped_ptr<VideoRendererWrapper> renderer(
   1549       VideoRendererWrapper::Create(
   1550           cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
   1551   return (jlong)renderer.release();
   1552 }
   1553 
   1554 JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
   1555     JNIEnv* jni, jclass, jobject j_callbacks) {
   1556   talk_base::scoped_ptr<JavaVideoRendererWrapper> renderer(
   1557       new JavaVideoRendererWrapper(jni, j_callbacks));
   1558   return (jlong)renderer.release();
   1559 }
   1560 
   1561 JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
   1562   cricket::VideoCapturer* capturer =
   1563       reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
   1564   talk_base::scoped_ptr<cricket::VideoFormatPod> format(
   1565       new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
   1566   capturer->Stop();
   1567   return jlongFromPointer(format.release());
   1568 }
   1569 
   1570 JOW(void, VideoSource_restart)(
   1571     JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
   1572   talk_base::scoped_ptr<cricket::VideoFormatPod> format(
   1573       reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
   1574   reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
   1575       StartCapturing(cricket::VideoFormat(*format));
   1576 }
   1577 
   1578 JOW(void, VideoSource_freeNativeVideoFormat)(
   1579     JNIEnv* jni, jclass, jlong j_p) {
   1580   delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
   1581 }
   1582 
   1583 JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
   1584   return JavaStringFromStdString(
   1585       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
   1586 }
   1587 
   1588 JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
   1589   return JavaStringFromStdString(
   1590       jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
   1591 }
   1592 
   1593 JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
   1594   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
   1595 }
   1596 
   1597 JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
   1598   return JavaEnumFromIndex(
   1599       jni,
   1600       "MediaStreamTrack$State",
   1601       reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
   1602 }
   1603 
   1604 JOW(jboolean, MediaStreamTrack_nativeSetState)(
   1605     JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
   1606   MediaStreamTrackInterface::TrackState new_state =
   1607       (MediaStreamTrackInterface::TrackState)j_new_state;
   1608   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
   1609       ->set_state(new_state);
   1610 }
   1611 
   1612 JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
   1613     JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
   1614   return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
   1615       ->set_enabled(enabled);
   1616 }
   1617 
   1618 JOW(void, VideoTrack_nativeAddRenderer)(
   1619     JNIEnv* jni, jclass,
   1620     jlong j_video_track_pointer, jlong j_renderer_pointer) {
   1621   reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
   1622       reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
   1623 }
   1624 
   1625 JOW(void, VideoTrack_nativeRemoveRenderer)(
   1626     JNIEnv* jni, jclass,
   1627     jlong j_video_track_pointer, jlong j_renderer_pointer) {
   1628   reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
   1629       reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
   1630 }
   1631