blob: 3353de76c31a1b87f29e787900b73d84f4dad4fc [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.orgc6c1dfd2014-06-13 22:59:08 +00001137//#define TRACK_BUFFER_TIMING
1138#ifdef TRACK_BUFFER_TIMING
1139#include <android/log.h>
1140#define TAG "MediaCodecVideoEncoder"
1141#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1142#else
1143#define ALOGV(...)
1144#endif
1145
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001146// Color formats supported by encoder - should mirror supportedColorList
1147// from MediaCodecVideoEncoder.java
1148enum COLOR_FORMATTYPE {
1149 COLOR_FormatYUV420Planar = 0x13,
1150 COLOR_FormatYUV420SemiPlanar = 0x15,
1151 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1152 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1153 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1154 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1155 // but requires some (16, 32?) byte alignment.
1156 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1157};
1158
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001159// Arbitrary interval to poll the codec for new outputs.
1160enum { kMediaCodecPollMs = 10 };
1161
1162// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1163// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1164// HW-backed video encode. This C++ class is implemented as a very thin shim,
1165// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1166// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1167// thread, currently the libjingle Worker thread.
1168class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
1169 public talk_base::MessageHandler {
1170 public:
1171 virtual ~MediaCodecVideoEncoder();
1172 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1173
1174 // webrtc::VideoEncoder implementation. Everything trampolines to
1175 // |codec_thread_| for execution.
1176 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1177 int32_t /* number_of_cores */,
1178 uint32_t /* max_payload_size */) OVERRIDE;
1179 virtual int32_t Encode(
1180 const webrtc::I420VideoFrame& input_image,
1181 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1182 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1183 virtual int32_t RegisterEncodeCompleteCallback(
1184 webrtc::EncodedImageCallback* callback) OVERRIDE;
1185 virtual int32_t Release() OVERRIDE;
1186 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1187 int /* rtt */) OVERRIDE;
1188 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1189
1190 // talk_base::MessageHandler implementation.
1191 virtual void OnMessage(talk_base::Message* msg) OVERRIDE;
1192
1193 private:
1194 // CHECK-fail if not running on |codec_thread_|.
1195 void CheckOnCodecThread();
1196
1197 // Release() and InitEncode() in an attempt to restore the codec to an
1198 // operable state. Necessary after all manner of OMX-layer errors.
1199 void ResetCodec();
1200
1201 // Implementation of webrtc::VideoEncoder methods above, all running on the
1202 // codec thread exclusively.
1203 //
1204 // If width==0 then this is assumed to be a re-initialization and the
1205 // previously-current values are reused instead of the passed parameters
1206 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001207 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001208 int32_t EncodeOnCodecThread(
1209 const webrtc::I420VideoFrame& input_image,
1210 const std::vector<webrtc::VideoFrameType>* frame_types);
1211 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1212 webrtc::EncodedImageCallback* callback);
1213 int32_t ReleaseOnCodecThread();
1214 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1215
1216 // Reset parameters valid between InitEncode() & Release() (see below).
1217 void ResetParameters(JNIEnv* jni);
1218
1219 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1220 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1221 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1222 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1223 jlong GetOutputBufferInfoPresentationTimestampUs(
1224 JNIEnv* jni,
1225 jobject j_output_buffer_info);
1226
1227 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1228 // true on success.
1229 bool DeliverPendingOutputs(JNIEnv* jni);
1230
1231 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1232 // |codec_thread_| synchronously.
1233 webrtc::EncodedImageCallback* callback_;
1234
1235 // State that is constant for the lifetime of this object once the ctor
1236 // returns.
1237 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1238 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1239 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1240 jmethodID j_init_encode_method_;
1241 jmethodID j_dequeue_input_buffer_method_;
1242 jmethodID j_encode_method_;
1243 jmethodID j_release_method_;
1244 jmethodID j_set_rates_method_;
1245 jmethodID j_dequeue_output_buffer_method_;
1246 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001247 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001248 jfieldID j_info_index_field_;
1249 jfieldID j_info_buffer_field_;
1250 jfieldID j_info_is_key_frame_field_;
1251 jfieldID j_info_presentation_timestamp_us_field_;
1252
1253 // State that is valid only between InitEncode() and the next Release().
1254 // Touched only on codec_thread_ so no explicit synchronization necessary.
1255 int width_; // Frame width in pixels.
1256 int height_; // Frame height in pixels.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001257 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001258 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001259 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001260 int frames_received_; // Number of frames received by encoder.
1261 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001262 int frames_in_queue_; // Number of frames in encoder queue.
1263 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1264 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001265 // Frame size in bytes fed to MediaCodec.
1266 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001267 // True only when between a callback_->Encoded() call return a positive value
1268 // and the next Encode() call being ignored.
1269 bool drop_next_input_frame_;
1270 // Global references; must be deleted in Release().
1271 std::vector<jobject> input_buffers_;
1272};
1273
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001274MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1275 // We depend on ResetParameters() to ensure no more callbacks to us after we
1276 // are deleted, so assert it here.
1277 CHECK(width_ == 0, "Release() should have been called");
1278}
1279
1280MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1281 : callback_(NULL),
1282 codec_thread_(new Thread()),
1283 j_media_codec_video_encoder_class_(
1284 jni,
1285 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1286 j_media_codec_video_encoder_(
1287 jni,
1288 jni->NewObject(*j_media_codec_video_encoder_class_,
1289 GetMethodID(jni,
1290 *j_media_codec_video_encoder_class_,
1291 "<init>",
1292 "()V"))) {
1293 ScopedLocalRefFrame local_ref_frame(jni);
1294 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1295 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1296 // 2732 means that deadlocks abound. This class synchronously trampolines
1297 // to |codec_thread_|, so if anything else can be coming to _us_ from
1298 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1299 // in the bug, we have a problem. For now work around that with a dedicated
1300 // thread.
1301 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
1302 CHECK(codec_thread_->Start(), "Failed to start MediaCodecVideoEncoder");
1303
1304 ResetParameters(jni);
1305
1306 jclass j_output_buffer_info_class =
1307 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1308 j_init_encode_method_ = GetMethodID(jni,
1309 *j_media_codec_video_encoder_class_,
1310 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001311 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001312 j_dequeue_input_buffer_method_ = GetMethodID(
1313 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1314 j_encode_method_ = GetMethodID(
1315 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1316 j_release_method_ =
1317 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1318 j_set_rates_method_ = GetMethodID(
1319 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1320 j_dequeue_output_buffer_method_ =
1321 GetMethodID(jni,
1322 *j_media_codec_video_encoder_class_,
1323 "dequeueOutputBuffer",
1324 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1325 j_release_output_buffer_method_ = GetMethodID(
1326 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1327
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001328 j_color_format_field_ =
1329 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001330 j_info_index_field_ =
1331 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1332 j_info_buffer_field_ = GetFieldID(
1333 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1334 j_info_is_key_frame_field_ =
1335 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1336 j_info_presentation_timestamp_us_field_ = GetFieldID(
1337 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
1338 CHECK_EXCEPTION(jni, "MediaCodecVideoEncoder ctor failed");
1339}
1340
1341int32_t MediaCodecVideoEncoder::InitEncode(
1342 const webrtc::VideoCodec* codec_settings,
1343 int32_t /* number_of_cores */,
1344 uint32_t /* max_payload_size */) {
1345 // Factory should guard against other codecs being used with us.
1346 CHECK(codec_settings->codecType == kVideoCodecVP8, "Unsupported codec");
1347
1348 return codec_thread_->Invoke<int32_t>(
1349 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1350 this,
1351 codec_settings->width,
1352 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001353 codec_settings->startBitrate,
1354 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001355}
1356
1357int32_t MediaCodecVideoEncoder::Encode(
1358 const webrtc::I420VideoFrame& frame,
1359 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1360 const std::vector<webrtc::VideoFrameType>* frame_types) {
1361 return codec_thread_->Invoke<int32_t>(Bind(
1362 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1363}
1364
1365int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1366 webrtc::EncodedImageCallback* callback) {
1367 return codec_thread_->Invoke<int32_t>(
1368 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1369 this,
1370 callback));
1371}
1372
1373int32_t MediaCodecVideoEncoder::Release() {
1374 return codec_thread_->Invoke<int32_t>(
1375 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1376}
1377
1378int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1379 int /* rtt */) {
1380 return WEBRTC_VIDEO_CODEC_OK;
1381}
1382
1383int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1384 uint32_t frame_rate) {
1385 return codec_thread_->Invoke<int32_t>(
1386 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1387 this,
1388 new_bit_rate,
1389 frame_rate));
1390}
1391
1392void MediaCodecVideoEncoder::OnMessage(talk_base::Message* msg) {
1393 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1394 ScopedLocalRefFrame local_ref_frame(jni);
1395
1396 // We only ever send one message to |this| directly (not through a Bind()'d
1397 // functor), so expect no ID/data.
1398 CHECK(!msg->message_id, "Unexpected message!");
1399 CHECK(!msg->pdata, "Unexpected message!");
1400 CheckOnCodecThread();
1401
1402 // It would be nice to recover from a failure here if one happened, but it's
1403 // unclear how to signal such a failure to the app, so instead we stay silent
1404 // about it and let the next app-called API method reveal the borkedness.
1405 DeliverPendingOutputs(jni);
1406 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1407}
1408
1409void MediaCodecVideoEncoder::CheckOnCodecThread() {
1410 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread(),
1411 "Running on wrong thread!");
1412}
1413
1414void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001415 LOG(LS_ERROR) << "ResetCodec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001416 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1417 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001418 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0, 0))
1419 != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001420 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1421 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1422 // https://code.google.com/p/webrtc/issues/detail?id=2920
1423 }
1424}
1425
1426int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001427 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001428 CheckOnCodecThread();
1429 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1430 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001431 LOG(LS_INFO) << "InitEncodeOnCodecThread " << width << " x " << height;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001432
1433 if (width == 0) {
1434 width = width_;
1435 height = height_;
1436 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001437 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001438 }
1439
1440 width_ = width;
1441 height_ = height;
1442 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001443 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001444 yuv_size_ = width_ * height_ * 3 / 2;
1445 frames_received_ = 0;
1446 frames_dropped_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001447 frames_in_queue_ = 0;
1448 last_input_timestamp_ms_ = -1;
1449 last_output_timestamp_ms_ = -1;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001450 // We enforce no extra stride/padding in the format creation step.
1451 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1452 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1453 j_init_encode_method_,
1454 width_,
1455 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001456 kbps,
1457 fps));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001458 CHECK_EXCEPTION(jni, "");
1459 if (IsNull(jni, input_buffers))
1460 return WEBRTC_VIDEO_CODEC_ERROR;
1461
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001462 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1463 j_color_format_field_)) {
1464 case COLOR_FormatYUV420Planar:
1465 encoder_fourcc_ = libyuv::FOURCC_YU12;
1466 break;
1467 case COLOR_FormatYUV420SemiPlanar:
1468 case COLOR_QCOM_FormatYUV420SemiPlanar:
1469 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1470 encoder_fourcc_ = libyuv::FOURCC_NV12;
1471 break;
1472 default:
1473 LOG(LS_ERROR) << "Wrong color format.";
1474 return WEBRTC_VIDEO_CODEC_ERROR;
1475 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001476 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1477 CHECK(input_buffers_.empty(), "Unexpected double InitEncode without Release");
1478 input_buffers_.resize(num_input_buffers);
1479 for (size_t i = 0; i < num_input_buffers; ++i) {
1480 input_buffers_[i] =
1481 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001482 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001483 jni->GetDirectBufferCapacity(input_buffers_[i]);
1484 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001485 CHECK(yuv_buffer_capacity >= yuv_size_, "Insufficient capacity");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001486 }
1487 CHECK_EXCEPTION(jni, "");
1488
1489 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1490 return WEBRTC_VIDEO_CODEC_OK;
1491}
1492
1493int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1494 const webrtc::I420VideoFrame& frame,
1495 const std::vector<webrtc::VideoFrameType>* frame_types) {
1496 CheckOnCodecThread();
1497 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1498 ScopedLocalRefFrame local_ref_frame(jni);
1499
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001500 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001501 if (!DeliverPendingOutputs(jni)) {
1502 ResetCodec();
1503 // Continue as if everything's fine.
1504 }
1505
1506 if (drop_next_input_frame_) {
1507 drop_next_input_frame_ = false;
1508 return WEBRTC_VIDEO_CODEC_OK;
1509 }
1510
1511 CHECK(frame_types->size() == 1, "Unexpected stream count");
1512 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1513
1514 CHECK(frame.width() == width_, "Unexpected resolution change");
1515 CHECK(frame.height() == height_, "Unexpected resolution change");
1516
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001517 // Check if we accumulated too many frames in encoder input buffers
1518 // so the encoder latency exceeds 100ms and drop frame if so.
1519 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ > 0 &&
1520 last_output_timestamp_ms_ > 0) {
1521 int encoder_latency_ms = last_input_timestamp_ms_ -
1522 last_output_timestamp_ms_;
1523 if (encoder_latency_ms > 100) {
1524 ALOGV("Drop frame - encoder is behind by %d ms. Q size: %d",
1525 encoder_latency_ms, frames_in_queue_);
1526 frames_dropped_++;
1527 return WEBRTC_VIDEO_CODEC_OK;
1528 }
1529 }
1530
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001531 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1532 j_dequeue_input_buffer_method_);
1533 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001534 if (j_input_buffer_index == -1) {
1535 // Video codec falls behind - no input buffer available.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001536 ALOGV("Drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001537 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001538 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001539 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001540 if (j_input_buffer_index == -2) {
1541 ResetCodec();
1542 return WEBRTC_VIDEO_CODEC_ERROR;
1543 }
1544
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001545 ALOGV("Frame # %d. Buffer # %d. TS: %lld.",
1546 frames_received_, j_input_buffer_index, frame.render_time_ms());
1547
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001548 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001549 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001550 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
1551 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001552 CHECK(yuv_buffer, "Indirect buffer??");
1553 CHECK(!libyuv::ConvertFromI420(
1554 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1555 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1556 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1557 yuv_buffer, width_,
1558 width_, height_,
1559 encoder_fourcc_),
1560 "ConvertFromI420 failed");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001561 jlong timestamp_us = frame.render_time_ms() * 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001562 last_input_timestamp_ms_ = frame.render_time_ms();
1563 frames_in_queue_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001564 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1565 j_encode_method_,
1566 key_frame,
1567 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001568 yuv_size_,
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001569 timestamp_us);
1570 CHECK_EXCEPTION(jni, "");
1571 if (!encode_status || !DeliverPendingOutputs(jni)) {
1572 ResetCodec();
1573 return WEBRTC_VIDEO_CODEC_ERROR;
1574 }
1575
1576 return WEBRTC_VIDEO_CODEC_OK;
1577}
1578
1579int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1580 webrtc::EncodedImageCallback* callback) {
1581 CheckOnCodecThread();
1582 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1583 ScopedLocalRefFrame local_ref_frame(jni);
1584 callback_ = callback;
1585 return WEBRTC_VIDEO_CODEC_OK;
1586}
1587
1588int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
1589 CheckOnCodecThread();
1590 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001591 LOG(LS_INFO) << "Frames received: " << frames_received_ <<
1592 ". Frames dropped: " << frames_dropped_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001593 ScopedLocalRefFrame local_ref_frame(jni);
1594 for (size_t i = 0; i < input_buffers_.size(); ++i)
1595 jni->DeleteGlobalRef(input_buffers_[i]);
1596 input_buffers_.clear();
1597 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1598 ResetParameters(jni);
1599 CHECK_EXCEPTION(jni, "");
1600 return WEBRTC_VIDEO_CODEC_OK;
1601}
1602
1603int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1604 uint32_t frame_rate) {
1605 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001606 if (last_set_bitrate_kbps_ == new_bit_rate &&
1607 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001608 return WEBRTC_VIDEO_CODEC_OK;
1609 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001610 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1611 ScopedLocalRefFrame local_ref_frame(jni);
1612 last_set_bitrate_kbps_ = new_bit_rate;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001613 last_set_fps_ = frame_rate;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001614 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1615 j_set_rates_method_,
1616 new_bit_rate,
1617 frame_rate);
1618 CHECK_EXCEPTION(jni, "");
1619 if (!ret) {
1620 ResetCodec();
1621 return WEBRTC_VIDEO_CODEC_ERROR;
1622 }
1623 return WEBRTC_VIDEO_CODEC_OK;
1624}
1625
1626void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
1627 talk_base::MessageQueueManager::Clear(this);
1628 width_ = 0;
1629 height_ = 0;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001630 yuv_size_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001631 drop_next_input_frame_ = false;
1632 CHECK(input_buffers_.empty(),
1633 "ResetParameters called while holding input_buffers_!");
1634}
1635
1636int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1637 JNIEnv* jni,
1638 jobject j_output_buffer_info) {
1639 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1640}
1641
1642jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1643 JNIEnv* jni,
1644 jobject j_output_buffer_info) {
1645 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1646}
1647
1648bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1649 JNIEnv* jni,
1650 jobject j_output_buffer_info) {
1651 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1652}
1653
1654jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1655 JNIEnv* jni,
1656 jobject j_output_buffer_info) {
1657 return GetLongField(
1658 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1659}
1660
1661bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1662 while (true) {
1663 jobject j_output_buffer_info = jni->CallObjectMethod(
1664 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
1665 CHECK_EXCEPTION(jni, "");
1666 if (IsNull(jni, j_output_buffer_info))
1667 break;
1668
1669 int output_buffer_index =
1670 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1671 if (output_buffer_index == -1) {
1672 ResetCodec();
1673 return false;
1674 }
1675
1676 jlong capture_time_ms =
1677 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1678 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001679 last_output_timestamp_ms_ = capture_time_ms;
1680 frames_in_queue_--;
1681 ALOGV("Got output buffer # %d. TS: %lld. Latency: %lld",
1682 output_buffer_index, last_output_timestamp_ms_,
1683 last_input_timestamp_ms_ - last_output_timestamp_ms_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001684
1685 int32_t callback_status = 0;
1686 if (callback_) {
1687 jobject j_output_buffer =
1688 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1689 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1690 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1691 uint8* payload = reinterpret_cast<uint8_t*>(
1692 jni->GetDirectBufferAddress(j_output_buffer));
1693 CHECK_EXCEPTION(jni, "");
1694 scoped_ptr<webrtc::EncodedImage> image(
1695 new webrtc::EncodedImage(payload, payload_size, payload_size));
1696 image->_encodedWidth = width_;
1697 image->_encodedHeight = height_;
1698 // Convert capture time to 90 kHz RTP timestamp.
1699 image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
1700 image->capture_time_ms_ = capture_time_ms;
1701 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1702 image->_completeFrame = true;
1703
1704 webrtc::CodecSpecificInfo info;
1705 memset(&info, 0, sizeof(info));
1706 info.codecType = kVideoCodecVP8;
1707 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1708 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1709 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1710
1711 // Generate a header describing a single fragment.
1712 webrtc::RTPFragmentationHeader header;
1713 memset(&header, 0, sizeof(header));
1714 header.VerifyAndAllocateFragmentationHeader(1);
1715 header.fragmentationOffset[0] = 0;
1716 header.fragmentationLength[0] = image->_length;
1717 header.fragmentationPlType[0] = 0;
1718 header.fragmentationTimeDiff[0] = 0;
1719
1720 callback_status = callback_->Encoded(*image, &info, &header);
1721 }
1722
1723 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1724 j_release_output_buffer_method_,
1725 output_buffer_index);
1726 CHECK_EXCEPTION(jni, "");
1727 if (!success) {
1728 ResetCodec();
1729 return false;
1730 }
1731
1732 if (callback_status > 0)
1733 drop_next_input_frame_ = true;
1734 // Theoretically could handle callback_status<0 here, but unclear what that
1735 // would mean for us.
1736 }
1737
1738 return true;
1739}
1740
1741// Simplest-possible implementation of an encoder factory, churns out
1742// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1743class MediaCodecVideoEncoderFactory
1744 : public cricket::WebRtcVideoEncoderFactory {
1745 public:
1746 MediaCodecVideoEncoderFactory();
1747 virtual ~MediaCodecVideoEncoderFactory();
1748
1749 // WebRtcVideoEncoderFactory implementation.
1750 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1751 OVERRIDE;
1752 virtual void AddObserver(Observer* observer) OVERRIDE;
1753 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1754 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1755 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1756
1757 private:
1758 // Empty if platform support is lacking, const after ctor returns.
1759 std::vector<VideoCodec> supported_codecs_;
1760};
1761
1762MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1763 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1764 ScopedLocalRefFrame local_ref_frame(jni);
1765 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1766 bool is_platform_supported = jni->CallStaticBooleanMethod(
1767 j_encoder_class,
1768 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
1769 CHECK_EXCEPTION(jni, "");
1770 if (!is_platform_supported)
1771 return;
1772
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001773 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1774 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1775 // reasonable defaults.
1776 supported_codecs_.push_back(
1777 VideoCodec(kVideoCodecVP8, "VP8", 1920, 1088, 30));
1778}
1779
1780MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1781
1782webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1783 webrtc::VideoCodecType type) {
1784 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1785 return NULL;
1786 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1787}
1788
1789// Since the available codec list is never going to change, we ignore the
1790// Observer-related interface here.
1791void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1792void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1793
1794const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1795MediaCodecVideoEncoderFactory::codecs() const {
1796 return supported_codecs_;
1797}
1798
1799void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1800 webrtc::VideoEncoder* encoder) {
1801 delete encoder;
1802}
1803
1804#endif // ANDROID
1805
1806} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001807
1808// Convenience macro defining JNI-accessible methods in the org.webrtc package.
1809// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1810#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1811 Java_org_webrtc_##name
1812
1813extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1814 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1815 g_jvm = jvm;
1816 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1817
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00001818 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey), "pthread_once");
1819
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001820 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1821
1822 JNIEnv* jni;
1823 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1824 return -1;
1825 g_class_reference_holder = new ClassReferenceHolder(jni);
1826
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001827 return JNI_VERSION_1_6;
1828}
1829
1830extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001831 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001832 delete g_class_reference_holder;
1833 g_class_reference_holder = NULL;
1834 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00001835 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836}
1837
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001838static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001839 jfieldID native_dc_id = GetFieldID(jni,
1840 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1841 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001842 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001843}
1844
1845JOW(jlong, DataChannel_registerObserverNative)(
1846 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001847 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001848 new DataChannelObserverWrapper(jni, j_observer));
1849 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00001850 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001851}
1852
1853JOW(void, DataChannel_unregisterObserverNative)(
1854 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1855 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1856 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1857}
1858
1859JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1860 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1861}
1862
1863JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1864 return JavaEnumFromIndex(
1865 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1866}
1867
1868JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1869 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1870 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1871 "buffered_amount overflowed jlong!");
1872 return static_cast<jlong>(buffered_amount);
1873}
1874
1875JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1876 ExtractNativeDC(jni, j_dc)->Close();
1877}
1878
1879JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1880 jbyteArray data, jboolean binary) {
1881 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1882 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1883 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1884 binary));
1885 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1886 return ret;
1887}
1888
1889JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001890 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001891}
1892
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001893JOW(void, Logging_nativeEnableTracing)(
1894 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1895 jint nativeSeverity) {
1896 std::string path = JavaToStdString(jni, j_path);
1897 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00001898 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00001899#ifdef ANDROID
1900 if (path != "logcat:") {
1901#endif
1902 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1903 "SetTraceFile failed");
1904#ifdef ANDROID
1905 } else {
1906 // Intentionally leak this to avoid needing to reason about its lifecycle.
1907 // It keeps no state and functions only as a dispatch point.
1908 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1909 }
1910#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001911 }
1912 talk_base::LogMessage::LogToDebug(nativeSeverity);
1913}
1914
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001916 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001917}
1918
1919JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1920 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1921 delete p;
1922}
1923
1924JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001925 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001926}
1927
1928JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1929 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1930}
1931
1932JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1933 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1934}
1935
1936JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001937 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938}
1939
1940JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1941 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001942 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001943 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001944}
1945
1946JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1947 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001948 return reinterpret_cast<MediaStreamInterface*>(pointer)
1949 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950}
1951
1952JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1953 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001954 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001956}
1957
1958JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1959 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001960 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001961 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962}
1963
1964JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1965 return JavaStringFromStdString(
1966 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1967}
1968
1969JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001970 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971}
1972
1973JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1974 JNIEnv * jni, jclass, jobject j_observer) {
1975 return (jlong)new PCOJava(jni, j_observer);
1976}
1977
1978#ifdef ANDROID
1979JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001980 JNIEnv* jni, jclass, jobject context,
1981 jboolean initialize_audio, jboolean initialize_video) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001982 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1983 bool failure = false;
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001984 if (initialize_video)
fischman@webrtc.org95127192014-06-06 18:40:44 +00001985 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001986 if (initialize_audio)
1987 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001988 return !failure;
1989}
1990#endif // ANDROID
1991
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001992// Helper struct for working around the fact that CreatePeerConnectionFactory()
1993// comes in two flavors: either entirely automagical (constructing its own
1994// threads and deleting them on teardown, but no external codec factory support)
1995// or entirely manual (requires caller to delete threads after factory
1996// teardown). This struct takes ownership of its ctor's arguments to present a
1997// single thing for Java to hold and eventually free.
1998class OwnedFactoryAndThreads {
1999 public:
2000 OwnedFactoryAndThreads(Thread* worker_thread,
2001 Thread* signaling_thread,
2002 PeerConnectionFactoryInterface* factory)
2003 : worker_thread_(worker_thread),
2004 signaling_thread_(signaling_thread),
2005 factory_(factory) {}
2006
2007 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2008
2009 PeerConnectionFactoryInterface* factory() { return factory_; }
2010
2011 private:
2012 const scoped_ptr<Thread> worker_thread_;
2013 const scoped_ptr<Thread> signaling_thread_;
2014 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2015};
2016
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002017JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2018 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002019 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2020 // ThreadManager only WrapCurrentThread()s the thread where it is first
2021 // created. Since the semantics around when auto-wrapping happens in
2022 // talk/base/ are convoluted, we simply wrap here to avoid having to think
2023 // about ramifications of auto-wrapping there.
2024 talk_base::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002025 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002026 Thread* worker_thread = new Thread();
2027 worker_thread->SetName("worker_thread", NULL);
2028 Thread* signaling_thread = new Thread();
2029 signaling_thread->SetName("signaling_thread", NULL);
2030 CHECK(worker_thread->Start() && signaling_thread->Start(),
2031 "Failed to start threads");
2032 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
2033#ifdef ANDROID
2034 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
2035#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002036 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002037 webrtc::CreatePeerConnectionFactory(worker_thread,
2038 signaling_thread,
2039 NULL,
2040 encoder_factory.release(),
2041 NULL));
2042 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2043 worker_thread, signaling_thread, factory.release());
2044 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002045}
2046
2047JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002048 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002049 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002050}
2051
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002052static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2053 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2054}
2055
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002056JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2057 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
2058 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002059 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002060 talk_base::scoped_refptr<MediaStreamInterface> stream(
2061 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2062 return (jlong)stream.release();
2063}
2064
2065JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2066 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2067 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002068 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002069 new ConstraintsWrapper(jni, j_constraints));
2070 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002071 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072 talk_base::scoped_refptr<VideoSourceInterface> source(
2073 factory->CreateVideoSource(
2074 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2075 constraints.get()));
2076 return (jlong)source.release();
2077}
2078
2079JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2080 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2081 jlong native_source) {
2082 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002083 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002084 talk_base::scoped_refptr<VideoTrackInterface> track(
2085 factory->CreateVideoTrack(
2086 JavaToStdString(jni, id),
2087 reinterpret_cast<VideoSourceInterface*>(native_source)));
2088 return (jlong)track.release();
2089}
2090
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002091JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2092 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2093 scoped_ptr<ConstraintsWrapper> constraints(
2094 new ConstraintsWrapper(jni, j_constraints));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002095 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002096 factoryFromJava(native_factory));
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002097 talk_base::scoped_refptr<AudioSourceInterface> source(
2098 factory->CreateAudioSource(constraints.get()));
2099 return (jlong)source.release();
2100}
2101
2102JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2103 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2104 jlong native_source) {
2105 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
2106 factoryFromJava(native_factory));
2107 talk_base::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
2108 JavaToStdString(jni, id),
2109 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002110 return (jlong)track.release();
2111}
2112
2113static void JavaIceServersToJsepIceServers(
2114 JNIEnv* jni, jobject j_ice_servers,
2115 PeerConnectionInterface::IceServers* ice_servers) {
2116 jclass list_class = GetObjectClass(jni, j_ice_servers);
2117 jmethodID iterator_id = GetMethodID(
2118 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2119 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
2120 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2121 jmethodID iterator_has_next = GetMethodID(
2122 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2123 jmethodID iterator_next = GetMethodID(
2124 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2125 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
2126 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2127 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
2128 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2129 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2130 jfieldID j_ice_server_uri_id =
2131 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2132 jfieldID j_ice_server_username_id =
2133 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2134 jfieldID j_ice_server_password_id =
2135 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2136 jstring uri = reinterpret_cast<jstring>(
2137 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2138 jstring username = reinterpret_cast<jstring>(
2139 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2140 jstring password = reinterpret_cast<jstring>(
2141 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2142 PeerConnectionInterface::IceServer server;
2143 server.uri = JavaToStdString(jni, uri);
2144 server.username = JavaToStdString(jni, username);
2145 server.password = JavaToStdString(jni, password);
2146 ice_servers->push_back(server);
2147 }
2148 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2149}
2150
2151JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2152 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2153 jobject j_constraints, jlong observer_p) {
2154 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002155 reinterpret_cast<PeerConnectionFactoryInterface*>(
2156 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002157 PeerConnectionInterface::IceServers servers;
2158 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2159 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2160 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
2161 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002162 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002163 return (jlong)pc.release();
2164}
2165
2166static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
2167 JNIEnv* jni, jobject j_pc) {
2168 jfieldID native_pc_id = GetFieldID(jni,
2169 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2170 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
2171 return talk_base::scoped_refptr<PeerConnectionInterface>(
2172 reinterpret_cast<PeerConnectionInterface*>(j_p));
2173}
2174
2175JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2176 const SessionDescriptionInterface* sdp =
2177 ExtractNativePC(jni, j_pc)->local_description();
2178 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2179}
2180
2181JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2182 const SessionDescriptionInterface* sdp =
2183 ExtractNativePC(jni, j_pc)->remote_description();
2184 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2185}
2186
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002187JOW(jobject, PeerConnection_createDataChannel)(
2188 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2189 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
2190 talk_base::scoped_refptr<DataChannelInterface> channel(
2191 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2192 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002193 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2194 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2195 // 32-bit parameter.
2196 jlong nativeChannelPtr = jlongFromPointer(channel.get());
2197 CHECK(nativeChannelPtr, "Failed to create DataChannel");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002198 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2199 jmethodID j_data_channel_ctor = GetMethodID(
2200 jni, j_data_channel_class, "<init>", "(J)V");
2201 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002202 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002203 CHECK_EXCEPTION(jni, "error during NewObject");
2204 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002205 int bumped_count = channel->AddRef();
2206 CHECK(bumped_count == 2, "Unexpected refcount");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002207 return j_channel;
2208}
2209
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002210JOW(void, PeerConnection_createOffer)(
2211 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2212 ConstraintsWrapper* constraints =
2213 new ConstraintsWrapper(jni, j_constraints);
2214 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2215 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2216 jni, j_observer, constraints));
2217 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2218}
2219
2220JOW(void, PeerConnection_createAnswer)(
2221 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2222 ConstraintsWrapper* constraints =
2223 new ConstraintsWrapper(jni, j_constraints);
2224 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2225 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2226 jni, j_observer, constraints));
2227 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2228}
2229
2230// Helper to create a SessionDescriptionInterface from a SessionDescription.
2231static SessionDescriptionInterface* JavaSdpToNativeSdp(
2232 JNIEnv* jni, jobject j_sdp) {
2233 jfieldID j_type_id = GetFieldID(
2234 jni, GetObjectClass(jni, j_sdp), "type",
2235 "Lorg/webrtc/SessionDescription$Type;");
2236 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2237 jmethodID j_canonical_form_id = GetMethodID(
2238 jni, GetObjectClass(jni, j_type), "canonicalForm",
2239 "()Ljava/lang/String;");
2240 jstring j_type_string = (jstring)jni->CallObjectMethod(
2241 j_type, j_canonical_form_id);
2242 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2243 std::string std_type = JavaToStdString(jni, j_type_string);
2244
2245 jfieldID j_description_id = GetFieldID(
2246 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2247 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2248 std::string std_description = JavaToStdString(jni, j_description);
2249
2250 return webrtc::CreateSessionDescription(
2251 std_type, std_description, NULL);
2252}
2253
2254JOW(void, PeerConnection_setLocalDescription)(
2255 JNIEnv* jni, jobject j_pc,
2256 jobject j_observer, jobject j_sdp) {
2257 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2258 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2259 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2260 ExtractNativePC(jni, j_pc)->SetLocalDescription(
2261 observer, JavaSdpToNativeSdp(jni, j_sdp));
2262}
2263
2264JOW(void, PeerConnection_setRemoteDescription)(
2265 JNIEnv* jni, jobject j_pc,
2266 jobject j_observer, jobject j_sdp) {
2267 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2268 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2269 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2270 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2271 observer, JavaSdpToNativeSdp(jni, j_sdp));
2272}
2273
2274JOW(jboolean, PeerConnection_updateIce)(
2275 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2276 PeerConnectionInterface::IceServers ice_servers;
2277 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002278 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002279 new ConstraintsWrapper(jni, j_constraints));
2280 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2281}
2282
2283JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2284 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2285 jint j_sdp_mline_index, jstring j_candidate_sdp) {
2286 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2287 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002288 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002289 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2290 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2291}
2292
2293JOW(jboolean, PeerConnection_nativeAddLocalStream)(
2294 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002295 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002296 new ConstraintsWrapper(jni, j_constraints));
2297 return ExtractNativePC(jni, j_pc)->AddStream(
2298 reinterpret_cast<MediaStreamInterface*>(native_stream),
2299 constraints.get());
2300}
2301
2302JOW(void, PeerConnection_nativeRemoveLocalStream)(
2303 JNIEnv* jni, jobject j_pc, jlong native_stream) {
2304 ExtractNativePC(jni, j_pc)->RemoveStream(
2305 reinterpret_cast<MediaStreamInterface*>(native_stream));
2306}
2307
2308JOW(bool, PeerConnection_nativeGetStats)(
2309 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
2310 talk_base::scoped_refptr<StatsObserverWrapper> observer(
2311 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
2312 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00002313 observer,
2314 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
2315 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002316}
2317
2318JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2319 PeerConnectionInterface::SignalingState state =
2320 ExtractNativePC(jni, j_pc)->signaling_state();
2321 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2322}
2323
2324JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2325 PeerConnectionInterface::IceConnectionState state =
2326 ExtractNativePC(jni, j_pc)->ice_connection_state();
2327 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2328}
2329
2330JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
2331 PeerConnectionInterface::IceGatheringState state =
2332 ExtractNativePC(jni, j_pc)->ice_gathering_state();
2333 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
2334}
2335
2336JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2337 ExtractNativePC(jni, j_pc)->Close();
2338 return;
2339}
2340
2341JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
2342 talk_base::scoped_refptr<MediaSourceInterface> p(
2343 reinterpret_cast<MediaSourceInterface*>(j_p));
2344 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2345}
2346
2347JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
2348 JNIEnv* jni, jclass, jstring j_device_name) {
2349 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002350 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002351 cricket::DeviceManagerFactory::Create());
2352 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
2353 cricket::Device device;
2354 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002355 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002356 return 0;
2357 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002358 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002359 device_manager->CreateVideoCapturer(device));
2360 return (jlong)capturer.release();
2361}
2362
2363JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2364 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002365 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2366 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367 return (jlong)renderer.release();
2368}
2369
2370JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2371 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002372 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002373 new JavaVideoRendererWrapper(jni, j_callbacks));
2374 return (jlong)renderer.release();
2375}
2376
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002377JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2378 cricket::VideoCapturer* capturer =
2379 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002380 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002381 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2382 capturer->Stop();
2383 return jlongFromPointer(format.release());
2384}
2385
2386JOW(void, VideoSource_restart)(
2387 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002388 CHECK(j_p_source, "");
2389 CHECK(j_p_format, "");
2390 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002391 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2392 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2393 StartCapturing(cricket::VideoFormat(*format));
2394}
2395
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00002396JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002397 JNIEnv* jni, jclass, jlong j_p) {
2398 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2399}
2400
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002401JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002402 return JavaStringFromStdString(
2403 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002404}
2405
2406JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002407 return JavaStringFromStdString(
2408 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002409}
2410
2411JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002412 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002413}
2414
2415JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002416 return JavaEnumFromIndex(
2417 jni,
2418 "MediaStreamTrack$State",
2419 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002420}
2421
2422JOW(jboolean, MediaStreamTrack_nativeSetState)(
2423 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002424 MediaStreamTrackInterface::TrackState new_state =
2425 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002426 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2427 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002428}
2429
2430JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2431 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002432 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2433 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002434}
2435
2436JOW(void, VideoTrack_nativeAddRenderer)(
2437 JNIEnv* jni, jclass,
2438 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002439 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002440 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2441}
2442
2443JOW(void, VideoTrack_nativeRemoveRenderer)(
2444 JNIEnv* jni, jclass,
2445 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002446 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002447 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2448}