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