blob: 8f05321e88805dd7a8f347bdede26ef681c0343e [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
fischman@webrtc.org33584f92013-07-25 16:43:30 +00003 * Copyright 2013, Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
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
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000059#include <asm/unistd.h>
henrike@webrtc.org723d6832013-07-12 16:04:50 +000060#include <limits>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061#include <map>
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000062#include <sys/prctl.h>
63#include <sys/syscall.h>
fischman@webrtc.orgeb7def22013-12-09 21:34:30 +000064#include <unistd.h>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66#include "talk/app/webrtc/mediaconstraintsinterface.h"
67#include "talk/app/webrtc/peerconnectioninterface.h"
68#include "talk/app/webrtc/videosourceinterface.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000069#include "talk/base/bind.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070#include "talk/base/logging.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000071#include "talk/base/messagequeue.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072#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"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000077#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000078#include "third_party/icu/source/common/unicode/unistr.h"
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +000079#include "third_party/libyuv/include/libyuv/convert_from.h"
80#include "third_party/libyuv/include/libyuv/video_common.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000081#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000082#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000083#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"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000087#ifdef ANDROID
88#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
89using webrtc::LogcatTraceContext;
90#endif
91
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092using icu::UnicodeString;
fischman@webrtc.org540acde2014-02-13 03:56:14 +000093using talk_base::Bind;
94using talk_base::Thread;
95using talk_base::ThreadManager;
96using talk_base::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097using webrtc::AudioSourceInterface;
98using webrtc::AudioTrackInterface;
99using webrtc::AudioTrackVector;
100using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000101using webrtc::DataBuffer;
102using webrtc::DataChannelInit;
103using webrtc::DataChannelInterface;
104using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105using webrtc::IceCandidateInterface;
106using webrtc::MediaConstraintsInterface;
107using webrtc::MediaSourceInterface;
108using webrtc::MediaStreamInterface;
109using webrtc::MediaStreamTrackInterface;
110using webrtc::PeerConnectionFactoryInterface;
111using webrtc::PeerConnectionInterface;
112using webrtc::PeerConnectionObserver;
113using webrtc::SessionDescriptionInterface;
114using webrtc::SetSessionDescriptionObserver;
115using webrtc::StatsObserver;
116using webrtc::StatsReport;
117using webrtc::VideoRendererInterface;
118using webrtc::VideoSourceInterface;
119using webrtc::VideoTrackInterface;
120using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000121using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122
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
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000139// 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
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151namespace {
152
153static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
154
155static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000156// 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.
159static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000161// Return thread ID as a string.
162static 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.
170static 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
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000177// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
178static 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
187static 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());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200 jint status = g_jvm->DetachCurrentThread();
201 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000202 CHECK(!GetEnv(), "Detaching was a successful no-op???");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203}
204
205static void CreateJNIPtrKey() {
206 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
207 "pthread_key_create");
208}
209
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000210// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000212 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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000224 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000226 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000227#endif
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000228 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");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000233 return jni;
234}
235
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000236// 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.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000239static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000240 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000241 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000242 // 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;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000248}
249
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250// 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
254class ClassReferenceHolder {
255 public:
256 explicit ClassReferenceHolder(JNIEnv* jni) {
257 LoadClass(jni, "java/nio/ByteBuffer");
258 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000259 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");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263 LoadClass(jni, "org/webrtc/IceCandidate");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000264#ifdef ANDROID
265 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
266 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
267#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268 LoadClass(jni, "org/webrtc/MediaSource$State");
269 LoadClass(jni, "org/webrtc/MediaStream");
270 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
272 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000273 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 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().
316static 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.
320jmethodID 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
329jmethodID 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
339jfieldID 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
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000347// Returns a global reference guaranteed to be valid for the lifetime of the
348// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349jclass FindClass(JNIEnv* jni, const char* name) {
350 return g_class_reference_holder->GetClass(name);
351}
352
353jclass 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
360jobject 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
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000367jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
368 return static_cast<jstring>(GetObjectField(jni, object, id));
369}
370
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
372 jlong l = jni->GetLongField(object, id);
373 CHECK_EXCEPTION(jni, "error during GetLongField");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000374 return l;
375}
376
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000377jint 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
383bool 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
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000389jobject 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
396void 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.
404class 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
fischman@webrtc.org41776152014-01-09 00:31:17 +0000423// 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).
426class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000428 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
429 CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000431 ~ScopedLocalRefFrame() {
432 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000434
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 private:
436 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437};
438
439// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000440template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441class ScopedGlobalRef {
442 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000443 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000444 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000445 ~ScopedGlobalRef() {
446 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
447 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000448 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 return obj_;
450 }
451 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000452 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453};
454
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000455// Java references to "null" can only be distinguished as such in C++ by
456// creating a local reference, so this helper wraps that logic.
457static bool IsNull(JNIEnv* jni, jobject obj) {
458 ScopedLocalRefFrame local_ref_frame(jni);
459 return jni->NewLocalRef(obj) == NULL;
460}
461
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462// Return the (singleton) Java Enum object corresponding to |index|;
463// |state_class_fragment| is something like "MediaSource$State".
464jobject 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());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000470 jobjectArray state_values = static_cast<jobjectArray>(
471 jni->CallStaticObjectMethod(state_class, state_values_id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000473 jobject ret = jni->GetObjectArrayElement(state_values, index);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474 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.
479static 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.
487static 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
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000498static 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
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000524class 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.
529class PCOJava : public PeerConnectionObserver {
530 public:
531 PCOJava(JNIEnv* jni, jobject j_observer)
532 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000533 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")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000539 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")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546 }
547
548 virtual ~PCOJava() {}
549
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000550 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000551 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 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");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000557 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);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000562 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000564 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
566 }
567
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000568 virtual void OnError() OVERRIDE {
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000569 ScopedLocalRefFrame local_ref_frame(jni());
570 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571 jni()->CallVoidMethod(*j_observer_global_, m);
572 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
573 }
574
575 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000576 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000577 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000579 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000581 jobject new_state_enum =
582 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
583 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
585 }
586
587 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000588 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000589 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000591 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000593 jobject new_state_enum = JavaEnumFromIndex(
594 jni(), "PeerConnection$IceConnectionState", new_state);
595 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
597 }
598
599 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000600 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000601 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000602 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000603 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000605 jobject new_state_enum = JavaEnumFromIndex(
606 jni(), "PeerConnection$IceGatheringState", new_state);
607 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
609 }
610
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000611 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000612 ScopedLocalRefFrame local_ref_frame(jni());
613 jobject j_stream = jni()->NewObject(
614 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 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];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000620 jstring id = JavaStringFromStdString(jni(), track->id());
621 jobject j_track = jni()->NewObject(
622 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000624 jfieldID audio_tracks_id = GetFieldID(jni(),
625 *j_media_stream_class_,
626 "audioTracks",
627 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000628 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000630 GetObjectClass(jni(), audio_tracks),
631 "add",
632 "(Ljava/lang/Object;)Z");
633 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 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];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000641 jstring id = JavaStringFromStdString(jni(), track->id());
642 jobject j_track = jni()->NewObject(
643 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000645 jfieldID video_tracks_id = GetFieldID(jni(),
646 *j_media_stream_class_,
647 "videoTracks",
648 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000649 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000651 GetObjectClass(jni(), video_tracks),
652 "add",
653 "(Ljava/lang/Object;)Z");
654 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
656 CHECK(added, "");
657 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000658 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
660
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000661 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
662 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000663 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
665 }
666
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000667 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000668 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669 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
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000677 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
678 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
680 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
681 }
682
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000683 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000684 ScopedLocalRefFrame local_ref_frame(jni());
685 jobject j_channel = jni()->NewObject(
686 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000687 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000688
689 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
690 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000691 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000692
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
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000700 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
701 }
702
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000703 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
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711 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
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000723 const ScopedGlobalRef<jobject> j_observer_global_;
724 const ScopedGlobalRef<jclass> j_observer_class_;
725 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000727 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000729 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000731 const ScopedGlobalRef<jclass> j_data_channel_class_;
732 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
734 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000735 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736};
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.
740class 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.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000752 virtual const Constraints& GetMandatory() const OVERRIDE {
753 return mandatory_;
754 }
755
756 virtual const Constraints& GetOptional() const OVERRIDE {
757 return optional_;
758 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759
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
800static jobject JavaSdpFromNativeSdp(
801 JNIEnv* jni, const SessionDescriptionInterface* desc) {
802 std::string sdp;
803 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
fischman@webrtc.org41776152014-01-09 00:31:17 +0000804 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805
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;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000811 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000813 j_type_class, j_type_from_canonical, j_type_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 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(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000821 j_sdp_class, j_sdp_ctor, j_type, j_description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822 CHECK_EXCEPTION(jni, "error during NewObject");
823 return j_sdp;
824}
825
826template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
827class SdpObserverWrapper : public T {
828 public:
829 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
830 ConstraintsWrapper* constraints)
831 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000832 j_observer_global_(jni, j_observer),
833 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 }
835
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000836 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000837
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000838 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000840 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000841 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
842 jni()->CallVoidMethod(*j_observer_global_, m);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
844 }
845
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000846 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000848 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000850 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000852 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
853 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 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) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000861 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
862 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000863 jstring j_error_string = JavaStringFromStdString(jni(), error);
864 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
866 }
867
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868 JNIEnv* jni() {
869 return AttachCurrentThreadIfNeeded();
870 }
871
fischman@webrtc.org41776152014-01-09 00:31:17 +0000872 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000873 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000874 const ScopedGlobalRef<jobject> j_observer_global_;
875 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876};
877
878class CreateSdpObserverWrapper
879 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
880 public:
881 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
882 ConstraintsWrapper* constraints)
883 : SdpObserverWrapper(jni, j_observer, constraints) {}
884
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000885 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000886 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 SdpObserverWrapper::OnFailure(std::string("Create"), error);
888 }
889};
890
891class SetSdpObserverWrapper
892 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
893 public:
894 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
895 ConstraintsWrapper* constraints)
896 : SdpObserverWrapper(jni, j_observer, constraints) {}
897
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000898 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000899 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 SdpObserverWrapper::OnFailure(std::string("Set"), error);
901 }
902};
903
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000904// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
905// and dispatching the callback from C++ back to Java.
906class 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 {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000923 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000924 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 {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000929 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000930 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
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
953// dispatching the callback from C++ back to Java.
954class StatsObserverWrapper : public StatsObserver {
955 public:
956 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000957 : 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")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000960 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000961 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000962 "(Ljava/lang/String;Ljava/lang/String;D"
963 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000964 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965 jni, "org/webrtc/StatsReport$Value")),
966 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000967 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000968 "(Ljava/lang/String;Ljava/lang/String;)V")) {
969 }
970
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000971 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000972
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000973 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000974 ScopedLocalRefFrame local_ref_frame(jni());
975 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000976 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
977 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000978 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979 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(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000986 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000988 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000989 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000990 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);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 }
1001 return reports_array;
1002 }
1003
1004 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1005 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001006 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001007 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001008 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001009 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001010 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);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001015 }
1016 return j_values;
1017 }
1018
1019 JNIEnv* jni() {
1020 return AttachCurrentThreadIfNeeded();
1021 }
1022
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001023 const ScopedGlobalRef<jobject> j_observer_global_;
1024 const ScopedGlobalRef<jclass> j_observer_class_;
1025 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001026 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001027 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001028 const jmethodID j_value_ctor_;
1029};
1030
1031// Adapter presenting a cricket::VideoRenderer as a
1032// webrtc::VideoRendererInterface.
1033class 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
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001043 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001044 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 const bool kNotReserved = false; // What does this param mean??
1046 renderer_->SetSize(width, height, kNotReserved);
1047 }
1048
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001049 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001050 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001051 renderer_->RenderFrame(frame);
1052 }
1053
1054 private:
1055 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1056 : renderer_(renderer) {}
1057
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001058 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059};
1060
1061// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1062// instance.
1063class JavaVideoRendererWrapper : public VideoRendererInterface {
1064 public:
1065 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001066 : 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")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001077 CHECK_EXCEPTION(jni, "");
1078 }
1079
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001080 virtual ~JavaVideoRendererWrapper() {}
1081
1082 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001083 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001084 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1085 CHECK_EXCEPTION(jni(), "");
1086 }
1087
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001088 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001089 ScopedLocalRefFrame local_ref_frame(jni());
1090 jobject j_frame = CricketToJavaFrame(frame);
1091 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001092 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) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001098 jintArray strides = jni()->NewIntArray(3);
1099 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001100 strides_array[0] = frame->GetYPitch();
1101 strides_array[1] = frame->GetUPitch();
1102 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001103 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1104 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1105 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001106 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001107 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);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001115 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001116 *j_frame_class_, j_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001117 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001118 }
1119
1120 JNIEnv* jni() {
1121 return AttachCurrentThreadIfNeeded();
1122 }
1123
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001124 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001125 jmethodID j_set_size_id_;
1126 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001127 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001128 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001129 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130};
1131
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001132#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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001137// Color formats supported by encoder - should mirror supportedColorList
1138// from MediaCodecVideoEncoder.java
1139enum COLOR_FORMATTYPE {
1140 COLOR_FormatYUV420Planar = 0x13,
1141 COLOR_FormatYUV420SemiPlanar = 0x15,
1142 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1143 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1144 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1145 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1146 // but requires some (16, 32?) byte alignment.
1147 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1148};
1149
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001150// Arbitrary interval to poll the codec for new outputs.
1151enum { kMediaCodecPollMs = 10 };
1152
1153// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1154// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1155// HW-backed video encode. This C++ class is implemented as a very thin shim,
1156// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1157// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1158// thread, currently the libjingle Worker thread.
1159class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
1160 public talk_base::MessageHandler {
1161 public:
1162 virtual ~MediaCodecVideoEncoder();
1163 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1164
1165 // webrtc::VideoEncoder implementation. Everything trampolines to
1166 // |codec_thread_| for execution.
1167 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1168 int32_t /* number_of_cores */,
1169 uint32_t /* max_payload_size */) OVERRIDE;
1170 virtual int32_t Encode(
1171 const webrtc::I420VideoFrame& input_image,
1172 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1173 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1174 virtual int32_t RegisterEncodeCompleteCallback(
1175 webrtc::EncodedImageCallback* callback) OVERRIDE;
1176 virtual int32_t Release() OVERRIDE;
1177 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1178 int /* rtt */) OVERRIDE;
1179 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1180
1181 // talk_base::MessageHandler implementation.
1182 virtual void OnMessage(talk_base::Message* msg) OVERRIDE;
1183
1184 private:
1185 // CHECK-fail if not running on |codec_thread_|.
1186 void CheckOnCodecThread();
1187
1188 // Release() and InitEncode() in an attempt to restore the codec to an
1189 // operable state. Necessary after all manner of OMX-layer errors.
1190 void ResetCodec();
1191
1192 // Implementation of webrtc::VideoEncoder methods above, all running on the
1193 // codec thread exclusively.
1194 //
1195 // If width==0 then this is assumed to be a re-initialization and the
1196 // previously-current values are reused instead of the passed parameters
1197 // (makes it easier to reason about thread-safety).
1198 int32_t InitEncodeOnCodecThread(int width, int height, int kbps);
1199 int32_t EncodeOnCodecThread(
1200 const webrtc::I420VideoFrame& input_image,
1201 const std::vector<webrtc::VideoFrameType>* frame_types);
1202 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1203 webrtc::EncodedImageCallback* callback);
1204 int32_t ReleaseOnCodecThread();
1205 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1206
1207 // Reset parameters valid between InitEncode() & Release() (see below).
1208 void ResetParameters(JNIEnv* jni);
1209
1210 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1211 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1212 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1213 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1214 jlong GetOutputBufferInfoPresentationTimestampUs(
1215 JNIEnv* jni,
1216 jobject j_output_buffer_info);
1217
1218 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1219 // true on success.
1220 bool DeliverPendingOutputs(JNIEnv* jni);
1221
1222 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1223 // |codec_thread_| synchronously.
1224 webrtc::EncodedImageCallback* callback_;
1225
1226 // State that is constant for the lifetime of this object once the ctor
1227 // returns.
1228 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1229 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1230 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1231 jmethodID j_init_encode_method_;
1232 jmethodID j_dequeue_input_buffer_method_;
1233 jmethodID j_encode_method_;
1234 jmethodID j_release_method_;
1235 jmethodID j_set_rates_method_;
1236 jmethodID j_dequeue_output_buffer_method_;
1237 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001238 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001239 jfieldID j_info_index_field_;
1240 jfieldID j_info_buffer_field_;
1241 jfieldID j_info_is_key_frame_field_;
1242 jfieldID j_info_presentation_timestamp_us_field_;
1243
1244 // State that is valid only between InitEncode() and the next Release().
1245 // Touched only on codec_thread_ so no explicit synchronization necessary.
1246 int width_; // Frame width in pixels.
1247 int height_; // Frame height in pixels.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001248 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001249 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001250 int frames_received_; // Number of frames received by encoder.
1251 int frames_dropped_; // Number of frames dropped by encoder.
1252 // Frame size in bytes fed to MediaCodec.
1253 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001254 // True only when between a callback_->Encoded() call return a positive value
1255 // and the next Encode() call being ignored.
1256 bool drop_next_input_frame_;
1257 // Global references; must be deleted in Release().
1258 std::vector<jobject> input_buffers_;
1259};
1260
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001261MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1262 // We depend on ResetParameters() to ensure no more callbacks to us after we
1263 // are deleted, so assert it here.
1264 CHECK(width_ == 0, "Release() should have been called");
1265}
1266
1267MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1268 : callback_(NULL),
1269 codec_thread_(new Thread()),
1270 j_media_codec_video_encoder_class_(
1271 jni,
1272 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1273 j_media_codec_video_encoder_(
1274 jni,
1275 jni->NewObject(*j_media_codec_video_encoder_class_,
1276 GetMethodID(jni,
1277 *j_media_codec_video_encoder_class_,
1278 "<init>",
1279 "()V"))) {
1280 ScopedLocalRefFrame local_ref_frame(jni);
1281 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1282 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1283 // 2732 means that deadlocks abound. This class synchronously trampolines
1284 // to |codec_thread_|, so if anything else can be coming to _us_ from
1285 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1286 // in the bug, we have a problem. For now work around that with a dedicated
1287 // thread.
1288 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
1289 CHECK(codec_thread_->Start(), "Failed to start MediaCodecVideoEncoder");
1290
1291 ResetParameters(jni);
1292
1293 jclass j_output_buffer_info_class =
1294 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1295 j_init_encode_method_ = GetMethodID(jni,
1296 *j_media_codec_video_encoder_class_,
1297 "initEncode",
1298 "(III)[Ljava/nio/ByteBuffer;");
1299 j_dequeue_input_buffer_method_ = GetMethodID(
1300 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1301 j_encode_method_ = GetMethodID(
1302 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1303 j_release_method_ =
1304 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1305 j_set_rates_method_ = GetMethodID(
1306 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1307 j_dequeue_output_buffer_method_ =
1308 GetMethodID(jni,
1309 *j_media_codec_video_encoder_class_,
1310 "dequeueOutputBuffer",
1311 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1312 j_release_output_buffer_method_ = GetMethodID(
1313 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1314
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001315 j_color_format_field_ =
1316 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001317 j_info_index_field_ =
1318 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1319 j_info_buffer_field_ = GetFieldID(
1320 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1321 j_info_is_key_frame_field_ =
1322 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1323 j_info_presentation_timestamp_us_field_ = GetFieldID(
1324 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
1325 CHECK_EXCEPTION(jni, "MediaCodecVideoEncoder ctor failed");
1326}
1327
1328int32_t MediaCodecVideoEncoder::InitEncode(
1329 const webrtc::VideoCodec* codec_settings,
1330 int32_t /* number_of_cores */,
1331 uint32_t /* max_payload_size */) {
1332 // Factory should guard against other codecs being used with us.
1333 CHECK(codec_settings->codecType == kVideoCodecVP8, "Unsupported codec");
1334
1335 return codec_thread_->Invoke<int32_t>(
1336 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1337 this,
1338 codec_settings->width,
1339 codec_settings->height,
1340 codec_settings->startBitrate));
1341}
1342
1343int32_t MediaCodecVideoEncoder::Encode(
1344 const webrtc::I420VideoFrame& frame,
1345 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1346 const std::vector<webrtc::VideoFrameType>* frame_types) {
1347 return codec_thread_->Invoke<int32_t>(Bind(
1348 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1349}
1350
1351int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1352 webrtc::EncodedImageCallback* callback) {
1353 return codec_thread_->Invoke<int32_t>(
1354 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1355 this,
1356 callback));
1357}
1358
1359int32_t MediaCodecVideoEncoder::Release() {
1360 return codec_thread_->Invoke<int32_t>(
1361 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1362}
1363
1364int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1365 int /* rtt */) {
1366 return WEBRTC_VIDEO_CODEC_OK;
1367}
1368
1369int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1370 uint32_t frame_rate) {
1371 return codec_thread_->Invoke<int32_t>(
1372 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1373 this,
1374 new_bit_rate,
1375 frame_rate));
1376}
1377
1378void MediaCodecVideoEncoder::OnMessage(talk_base::Message* msg) {
1379 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1380 ScopedLocalRefFrame local_ref_frame(jni);
1381
1382 // We only ever send one message to |this| directly (not through a Bind()'d
1383 // functor), so expect no ID/data.
1384 CHECK(!msg->message_id, "Unexpected message!");
1385 CHECK(!msg->pdata, "Unexpected message!");
1386 CheckOnCodecThread();
1387
1388 // It would be nice to recover from a failure here if one happened, but it's
1389 // unclear how to signal such a failure to the app, so instead we stay silent
1390 // about it and let the next app-called API method reveal the borkedness.
1391 DeliverPendingOutputs(jni);
1392 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1393}
1394
1395void MediaCodecVideoEncoder::CheckOnCodecThread() {
1396 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread(),
1397 "Running on wrong thread!");
1398}
1399
1400void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001401 LOG(LS_ERROR) << "ResetCodec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001402 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1403 codec_thread_->Invoke<int32_t>(Bind(
1404 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0)) !=
1405 WEBRTC_VIDEO_CODEC_OK) {
1406 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1407 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1408 // https://code.google.com/p/webrtc/issues/detail?id=2920
1409 }
1410}
1411
1412int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
1413 int width, int height, int kbps) {
1414 CheckOnCodecThread();
1415 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1416 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001417 LOG(LS_INFO) << "InitEncodeOnCodecThread " << width << " x " << height;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001418
1419 if (width == 0) {
1420 width = width_;
1421 height = height_;
1422 kbps = last_set_bitrate_kbps_;
1423 }
1424
1425 width_ = width;
1426 height_ = height;
1427 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001428 yuv_size_ = width_ * height_ * 3 / 2;
1429 frames_received_ = 0;
1430 frames_dropped_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001431 // We enforce no extra stride/padding in the format creation step.
1432 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1433 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1434 j_init_encode_method_,
1435 width_,
1436 height_,
1437 kbps));
1438 CHECK_EXCEPTION(jni, "");
1439 if (IsNull(jni, input_buffers))
1440 return WEBRTC_VIDEO_CODEC_ERROR;
1441
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001442 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1443 j_color_format_field_)) {
1444 case COLOR_FormatYUV420Planar:
1445 encoder_fourcc_ = libyuv::FOURCC_YU12;
1446 break;
1447 case COLOR_FormatYUV420SemiPlanar:
1448 case COLOR_QCOM_FormatYUV420SemiPlanar:
1449 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1450 encoder_fourcc_ = libyuv::FOURCC_NV12;
1451 break;
1452 default:
1453 LOG(LS_ERROR) << "Wrong color format.";
1454 return WEBRTC_VIDEO_CODEC_ERROR;
1455 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001456 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1457 CHECK(input_buffers_.empty(), "Unexpected double InitEncode without Release");
1458 input_buffers_.resize(num_input_buffers);
1459 for (size_t i = 0; i < num_input_buffers; ++i) {
1460 input_buffers_[i] =
1461 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001462 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001463 jni->GetDirectBufferCapacity(input_buffers_[i]);
1464 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001465 CHECK(yuv_buffer_capacity >= yuv_size_, "Insufficient capacity");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001466 }
1467 CHECK_EXCEPTION(jni, "");
1468
1469 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1470 return WEBRTC_VIDEO_CODEC_OK;
1471}
1472
1473int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1474 const webrtc::I420VideoFrame& frame,
1475 const std::vector<webrtc::VideoFrameType>* frame_types) {
1476 CheckOnCodecThread();
1477 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1478 ScopedLocalRefFrame local_ref_frame(jni);
1479
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001480 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001481 if (!DeliverPendingOutputs(jni)) {
1482 ResetCodec();
1483 // Continue as if everything's fine.
1484 }
1485
1486 if (drop_next_input_frame_) {
1487 drop_next_input_frame_ = false;
1488 return WEBRTC_VIDEO_CODEC_OK;
1489 }
1490
1491 CHECK(frame_types->size() == 1, "Unexpected stream count");
1492 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1493
1494 CHECK(frame.width() == width_, "Unexpected resolution change");
1495 CHECK(frame.height() == height_, "Unexpected resolution change");
1496
1497 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1498 j_dequeue_input_buffer_method_);
1499 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001500 if (j_input_buffer_index == -1) {
1501 // Video codec falls behind - no input buffer available.
1502 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001503 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001504 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001505 if (j_input_buffer_index == -2) {
1506 ResetCodec();
1507 return WEBRTC_VIDEO_CODEC_ERROR;
1508 }
1509
1510 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001511 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001512 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
1513 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001514 CHECK(yuv_buffer, "Indirect buffer??");
1515 CHECK(!libyuv::ConvertFromI420(
1516 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1517 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1518 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1519 yuv_buffer, width_,
1520 width_, height_,
1521 encoder_fourcc_),
1522 "ConvertFromI420 failed");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001523 jlong timestamp_us = frame.render_time_ms() * 1000;
1524 int64_t start = talk_base::Time();
1525 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1526 j_encode_method_,
1527 key_frame,
1528 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001529 yuv_size_,
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001530 timestamp_us);
1531 CHECK_EXCEPTION(jni, "");
1532 if (!encode_status || !DeliverPendingOutputs(jni)) {
1533 ResetCodec();
1534 return WEBRTC_VIDEO_CODEC_ERROR;
1535 }
1536
1537 return WEBRTC_VIDEO_CODEC_OK;
1538}
1539
1540int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1541 webrtc::EncodedImageCallback* callback) {
1542 CheckOnCodecThread();
1543 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1544 ScopedLocalRefFrame local_ref_frame(jni);
1545 callback_ = callback;
1546 return WEBRTC_VIDEO_CODEC_OK;
1547}
1548
1549int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
1550 CheckOnCodecThread();
1551 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001552 LOG(LS_INFO) << "Frames received: " << frames_received_ <<
1553 ". Frames dropped: " << frames_dropped_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001554 ScopedLocalRefFrame local_ref_frame(jni);
1555 for (size_t i = 0; i < input_buffers_.size(); ++i)
1556 jni->DeleteGlobalRef(input_buffers_[i]);
1557 input_buffers_.clear();
1558 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1559 ResetParameters(jni);
1560 CHECK_EXCEPTION(jni, "");
1561 return WEBRTC_VIDEO_CODEC_OK;
1562}
1563
1564int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1565 uint32_t frame_rate) {
1566 CheckOnCodecThread();
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001567 if (last_set_bitrate_kbps_ == new_bit_rate) {
1568 return WEBRTC_VIDEO_CODEC_OK;
1569 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001570 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1571 ScopedLocalRefFrame local_ref_frame(jni);
1572 last_set_bitrate_kbps_ = new_bit_rate;
1573 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1574 j_set_rates_method_,
1575 new_bit_rate,
1576 frame_rate);
1577 CHECK_EXCEPTION(jni, "");
1578 if (!ret) {
1579 ResetCodec();
1580 return WEBRTC_VIDEO_CODEC_ERROR;
1581 }
1582 return WEBRTC_VIDEO_CODEC_OK;
1583}
1584
1585void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
1586 talk_base::MessageQueueManager::Clear(this);
1587 width_ = 0;
1588 height_ = 0;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001589 yuv_size_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001590 drop_next_input_frame_ = false;
1591 CHECK(input_buffers_.empty(),
1592 "ResetParameters called while holding input_buffers_!");
1593}
1594
1595int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1596 JNIEnv* jni,
1597 jobject j_output_buffer_info) {
1598 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1599}
1600
1601jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1602 JNIEnv* jni,
1603 jobject j_output_buffer_info) {
1604 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1605}
1606
1607bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1608 JNIEnv* jni,
1609 jobject j_output_buffer_info) {
1610 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1611}
1612
1613jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1614 JNIEnv* jni,
1615 jobject j_output_buffer_info) {
1616 return GetLongField(
1617 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1618}
1619
1620bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1621 while (true) {
1622 jobject j_output_buffer_info = jni->CallObjectMethod(
1623 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
1624 CHECK_EXCEPTION(jni, "");
1625 if (IsNull(jni, j_output_buffer_info))
1626 break;
1627
1628 int output_buffer_index =
1629 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1630 if (output_buffer_index == -1) {
1631 ResetCodec();
1632 return false;
1633 }
1634
1635 jlong capture_time_ms =
1636 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1637 1000;
1638
1639 int32_t callback_status = 0;
1640 if (callback_) {
1641 jobject j_output_buffer =
1642 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1643 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1644 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1645 uint8* payload = reinterpret_cast<uint8_t*>(
1646 jni->GetDirectBufferAddress(j_output_buffer));
1647 CHECK_EXCEPTION(jni, "");
1648 scoped_ptr<webrtc::EncodedImage> image(
1649 new webrtc::EncodedImage(payload, payload_size, payload_size));
1650 image->_encodedWidth = width_;
1651 image->_encodedHeight = height_;
1652 // Convert capture time to 90 kHz RTP timestamp.
1653 image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
1654 image->capture_time_ms_ = capture_time_ms;
1655 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1656 image->_completeFrame = true;
1657
1658 webrtc::CodecSpecificInfo info;
1659 memset(&info, 0, sizeof(info));
1660 info.codecType = kVideoCodecVP8;
1661 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1662 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1663 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1664
1665 // Generate a header describing a single fragment.
1666 webrtc::RTPFragmentationHeader header;
1667 memset(&header, 0, sizeof(header));
1668 header.VerifyAndAllocateFragmentationHeader(1);
1669 header.fragmentationOffset[0] = 0;
1670 header.fragmentationLength[0] = image->_length;
1671 header.fragmentationPlType[0] = 0;
1672 header.fragmentationTimeDiff[0] = 0;
1673
1674 callback_status = callback_->Encoded(*image, &info, &header);
1675 }
1676
1677 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1678 j_release_output_buffer_method_,
1679 output_buffer_index);
1680 CHECK_EXCEPTION(jni, "");
1681 if (!success) {
1682 ResetCodec();
1683 return false;
1684 }
1685
1686 if (callback_status > 0)
1687 drop_next_input_frame_ = true;
1688 // Theoretically could handle callback_status<0 here, but unclear what that
1689 // would mean for us.
1690 }
1691
1692 return true;
1693}
1694
1695// Simplest-possible implementation of an encoder factory, churns out
1696// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1697class MediaCodecVideoEncoderFactory
1698 : public cricket::WebRtcVideoEncoderFactory {
1699 public:
1700 MediaCodecVideoEncoderFactory();
1701 virtual ~MediaCodecVideoEncoderFactory();
1702
1703 // WebRtcVideoEncoderFactory implementation.
1704 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1705 OVERRIDE;
1706 virtual void AddObserver(Observer* observer) OVERRIDE;
1707 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1708 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1709 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1710
1711 private:
1712 // Empty if platform support is lacking, const after ctor returns.
1713 std::vector<VideoCodec> supported_codecs_;
1714};
1715
1716MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1717 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1718 ScopedLocalRefFrame local_ref_frame(jni);
1719 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1720 bool is_platform_supported = jni->CallStaticBooleanMethod(
1721 j_encoder_class,
1722 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
1723 CHECK_EXCEPTION(jni, "");
1724 if (!is_platform_supported)
1725 return;
1726
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001727 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1728 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1729 // reasonable defaults.
1730 supported_codecs_.push_back(
1731 VideoCodec(kVideoCodecVP8, "VP8", 1920, 1088, 30));
1732}
1733
1734MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1735
1736webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1737 webrtc::VideoCodecType type) {
1738 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1739 return NULL;
1740 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1741}
1742
1743// Since the available codec list is never going to change, we ignore the
1744// Observer-related interface here.
1745void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1746void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1747
1748const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1749MediaCodecVideoEncoderFactory::codecs() const {
1750 return supported_codecs_;
1751}
1752
1753void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1754 webrtc::VideoEncoder* encoder) {
1755 delete encoder;
1756}
1757
1758#endif // ANDROID
1759
1760} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001761
1762// Convenience macro defining JNI-accessible methods in the org.webrtc package.
1763// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1764#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1765 Java_org_webrtc_##name
1766
1767extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1768 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1769 g_jvm = jvm;
1770 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1771
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00001772 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey), "pthread_once");
1773
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1775
1776 JNIEnv* jni;
1777 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1778 return -1;
1779 g_class_reference_holder = new ClassReferenceHolder(jni);
1780
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001781 return JNI_VERSION_1_6;
1782}
1783
1784extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001785 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001786 delete g_class_reference_holder;
1787 g_class_reference_holder = NULL;
1788 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00001789 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001790}
1791
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001792static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001793 jfieldID native_dc_id = GetFieldID(jni,
1794 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1795 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001796 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001797}
1798
1799JOW(jlong, DataChannel_registerObserverNative)(
1800 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001801 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001802 new DataChannelObserverWrapper(jni, j_observer));
1803 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00001804 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001805}
1806
1807JOW(void, DataChannel_unregisterObserverNative)(
1808 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1809 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1810 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1811}
1812
1813JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1814 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1815}
1816
1817JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1818 return JavaEnumFromIndex(
1819 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1820}
1821
1822JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1823 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1824 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1825 "buffered_amount overflowed jlong!");
1826 return static_cast<jlong>(buffered_amount);
1827}
1828
1829JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1830 ExtractNativeDC(jni, j_dc)->Close();
1831}
1832
1833JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1834 jbyteArray data, jboolean binary) {
1835 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1836 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1837 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1838 binary));
1839 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1840 return ret;
1841}
1842
1843JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001844 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001845}
1846
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001847JOW(void, Logging_nativeEnableTracing)(
1848 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1849 jint nativeSeverity) {
1850 std::string path = JavaToStdString(jni, j_path);
1851 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00001852 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00001853#ifdef ANDROID
1854 if (path != "logcat:") {
1855#endif
1856 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1857 "SetTraceFile failed");
1858#ifdef ANDROID
1859 } else {
1860 // Intentionally leak this to avoid needing to reason about its lifecycle.
1861 // It keeps no state and functions only as a dispatch point.
1862 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1863 }
1864#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001865 }
1866 talk_base::LogMessage::LogToDebug(nativeSeverity);
1867}
1868
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001869JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001870 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871}
1872
1873JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1874 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1875 delete p;
1876}
1877
1878JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001879 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001880}
1881
1882JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1883 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1884}
1885
1886JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1887 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1888}
1889
1890JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001891 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001892}
1893
1894JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1895 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001896 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001897 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001898}
1899
1900JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1901 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001902 return reinterpret_cast<MediaStreamInterface*>(pointer)
1903 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001904}
1905
1906JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1907 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001908 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001909 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001910}
1911
1912JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1913 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001914 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001916}
1917
1918JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1919 return JavaStringFromStdString(
1920 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1921}
1922
1923JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001924 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001925}
1926
1927JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1928 JNIEnv * jni, jclass, jobject j_observer) {
1929 return (jlong)new PCOJava(jni, j_observer);
1930}
1931
1932#ifdef ANDROID
1933JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001934 JNIEnv* jni, jclass, jobject context,
1935 jboolean initialize_audio, jboolean initialize_video) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001936 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1937 bool failure = false;
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001938 if (initialize_video)
fischman@webrtc.org95127192014-06-06 18:40:44 +00001939 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001940 if (initialize_audio)
1941 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942 return !failure;
1943}
1944#endif // ANDROID
1945
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001946// Helper struct for working around the fact that CreatePeerConnectionFactory()
1947// comes in two flavors: either entirely automagical (constructing its own
1948// threads and deleting them on teardown, but no external codec factory support)
1949// or entirely manual (requires caller to delete threads after factory
1950// teardown). This struct takes ownership of its ctor's arguments to present a
1951// single thing for Java to hold and eventually free.
1952class OwnedFactoryAndThreads {
1953 public:
1954 OwnedFactoryAndThreads(Thread* worker_thread,
1955 Thread* signaling_thread,
1956 PeerConnectionFactoryInterface* factory)
1957 : worker_thread_(worker_thread),
1958 signaling_thread_(signaling_thread),
1959 factory_(factory) {}
1960
1961 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
1962
1963 PeerConnectionFactoryInterface* factory() { return factory_; }
1964
1965 private:
1966 const scoped_ptr<Thread> worker_thread_;
1967 const scoped_ptr<Thread> signaling_thread_;
1968 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
1969};
1970
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1972 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00001973 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
1974 // ThreadManager only WrapCurrentThread()s the thread where it is first
1975 // created. Since the semantics around when auto-wrapping happens in
1976 // talk/base/ are convoluted, we simply wrap here to avoid having to think
1977 // about ramifications of auto-wrapping there.
1978 talk_base::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001979 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001980 Thread* worker_thread = new Thread();
1981 worker_thread->SetName("worker_thread", NULL);
1982 Thread* signaling_thread = new Thread();
1983 signaling_thread->SetName("signaling_thread", NULL);
1984 CHECK(worker_thread->Start() && signaling_thread->Start(),
1985 "Failed to start threads");
1986 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
1987#ifdef ANDROID
1988 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
1989#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001990 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001991 webrtc::CreatePeerConnectionFactory(worker_thread,
1992 signaling_thread,
1993 NULL,
1994 encoder_factory.release(),
1995 NULL));
1996 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
1997 worker_thread, signaling_thread, factory.release());
1998 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999}
2000
2001JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002002 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002003 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002004}
2005
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002006static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2007 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2008}
2009
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2011 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
2012 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002013 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002014 talk_base::scoped_refptr<MediaStreamInterface> stream(
2015 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2016 return (jlong)stream.release();
2017}
2018
2019JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2020 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2021 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002022 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002023 new ConstraintsWrapper(jni, j_constraints));
2024 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002025 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002026 talk_base::scoped_refptr<VideoSourceInterface> source(
2027 factory->CreateVideoSource(
2028 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2029 constraints.get()));
2030 return (jlong)source.release();
2031}
2032
2033JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2034 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2035 jlong native_source) {
2036 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002037 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038 talk_base::scoped_refptr<VideoTrackInterface> track(
2039 factory->CreateVideoTrack(
2040 JavaToStdString(jni, id),
2041 reinterpret_cast<VideoSourceInterface*>(native_source)));
2042 return (jlong)track.release();
2043}
2044
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002045JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2046 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2047 scoped_ptr<ConstraintsWrapper> constraints(
2048 new ConstraintsWrapper(jni, j_constraints));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002049 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002050 factoryFromJava(native_factory));
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002051 talk_base::scoped_refptr<AudioSourceInterface> source(
2052 factory->CreateAudioSource(constraints.get()));
2053 return (jlong)source.release();
2054}
2055
2056JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2057 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2058 jlong native_source) {
2059 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
2060 factoryFromJava(native_factory));
2061 talk_base::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
2062 JavaToStdString(jni, id),
2063 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002064 return (jlong)track.release();
2065}
2066
2067static void JavaIceServersToJsepIceServers(
2068 JNIEnv* jni, jobject j_ice_servers,
2069 PeerConnectionInterface::IceServers* ice_servers) {
2070 jclass list_class = GetObjectClass(jni, j_ice_servers);
2071 jmethodID iterator_id = GetMethodID(
2072 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2073 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
2074 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2075 jmethodID iterator_has_next = GetMethodID(
2076 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2077 jmethodID iterator_next = GetMethodID(
2078 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2079 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
2080 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2081 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
2082 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2083 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2084 jfieldID j_ice_server_uri_id =
2085 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2086 jfieldID j_ice_server_username_id =
2087 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2088 jfieldID j_ice_server_password_id =
2089 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2090 jstring uri = reinterpret_cast<jstring>(
2091 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2092 jstring username = reinterpret_cast<jstring>(
2093 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2094 jstring password = reinterpret_cast<jstring>(
2095 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2096 PeerConnectionInterface::IceServer server;
2097 server.uri = JavaToStdString(jni, uri);
2098 server.username = JavaToStdString(jni, username);
2099 server.password = JavaToStdString(jni, password);
2100 ice_servers->push_back(server);
2101 }
2102 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2103}
2104
2105JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2106 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2107 jobject j_constraints, jlong observer_p) {
2108 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002109 reinterpret_cast<PeerConnectionFactoryInterface*>(
2110 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002111 PeerConnectionInterface::IceServers servers;
2112 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2113 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2114 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
2115 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002116 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002117 return (jlong)pc.release();
2118}
2119
2120static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
2121 JNIEnv* jni, jobject j_pc) {
2122 jfieldID native_pc_id = GetFieldID(jni,
2123 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2124 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
2125 return talk_base::scoped_refptr<PeerConnectionInterface>(
2126 reinterpret_cast<PeerConnectionInterface*>(j_p));
2127}
2128
2129JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2130 const SessionDescriptionInterface* sdp =
2131 ExtractNativePC(jni, j_pc)->local_description();
2132 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2133}
2134
2135JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2136 const SessionDescriptionInterface* sdp =
2137 ExtractNativePC(jni, j_pc)->remote_description();
2138 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2139}
2140
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002141JOW(jobject, PeerConnection_createDataChannel)(
2142 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2143 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
2144 talk_base::scoped_refptr<DataChannelInterface> channel(
2145 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2146 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002147 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2148 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2149 // 32-bit parameter.
2150 jlong nativeChannelPtr = jlongFromPointer(channel.get());
2151 CHECK(nativeChannelPtr, "Failed to create DataChannel");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002152 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2153 jmethodID j_data_channel_ctor = GetMethodID(
2154 jni, j_data_channel_class, "<init>", "(J)V");
2155 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002156 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002157 CHECK_EXCEPTION(jni, "error during NewObject");
2158 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002159 int bumped_count = channel->AddRef();
2160 CHECK(bumped_count == 2, "Unexpected refcount");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002161 return j_channel;
2162}
2163
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164JOW(void, PeerConnection_createOffer)(
2165 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2166 ConstraintsWrapper* constraints =
2167 new ConstraintsWrapper(jni, j_constraints);
2168 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2169 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2170 jni, j_observer, constraints));
2171 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2172}
2173
2174JOW(void, PeerConnection_createAnswer)(
2175 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2176 ConstraintsWrapper* constraints =
2177 new ConstraintsWrapper(jni, j_constraints);
2178 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2179 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2180 jni, j_observer, constraints));
2181 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2182}
2183
2184// Helper to create a SessionDescriptionInterface from a SessionDescription.
2185static SessionDescriptionInterface* JavaSdpToNativeSdp(
2186 JNIEnv* jni, jobject j_sdp) {
2187 jfieldID j_type_id = GetFieldID(
2188 jni, GetObjectClass(jni, j_sdp), "type",
2189 "Lorg/webrtc/SessionDescription$Type;");
2190 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2191 jmethodID j_canonical_form_id = GetMethodID(
2192 jni, GetObjectClass(jni, j_type), "canonicalForm",
2193 "()Ljava/lang/String;");
2194 jstring j_type_string = (jstring)jni->CallObjectMethod(
2195 j_type, j_canonical_form_id);
2196 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2197 std::string std_type = JavaToStdString(jni, j_type_string);
2198
2199 jfieldID j_description_id = GetFieldID(
2200 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2201 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2202 std::string std_description = JavaToStdString(jni, j_description);
2203
2204 return webrtc::CreateSessionDescription(
2205 std_type, std_description, NULL);
2206}
2207
2208JOW(void, PeerConnection_setLocalDescription)(
2209 JNIEnv* jni, jobject j_pc,
2210 jobject j_observer, jobject j_sdp) {
2211 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2212 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2213 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2214 ExtractNativePC(jni, j_pc)->SetLocalDescription(
2215 observer, JavaSdpToNativeSdp(jni, j_sdp));
2216}
2217
2218JOW(void, PeerConnection_setRemoteDescription)(
2219 JNIEnv* jni, jobject j_pc,
2220 jobject j_observer, jobject j_sdp) {
2221 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2222 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2223 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2224 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2225 observer, JavaSdpToNativeSdp(jni, j_sdp));
2226}
2227
2228JOW(jboolean, PeerConnection_updateIce)(
2229 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2230 PeerConnectionInterface::IceServers ice_servers;
2231 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002232 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002233 new ConstraintsWrapper(jni, j_constraints));
2234 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2235}
2236
2237JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2238 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2239 jint j_sdp_mline_index, jstring j_candidate_sdp) {
2240 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2241 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002242 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002243 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2244 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2245}
2246
2247JOW(jboolean, PeerConnection_nativeAddLocalStream)(
2248 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002249 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002250 new ConstraintsWrapper(jni, j_constraints));
2251 return ExtractNativePC(jni, j_pc)->AddStream(
2252 reinterpret_cast<MediaStreamInterface*>(native_stream),
2253 constraints.get());
2254}
2255
2256JOW(void, PeerConnection_nativeRemoveLocalStream)(
2257 JNIEnv* jni, jobject j_pc, jlong native_stream) {
2258 ExtractNativePC(jni, j_pc)->RemoveStream(
2259 reinterpret_cast<MediaStreamInterface*>(native_stream));
2260}
2261
2262JOW(bool, PeerConnection_nativeGetStats)(
2263 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
2264 talk_base::scoped_refptr<StatsObserverWrapper> observer(
2265 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
2266 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00002267 observer,
2268 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
2269 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002270}
2271
2272JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2273 PeerConnectionInterface::SignalingState state =
2274 ExtractNativePC(jni, j_pc)->signaling_state();
2275 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2276}
2277
2278JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2279 PeerConnectionInterface::IceConnectionState state =
2280 ExtractNativePC(jni, j_pc)->ice_connection_state();
2281 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2282}
2283
2284JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
2285 PeerConnectionInterface::IceGatheringState state =
2286 ExtractNativePC(jni, j_pc)->ice_gathering_state();
2287 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
2288}
2289
2290JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2291 ExtractNativePC(jni, j_pc)->Close();
2292 return;
2293}
2294
2295JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
2296 talk_base::scoped_refptr<MediaSourceInterface> p(
2297 reinterpret_cast<MediaSourceInterface*>(j_p));
2298 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2299}
2300
2301JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
2302 JNIEnv* jni, jclass, jstring j_device_name) {
2303 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002304 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002305 cricket::DeviceManagerFactory::Create());
2306 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
2307 cricket::Device device;
2308 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002309 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310 return 0;
2311 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002312 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002313 device_manager->CreateVideoCapturer(device));
2314 return (jlong)capturer.release();
2315}
2316
2317JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2318 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002319 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2320 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002321 return (jlong)renderer.release();
2322}
2323
2324JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2325 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002326 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002327 new JavaVideoRendererWrapper(jni, j_callbacks));
2328 return (jlong)renderer.release();
2329}
2330
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002331JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2332 cricket::VideoCapturer* capturer =
2333 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002334 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002335 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2336 capturer->Stop();
2337 return jlongFromPointer(format.release());
2338}
2339
2340JOW(void, VideoSource_restart)(
2341 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002342 CHECK(j_p_source, "");
2343 CHECK(j_p_format, "");
2344 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002345 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2346 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2347 StartCapturing(cricket::VideoFormat(*format));
2348}
2349
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00002350JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002351 JNIEnv* jni, jclass, jlong j_p) {
2352 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2353}
2354
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002355JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002356 return JavaStringFromStdString(
2357 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002358}
2359
2360JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002361 return JavaStringFromStdString(
2362 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002363}
2364
2365JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002366 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367}
2368
2369JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002370 return JavaEnumFromIndex(
2371 jni,
2372 "MediaStreamTrack$State",
2373 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002374}
2375
2376JOW(jboolean, MediaStreamTrack_nativeSetState)(
2377 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002378 MediaStreamTrackInterface::TrackState new_state =
2379 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002380 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2381 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382}
2383
2384JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2385 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002386 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2387 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002388}
2389
2390JOW(void, VideoTrack_nativeAddRenderer)(
2391 JNIEnv* jni, jclass,
2392 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002393 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002394 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2395}
2396
2397JOW(void, VideoTrack_nativeRemoveRenderer)(
2398 JNIEnv* jni, jclass,
2399 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002400 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002401 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2402}