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