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