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