blob: 6bb8fed49be042434ef7e388797e578b5f49a680 [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"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000079#include "third_party/libyuv/include/libyuv/convert.h"
80#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000081#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000082#include "webrtc/system_wrappers/interface/trace.h"
83#include "webrtc/video_engine/include/vie_base.h"
84#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000086#ifdef ANDROID
87#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
88using webrtc::LogcatTraceContext;
89#endif
90
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091using icu::UnicodeString;
fischman@webrtc.org540acde2014-02-13 03:56:14 +000092using talk_base::Bind;
93using talk_base::Thread;
94using talk_base::ThreadManager;
95using talk_base::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000096using webrtc::AudioSourceInterface;
97using webrtc::AudioTrackInterface;
98using webrtc::AudioTrackVector;
99using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000100using webrtc::DataBuffer;
101using webrtc::DataChannelInit;
102using webrtc::DataChannelInterface;
103using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104using webrtc::IceCandidateInterface;
105using webrtc::MediaConstraintsInterface;
106using webrtc::MediaSourceInterface;
107using webrtc::MediaStreamInterface;
108using webrtc::MediaStreamTrackInterface;
109using webrtc::PeerConnectionFactoryInterface;
110using webrtc::PeerConnectionInterface;
111using webrtc::PeerConnectionObserver;
112using webrtc::SessionDescriptionInterface;
113using webrtc::SetSessionDescriptionObserver;
114using webrtc::StatsObserver;
115using webrtc::StatsReport;
116using webrtc::VideoRendererInterface;
117using webrtc::VideoSourceInterface;
118using webrtc::VideoTrackInterface;
119using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000120using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121
122// Abort the process if |x| is false, emitting |msg|.
123#define CHECK(x, msg) \
124 if (x) {} else { \
125 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
126 abort(); \
127 }
128// Abort the process if |jni| has a Java exception pending, emitting |msg|.
129#define CHECK_EXCEPTION(jni, msg) \
130 if (0) {} else { \
131 if (jni->ExceptionCheck()) { \
132 jni->ExceptionDescribe(); \
133 jni->ExceptionClear(); \
134 CHECK(0, msg); \
135 } \
136 }
137
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000138// Helper that calls ptr->Release() and logs a useful message if that didn't
139// actually delete *ptr because of extra refcounts.
140#define CHECK_RELEASE(ptr) \
141 do { \
142 int count = (ptr)->Release(); \
143 if (count != 0) { \
144 LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr) \
145 << ": " << count; \
146 } \
147 CHECK(!count, "Unexpected refcount"); \
148 } while (0)
149
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150namespace {
151
152static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
153
154static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000155// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
156// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
157// were attached by the JVM because of a Java->native call.
158static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000160// Return thread ID as a string.
161static std::string GetThreadId() {
162 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
163 CHECK(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)) <= sizeof(buf),
164 "Thread id is bigger than uint64??");
165 return std::string(buf);
166}
167
168// Return the current thread's name.
169static std::string GetThreadName() {
170 char name[17];
171 CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
172 name[16] = '\0';
173 return std::string(name);
174}
175
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000176// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
177static JNIEnv* GetEnv() {
178 void* env = NULL;
179 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
180 CHECK(((env != NULL) && (status == JNI_OK)) ||
181 ((env == NULL) && (status == JNI_EDETACHED)),
182 "Unexpected GetEnv return: " << status << ":" << env);
183 return reinterpret_cast<JNIEnv*>(env);
184}
185
186static void ThreadDestructor(void* prev_jni_ptr) {
187 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
188 // we were responsible for originally attaching the thread, so are responsible
189 // for detaching it now. However, because some JVM implementations (notably
190 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
191 // the JVMs accounting info for this thread may already be wiped out by the
192 // time this is called. Thus it may appear we are already detached even though
193 // it was our responsibility to detach! Oh well.
194 if (!GetEnv())
195 return;
196
197 CHECK(GetEnv() == prev_jni_ptr,
198 "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199 jint status = g_jvm->DetachCurrentThread();
200 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000201 CHECK(!GetEnv(), "Detaching was a successful no-op???");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202}
203
204static void CreateJNIPtrKey() {
205 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
206 "pthread_key_create");
207}
208
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000209// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000211 JNIEnv* jni = GetEnv();
212 if (jni)
213 return jni;
214 CHECK(!pthread_getspecific(g_jni_ptr), "TLS has a JNIEnv* but not attached?");
215
216 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
217 JavaVMAttachArgs args;
218 args.version = JNI_VERSION_1_6;
219 args.name = name;
220 args.group = NULL;
221 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000222#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000223 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000224#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000225 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226#endif
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000227 CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
228 free(name);
229 CHECK(env, "AttachCurrentThread handed back NULL!");
230 jni = reinterpret_cast<JNIEnv*>(env);
231 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000232 return jni;
233}
234
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000235// Return a |jlong| that will correctly convert back to |ptr|. This is needed
236// because the alternative (of silently passing a 32-bit pointer to a vararg
237// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000238static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000239 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000240 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000241 // Going through intptr_t to be obvious about the definedness of the
242 // conversion from pointer to integral type. intptr_t to jlong is a standard
243 // widening by the COMPILE_ASSERT above.
244 jlong ret = reinterpret_cast<intptr_t>(ptr);
245 assert(reinterpret_cast<void*>(ret) == ptr);
246 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000247}
248
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000249// Android's FindClass() is trickier than usual because the app-specific
250// ClassLoader is not consulted when there is no app-specific frame on the
251// stack. Consequently, we only look up classes once in JNI_OnLoad.
252// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
253class ClassReferenceHolder {
254 public:
255 explicit ClassReferenceHolder(JNIEnv* jni) {
256 LoadClass(jni, "java/nio/ByteBuffer");
257 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000258 LoadClass(jni, "org/webrtc/DataChannel");
259 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
260 LoadClass(jni, "org/webrtc/DataChannel$Init");
261 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262 LoadClass(jni, "org/webrtc/IceCandidate");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000263#ifdef ANDROID
264 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
265 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
266#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267 LoadClass(jni, "org/webrtc/MediaSource$State");
268 LoadClass(jni, "org/webrtc/MediaStream");
269 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
271 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000272 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000273 LoadClass(jni, "org/webrtc/SessionDescription");
274 LoadClass(jni, "org/webrtc/SessionDescription$Type");
275 LoadClass(jni, "org/webrtc/StatsReport");
276 LoadClass(jni, "org/webrtc/StatsReport$Value");
277 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
278 LoadClass(jni, "org/webrtc/VideoTrack");
279 }
280
281 ~ClassReferenceHolder() {
282 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
283 }
284
285 void FreeReferences(JNIEnv* jni) {
286 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
287 it != classes_.end(); ++it) {
288 jni->DeleteGlobalRef(it->second);
289 }
290 classes_.clear();
291 }
292
293 jclass GetClass(const std::string& name) {
294 std::map<std::string, jclass>::iterator it = classes_.find(name);
295 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
296 return it->second;
297 }
298
299 private:
300 void LoadClass(JNIEnv* jni, const std::string& name) {
301 jclass localRef = jni->FindClass(name.c_str());
302 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
303 CHECK(localRef, name);
304 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
305 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
306 CHECK(globalRef, name);
307 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
308 CHECK(inserted, "Duplicate class name: " << name);
309 }
310
311 std::map<std::string, jclass> classes_;
312};
313
314// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
315static ClassReferenceHolder* g_class_reference_holder = NULL;
316
317// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
318// object/class/method/field is non-null.
319jmethodID GetMethodID(
320 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
321 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
322 CHECK_EXCEPTION(jni,
323 "error during GetMethodID: " << name << ", " << signature);
324 CHECK(m, name << ", " << signature);
325 return m;
326}
327
328jmethodID GetStaticMethodID(
329 JNIEnv* jni, jclass c, const char* name, const char* signature) {
330 jmethodID m = jni->GetStaticMethodID(c, name, signature);
331 CHECK_EXCEPTION(jni,
332 "error during GetStaticMethodID: "
333 << name << ", " << signature);
334 CHECK(m, name << ", " << signature);
335 return m;
336}
337
338jfieldID GetFieldID(
339 JNIEnv* jni, jclass c, const char* name, const char* signature) {
340 jfieldID f = jni->GetFieldID(c, name, signature);
341 CHECK_EXCEPTION(jni, "error during GetFieldID");
342 CHECK(f, name << ", " << signature);
343 return f;
344}
345
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000346// Returns a global reference guaranteed to be valid for the lifetime of the
347// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000348jclass FindClass(JNIEnv* jni, const char* name) {
349 return g_class_reference_holder->GetClass(name);
350}
351
352jclass GetObjectClass(JNIEnv* jni, jobject object) {
353 jclass c = jni->GetObjectClass(object);
354 CHECK_EXCEPTION(jni, "error during GetObjectClass");
355 CHECK(c, "");
356 return c;
357}
358
359jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
360 jobject o = jni->GetObjectField(object, id);
361 CHECK_EXCEPTION(jni, "error during GetObjectField");
362 CHECK(o, "");
363 return o;
364}
365
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000366jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
367 return static_cast<jstring>(GetObjectField(jni, object, id));
368}
369
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
371 jlong l = jni->GetLongField(object, id);
372 CHECK_EXCEPTION(jni, "error during GetLongField");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000373 return l;
374}
375
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000376jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
377 jint i = jni->GetIntField(object, id);
378 CHECK_EXCEPTION(jni, "error during GetIntField");
379 return i;
380}
381
382bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
383 jboolean b = jni->GetBooleanField(object, id);
384 CHECK_EXCEPTION(jni, "error during GetBooleanField");
385 return b;
386}
387
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000388jobject NewGlobalRef(JNIEnv* jni, jobject o) {
389 jobject ret = jni->NewGlobalRef(o);
390 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
391 CHECK(ret, "");
392 return ret;
393}
394
395void DeleteGlobalRef(JNIEnv* jni, jobject o) {
396 jni->DeleteGlobalRef(o);
397 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
398}
399
400// Given a jweak reference, allocate a (strong) local reference scoped to the
401// lifetime of this object if the weak reference is still valid, or NULL
402// otherwise.
403class WeakRef {
404 public:
405 WeakRef(JNIEnv* jni, jweak ref)
406 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
407 CHECK_EXCEPTION(jni, "error during NewLocalRef");
408 }
409 ~WeakRef() {
410 if (obj_) {
411 jni_->DeleteLocalRef(obj_);
412 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
413 }
414 }
415 jobject obj() { return obj_; }
416
417 private:
418 JNIEnv* const jni_;
419 jobject const obj_;
420};
421
fischman@webrtc.org41776152014-01-09 00:31:17 +0000422// Scope Java local references to the lifetime of this object. Use in all C++
423// callbacks (i.e. entry points that don't originate in a Java callstack
424// through a "native" method call).
425class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000427 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
428 CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000430 ~ScopedLocalRefFrame() {
431 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000433
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 private:
435 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436};
437
438// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000439template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440class ScopedGlobalRef {
441 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000442 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000443 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 ~ScopedGlobalRef() {
445 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
446 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000447 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 return obj_;
449 }
450 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000451 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452};
453
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000454// Java references to "null" can only be distinguished as such in C++ by
455// creating a local reference, so this helper wraps that logic.
456static bool IsNull(JNIEnv* jni, jobject obj) {
457 ScopedLocalRefFrame local_ref_frame(jni);
458 return jni->NewLocalRef(obj) == NULL;
459}
460
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461// Return the (singleton) Java Enum object corresponding to |index|;
462// |state_class_fragment| is something like "MediaSource$State".
463jobject JavaEnumFromIndex(
464 JNIEnv* jni, const std::string& state_class_fragment, int index) {
465 std::string state_class_name = "org/webrtc/" + state_class_fragment;
466 jclass state_class = FindClass(jni, state_class_name.c_str());
467 jmethodID state_values_id = GetStaticMethodID(
468 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000469 jobjectArray state_values = static_cast<jobjectArray>(
470 jni->CallStaticObjectMethod(state_class, state_values_id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000472 jobject ret = jni->GetObjectArrayElement(state_values, index);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
474 return ret;
475}
476
477// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
478static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
479 UnicodeString ustr(UnicodeString::fromUTF8(native));
480 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
481 CHECK_EXCEPTION(jni, "error during NewString");
482 return jstr;
483}
484
485// Given a (UTF-16) jstring return a new UTF-8 native string.
486static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
487 const jchar* jchars = jni->GetStringChars(j_string, NULL);
488 CHECK_EXCEPTION(jni, "Error during GetStringChars");
489 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
490 CHECK_EXCEPTION(jni, "Error during GetStringLength");
491 jni->ReleaseStringChars(j_string, jchars);
492 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
493 std::string ret;
494 return ustr.toUTF8String(ret);
495}
496
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000497static DataChannelInit JavaDataChannelInitToNative(
498 JNIEnv* jni, jobject j_init) {
499 DataChannelInit init;
500
501 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
502 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
503 jfieldID max_retransmit_time_id =
504 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
505 jfieldID max_retransmits_id =
506 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
507 jfieldID protocol_id =
508 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
509 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
510 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
511
512 init.ordered = GetBooleanField(jni, j_init, ordered_id);
513 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
514 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
515 init.protocol = JavaToStdString(
516 jni, GetStringField(jni, j_init, protocol_id));
517 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
518 init.id = GetIntField(jni, j_init, id_id);
519
520 return init;
521}
522
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523class ConstraintsWrapper;
524
525// Adapter between the C++ PeerConnectionObserver interface and the Java
526// PeerConnection.Observer interface. Wraps an instance of the Java interface
527// and dispatches C++ callbacks to Java.
528class PCOJava : public PeerConnectionObserver {
529 public:
530 PCOJava(JNIEnv* jni, jobject j_observer)
531 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000532 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
533 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
534 j_media_stream_ctor_(GetMethodID(
535 jni, *j_media_stream_class_, "<init>", "(J)V")),
536 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000538 jni, *j_audio_track_class_, "<init>", "(J)V")),
539 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
540 j_video_track_ctor_(GetMethodID(
541 jni, *j_video_track_class_, "<init>", "(J)V")),
542 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
543 j_data_channel_ctor_(GetMethodID(
544 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 }
546
547 virtual ~PCOJava() {}
548
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000549 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000550 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551 std::string sdp;
552 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
553 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
554 jmethodID ctor = GetMethodID(jni(), candidate_class,
555 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000556 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
557 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
558 jobject j_candidate = jni()->NewObject(
559 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000561 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000563 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
565 }
566
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000567 virtual void OnError() OVERRIDE {
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000568 ScopedLocalRefFrame local_ref_frame(jni());
569 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570 jni()->CallVoidMethod(*j_observer_global_, m);
571 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
572 }
573
574 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000575 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000576 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000578 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000580 jobject new_state_enum =
581 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
582 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000583 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
584 }
585
586 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000587 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000588 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000590 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000592 jobject new_state_enum = JavaEnumFromIndex(
593 jni(), "PeerConnection$IceConnectionState", new_state);
594 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
596 }
597
598 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000599 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000600 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000602 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000604 jobject new_state_enum = JavaEnumFromIndex(
605 jni(), "PeerConnection$IceGatheringState", new_state);
606 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
608 }
609
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000610 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000611 ScopedLocalRefFrame local_ref_frame(jni());
612 jobject j_stream = jni()->NewObject(
613 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 CHECK_EXCEPTION(jni(), "error during NewObject");
615
616 AudioTrackVector audio_tracks = stream->GetAudioTracks();
617 for (size_t i = 0; i < audio_tracks.size(); ++i) {
618 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000619 jstring id = JavaStringFromStdString(jni(), track->id());
620 jobject j_track = jni()->NewObject(
621 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000623 jfieldID audio_tracks_id = GetFieldID(jni(),
624 *j_media_stream_class_,
625 "audioTracks",
626 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000627 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000629 GetObjectClass(jni(), audio_tracks),
630 "add",
631 "(Ljava/lang/Object;)Z");
632 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000633 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
634 CHECK(added, "");
635 }
636
637 VideoTrackVector video_tracks = stream->GetVideoTracks();
638 for (size_t i = 0; i < video_tracks.size(); ++i) {
639 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000640 jstring id = JavaStringFromStdString(jni(), track->id());
641 jobject j_track = jni()->NewObject(
642 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000644 jfieldID video_tracks_id = GetFieldID(jni(),
645 *j_media_stream_class_,
646 "videoTracks",
647 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000648 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000650 GetObjectClass(jni(), video_tracks),
651 "add",
652 "(Ljava/lang/Object;)Z");
653 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
655 CHECK(added, "");
656 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000657 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
659
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000660 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
661 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000662 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
664 }
665
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000666 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000667 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
669 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
670
671 WeakRef s(jni(), it->second);
672 streams_.erase(it);
673 if (!s.obj())
674 return;
675
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000676 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
677 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
679 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
680 }
681
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000682 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000683 ScopedLocalRefFrame local_ref_frame(jni());
684 jobject j_channel = jni()->NewObject(
685 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000686 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000687
688 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
689 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000690 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000691
692 // Channel is now owned by Java object, and will be freed from
693 // DataChannel.dispose(). Important that this be done _after_ the
694 // CallVoidMethod above as Java code might call back into native code and be
695 // surprised to see a refcount of 2.
696 int bumped_count = channel->AddRef();
697 CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
698
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000699 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
700 }
701
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000702 virtual void OnRenegotiationNeeded() OVERRIDE {
703 ScopedLocalRefFrame local_ref_frame(jni());
704 jmethodID m =
705 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
706 jni()->CallVoidMethod(*j_observer_global_, m);
707 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
708 }
709
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 void SetConstraints(ConstraintsWrapper* constraints) {
711 CHECK(!constraints_.get(), "constraints already set!");
712 constraints_.reset(constraints);
713 }
714
715 const ConstraintsWrapper* constraints() { return constraints_.get(); }
716
717 private:
718 JNIEnv* jni() {
719 return AttachCurrentThreadIfNeeded();
720 }
721
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000722 const ScopedGlobalRef<jobject> j_observer_global_;
723 const ScopedGlobalRef<jclass> j_observer_class_;
724 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000725 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000726 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000728 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000730 const ScopedGlobalRef<jclass> j_data_channel_class_;
731 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
733 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000734 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000735};
736
737// Wrapper for a Java MediaConstraints object. Copies all needed data so when
738// the constructor returns the Java object is no longer needed.
739class ConstraintsWrapper : public MediaConstraintsInterface {
740 public:
741 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
742 PopulateConstraintsFromJavaPairList(
743 jni, j_constraints, "mandatory", &mandatory_);
744 PopulateConstraintsFromJavaPairList(
745 jni, j_constraints, "optional", &optional_);
746 }
747
748 virtual ~ConstraintsWrapper() {}
749
750 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000751 virtual const Constraints& GetMandatory() const OVERRIDE {
752 return mandatory_;
753 }
754
755 virtual const Constraints& GetOptional() const OVERRIDE {
756 return optional_;
757 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758
759 private:
760 // Helper for translating a List<Pair<String, String>> to a Constraints.
761 static void PopulateConstraintsFromJavaPairList(
762 JNIEnv* jni, jobject j_constraints,
763 const char* field_name, Constraints* field) {
764 jfieldID j_id = GetFieldID(jni,
765 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
766 jobject j_list = GetObjectField(jni, j_constraints, j_id);
767 jmethodID j_iterator_id = GetMethodID(jni,
768 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
769 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
770 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
771 jmethodID j_has_next = GetMethodID(jni,
772 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
773 jmethodID j_next = GetMethodID(jni,
774 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
775 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
776 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
777 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
778 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
779 jmethodID get_key = GetMethodID(jni,
780 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
781 jstring j_key = reinterpret_cast<jstring>(
782 jni->CallObjectMethod(entry, get_key));
783 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
784 jmethodID get_value = GetMethodID(jni,
785 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
786 jstring j_value = reinterpret_cast<jstring>(
787 jni->CallObjectMethod(entry, get_value));
788 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
789 field->push_back(Constraint(JavaToStdString(jni, j_key),
790 JavaToStdString(jni, j_value)));
791 }
792 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
793 }
794
795 Constraints mandatory_;
796 Constraints optional_;
797};
798
799static jobject JavaSdpFromNativeSdp(
800 JNIEnv* jni, const SessionDescriptionInterface* desc) {
801 std::string sdp;
802 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
fischman@webrtc.org41776152014-01-09 00:31:17 +0000803 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804
805 jclass j_type_class = FindClass(
806 jni, "org/webrtc/SessionDescription$Type");
807 jmethodID j_type_from_canonical = GetStaticMethodID(
808 jni, j_type_class, "fromCanonicalForm",
809 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000810 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000812 j_type_class, j_type_from_canonical, j_type_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
814
815 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
816 jmethodID j_sdp_ctor = GetMethodID(
817 jni, j_sdp_class, "<init>",
818 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
819 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000820 j_sdp_class, j_sdp_ctor, j_type, j_description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 CHECK_EXCEPTION(jni, "error during NewObject");
822 return j_sdp;
823}
824
825template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
826class SdpObserverWrapper : public T {
827 public:
828 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
829 ConstraintsWrapper* constraints)
830 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000831 j_observer_global_(jni, j_observer),
832 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 }
834
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000835 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000837 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000839 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000840 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
841 jni()->CallVoidMethod(*j_observer_global_, m);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
843 }
844
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000845 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000847 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000849 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000851 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
852 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
854 }
855
856 protected:
857 // Common implementation for failure of Set & Create types, distinguished by
858 // |op| being "Set" or "Create".
859 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000860 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
861 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000862 jstring j_error_string = JavaStringFromStdString(jni(), error);
863 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
865 }
866
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 JNIEnv* jni() {
868 return AttachCurrentThreadIfNeeded();
869 }
870
fischman@webrtc.org41776152014-01-09 00:31:17 +0000871 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000872 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000873 const ScopedGlobalRef<jobject> j_observer_global_;
874 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875};
876
877class CreateSdpObserverWrapper
878 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
879 public:
880 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
881 ConstraintsWrapper* constraints)
882 : SdpObserverWrapper(jni, j_observer, constraints) {}
883
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000884 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000885 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886 SdpObserverWrapper::OnFailure(std::string("Create"), error);
887 }
888};
889
890class SetSdpObserverWrapper
891 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
892 public:
893 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
894 ConstraintsWrapper* constraints)
895 : SdpObserverWrapper(jni, j_observer, constraints) {}
896
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000897 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000898 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899 SdpObserverWrapper::OnFailure(std::string("Set"), error);
900 }
901};
902
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000903// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
904// and dispatching the callback from C++ back to Java.
905class DataChannelObserverWrapper : public DataChannelObserver {
906 public:
907 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
908 : j_observer_global_(jni, j_observer),
909 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
910 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
911 "onStateChange", "()V")),
912 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
913 "(Lorg/webrtc/DataChannel$Buffer;)V")),
914 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
915 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
916 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
917 }
918
919 virtual ~DataChannelObserverWrapper() {}
920
921 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000922 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000923 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
924 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
925 }
926
927 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000928 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000929 jobject byte_buffer =
930 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
931 buffer.data.length());
932 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
933 byte_buffer, buffer.binary);
934 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
935 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
936 }
937
938 private:
939 JNIEnv* jni() {
940 return AttachCurrentThreadIfNeeded();
941 }
942
943 const ScopedGlobalRef<jobject> j_observer_global_;
944 const ScopedGlobalRef<jclass> j_observer_class_;
945 const ScopedGlobalRef<jclass> j_buffer_class_;
946 const jmethodID j_on_state_change_mid_;
947 const jmethodID j_on_message_mid_;
948 const jmethodID j_buffer_ctor_;
949};
950
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
952// dispatching the callback from C++ back to Java.
953class StatsObserverWrapper : public StatsObserver {
954 public:
955 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000956 : j_observer_global_(jni, j_observer),
957 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
958 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000959 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000960 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961 "(Ljava/lang/String;Ljava/lang/String;D"
962 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000963 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000964 jni, "org/webrtc/StatsReport$Value")),
965 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000966 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000967 "(Ljava/lang/String;Ljava/lang/String;)V")) {
968 }
969
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000970 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000971
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000972 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000973 ScopedLocalRefFrame local_ref_frame(jni());
974 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000975 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
976 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000977 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000978 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
979 }
980
981 private:
982 jobjectArray ReportsToJava(
983 JNIEnv* jni, const std::vector<StatsReport>& reports) {
984 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000985 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000987 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000989 jstring j_id = JavaStringFromStdString(jni, report.id);
990 jstring j_type = JavaStringFromStdString(jni, report.type);
991 jobjectArray j_values = ValuesToJava(jni, report.values);
992 jobject j_report = jni->NewObject(*j_stats_report_class_,
993 j_stats_report_ctor_,
994 j_id,
995 j_type,
996 report.timestamp,
997 j_values);
998 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000999 }
1000 return reports_array;
1001 }
1002
1003 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1004 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001005 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001006 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001007 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001008 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001009 jstring j_name = JavaStringFromStdString(jni, value.name);
1010 jstring j_value = JavaStringFromStdString(jni, value.value);
1011 jobject j_element_value =
1012 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1013 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001014 }
1015 return j_values;
1016 }
1017
1018 JNIEnv* jni() {
1019 return AttachCurrentThreadIfNeeded();
1020 }
1021
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001022 const ScopedGlobalRef<jobject> j_observer_global_;
1023 const ScopedGlobalRef<jclass> j_observer_class_;
1024 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001026 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001027 const jmethodID j_value_ctor_;
1028};
1029
1030// Adapter presenting a cricket::VideoRenderer as a
1031// webrtc::VideoRendererInterface.
1032class VideoRendererWrapper : public VideoRendererInterface {
1033 public:
1034 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1035 if (renderer)
1036 return new VideoRendererWrapper(renderer);
1037 return NULL;
1038 }
1039
1040 virtual ~VideoRendererWrapper() {}
1041
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001042 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001043 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001044 const bool kNotReserved = false; // What does this param mean??
1045 renderer_->SetSize(width, height, kNotReserved);
1046 }
1047
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001048 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001049 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001050 renderer_->RenderFrame(frame);
1051 }
1052
1053 private:
1054 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1055 : renderer_(renderer) {}
1056
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001057 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001058};
1059
1060// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1061// instance.
1062class JavaVideoRendererWrapper : public VideoRendererInterface {
1063 public:
1064 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001065 : j_callbacks_(jni, j_callbacks),
1066 j_set_size_id_(GetMethodID(
1067 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1068 j_render_frame_id_(GetMethodID(
1069 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1070 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1071 j_frame_class_(jni,
1072 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1073 j_frame_ctor_id_(GetMethodID(
1074 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1075 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076 CHECK_EXCEPTION(jni, "");
1077 }
1078
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001079 virtual ~JavaVideoRendererWrapper() {}
1080
1081 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001082 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001083 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1084 CHECK_EXCEPTION(jni(), "");
1085 }
1086
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001087 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001088 ScopedLocalRefFrame local_ref_frame(jni());
1089 jobject j_frame = CricketToJavaFrame(frame);
1090 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001091 CHECK_EXCEPTION(jni(), "");
1092 }
1093
1094 private:
1095 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1096 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001097 jintArray strides = jni()->NewIntArray(3);
1098 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001099 strides_array[0] = frame->GetYPitch();
1100 strides_array[1] = frame->GetUPitch();
1101 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001102 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1103 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1104 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001105 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001106 frame->GetYPitch() * frame->GetHeight());
1107 jobject u_buffer = jni()->NewDirectByteBuffer(
1108 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1109 jobject v_buffer = jni()->NewDirectByteBuffer(
1110 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1111 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1112 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1113 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001114 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001115 *j_frame_class_, j_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001116 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001117 }
1118
1119 JNIEnv* jni() {
1120 return AttachCurrentThreadIfNeeded();
1121 }
1122
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001123 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 jmethodID j_set_size_id_;
1125 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001126 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001128 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001129};
1130
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001131#ifdef ANDROID
1132// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1133// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1134// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001135
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001136// Arbitrary interval to poll the codec for new outputs.
1137enum { kMediaCodecPollMs = 10 };
1138
1139// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1140// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1141// HW-backed video encode. This C++ class is implemented as a very thin shim,
1142// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1143// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1144// thread, currently the libjingle Worker thread.
1145class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
1146 public talk_base::MessageHandler {
1147 public:
1148 virtual ~MediaCodecVideoEncoder();
1149 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1150
1151 // webrtc::VideoEncoder implementation. Everything trampolines to
1152 // |codec_thread_| for execution.
1153 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1154 int32_t /* number_of_cores */,
1155 uint32_t /* max_payload_size */) OVERRIDE;
1156 virtual int32_t Encode(
1157 const webrtc::I420VideoFrame& input_image,
1158 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1159 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1160 virtual int32_t RegisterEncodeCompleteCallback(
1161 webrtc::EncodedImageCallback* callback) OVERRIDE;
1162 virtual int32_t Release() OVERRIDE;
1163 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1164 int /* rtt */) OVERRIDE;
1165 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1166
1167 // talk_base::MessageHandler implementation.
1168 virtual void OnMessage(talk_base::Message* msg) OVERRIDE;
1169
1170 private:
1171 // CHECK-fail if not running on |codec_thread_|.
1172 void CheckOnCodecThread();
1173
1174 // Release() and InitEncode() in an attempt to restore the codec to an
1175 // operable state. Necessary after all manner of OMX-layer errors.
1176 void ResetCodec();
1177
1178 // Implementation of webrtc::VideoEncoder methods above, all running on the
1179 // codec thread exclusively.
1180 //
1181 // If width==0 then this is assumed to be a re-initialization and the
1182 // previously-current values are reused instead of the passed parameters
1183 // (makes it easier to reason about thread-safety).
1184 int32_t InitEncodeOnCodecThread(int width, int height, int kbps);
1185 int32_t EncodeOnCodecThread(
1186 const webrtc::I420VideoFrame& input_image,
1187 const std::vector<webrtc::VideoFrameType>* frame_types);
1188 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1189 webrtc::EncodedImageCallback* callback);
1190 int32_t ReleaseOnCodecThread();
1191 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1192
1193 // Reset parameters valid between InitEncode() & Release() (see below).
1194 void ResetParameters(JNIEnv* jni);
1195
1196 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1197 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1198 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1199 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1200 jlong GetOutputBufferInfoPresentationTimestampUs(
1201 JNIEnv* jni,
1202 jobject j_output_buffer_info);
1203
1204 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1205 // true on success.
1206 bool DeliverPendingOutputs(JNIEnv* jni);
1207
1208 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1209 // |codec_thread_| synchronously.
1210 webrtc::EncodedImageCallback* callback_;
1211
1212 // State that is constant for the lifetime of this object once the ctor
1213 // returns.
1214 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1215 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1216 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1217 jmethodID j_init_encode_method_;
1218 jmethodID j_dequeue_input_buffer_method_;
1219 jmethodID j_encode_method_;
1220 jmethodID j_release_method_;
1221 jmethodID j_set_rates_method_;
1222 jmethodID j_dequeue_output_buffer_method_;
1223 jmethodID j_release_output_buffer_method_;
1224 jfieldID j_info_index_field_;
1225 jfieldID j_info_buffer_field_;
1226 jfieldID j_info_is_key_frame_field_;
1227 jfieldID j_info_presentation_timestamp_us_field_;
1228
1229 // State that is valid only between InitEncode() and the next Release().
1230 // Touched only on codec_thread_ so no explicit synchronization necessary.
1231 int width_; // Frame width in pixels.
1232 int height_; // Frame height in pixels.
1233 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
1234 // Frame size in bytes fed to MediaCodec (stride==width, sliceHeight==height).
1235 int nv12_size_;
1236 // True only when between a callback_->Encoded() call return a positive value
1237 // and the next Encode() call being ignored.
1238 bool drop_next_input_frame_;
1239 // Global references; must be deleted in Release().
1240 std::vector<jobject> input_buffers_;
1241};
1242
1243enum { MSG_SET_RATES, MSG_POLL_FOR_READY_OUTPUTS, };
1244
1245MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1246 // We depend on ResetParameters() to ensure no more callbacks to us after we
1247 // are deleted, so assert it here.
1248 CHECK(width_ == 0, "Release() should have been called");
1249}
1250
1251MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1252 : callback_(NULL),
1253 codec_thread_(new Thread()),
1254 j_media_codec_video_encoder_class_(
1255 jni,
1256 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1257 j_media_codec_video_encoder_(
1258 jni,
1259 jni->NewObject(*j_media_codec_video_encoder_class_,
1260 GetMethodID(jni,
1261 *j_media_codec_video_encoder_class_,
1262 "<init>",
1263 "()V"))) {
1264 ScopedLocalRefFrame local_ref_frame(jni);
1265 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1266 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1267 // 2732 means that deadlocks abound. This class synchronously trampolines
1268 // to |codec_thread_|, so if anything else can be coming to _us_ from
1269 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1270 // in the bug, we have a problem. For now work around that with a dedicated
1271 // thread.
1272 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
1273 CHECK(codec_thread_->Start(), "Failed to start MediaCodecVideoEncoder");
1274
1275 ResetParameters(jni);
1276
1277 jclass j_output_buffer_info_class =
1278 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1279 j_init_encode_method_ = GetMethodID(jni,
1280 *j_media_codec_video_encoder_class_,
1281 "initEncode",
1282 "(III)[Ljava/nio/ByteBuffer;");
1283 j_dequeue_input_buffer_method_ = GetMethodID(
1284 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1285 j_encode_method_ = GetMethodID(
1286 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1287 j_release_method_ =
1288 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1289 j_set_rates_method_ = GetMethodID(
1290 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1291 j_dequeue_output_buffer_method_ =
1292 GetMethodID(jni,
1293 *j_media_codec_video_encoder_class_,
1294 "dequeueOutputBuffer",
1295 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1296 j_release_output_buffer_method_ = GetMethodID(
1297 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1298
1299 j_info_index_field_ =
1300 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1301 j_info_buffer_field_ = GetFieldID(
1302 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1303 j_info_is_key_frame_field_ =
1304 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1305 j_info_presentation_timestamp_us_field_ = GetFieldID(
1306 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
1307 CHECK_EXCEPTION(jni, "MediaCodecVideoEncoder ctor failed");
1308}
1309
1310int32_t MediaCodecVideoEncoder::InitEncode(
1311 const webrtc::VideoCodec* codec_settings,
1312 int32_t /* number_of_cores */,
1313 uint32_t /* max_payload_size */) {
1314 // Factory should guard against other codecs being used with us.
1315 CHECK(codec_settings->codecType == kVideoCodecVP8, "Unsupported codec");
1316
1317 return codec_thread_->Invoke<int32_t>(
1318 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1319 this,
1320 codec_settings->width,
1321 codec_settings->height,
1322 codec_settings->startBitrate));
1323}
1324
1325int32_t MediaCodecVideoEncoder::Encode(
1326 const webrtc::I420VideoFrame& frame,
1327 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1328 const std::vector<webrtc::VideoFrameType>* frame_types) {
1329 return codec_thread_->Invoke<int32_t>(Bind(
1330 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1331}
1332
1333int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1334 webrtc::EncodedImageCallback* callback) {
1335 return codec_thread_->Invoke<int32_t>(
1336 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1337 this,
1338 callback));
1339}
1340
1341int32_t MediaCodecVideoEncoder::Release() {
1342 return codec_thread_->Invoke<int32_t>(
1343 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1344}
1345
1346int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1347 int /* rtt */) {
1348 return WEBRTC_VIDEO_CODEC_OK;
1349}
1350
1351int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1352 uint32_t frame_rate) {
1353 return codec_thread_->Invoke<int32_t>(
1354 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1355 this,
1356 new_bit_rate,
1357 frame_rate));
1358}
1359
1360void MediaCodecVideoEncoder::OnMessage(talk_base::Message* msg) {
1361 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1362 ScopedLocalRefFrame local_ref_frame(jni);
1363
1364 // We only ever send one message to |this| directly (not through a Bind()'d
1365 // functor), so expect no ID/data.
1366 CHECK(!msg->message_id, "Unexpected message!");
1367 CHECK(!msg->pdata, "Unexpected message!");
1368 CheckOnCodecThread();
1369
1370 // It would be nice to recover from a failure here if one happened, but it's
1371 // unclear how to signal such a failure to the app, so instead we stay silent
1372 // about it and let the next app-called API method reveal the borkedness.
1373 DeliverPendingOutputs(jni);
1374 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1375}
1376
1377void MediaCodecVideoEncoder::CheckOnCodecThread() {
1378 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread(),
1379 "Running on wrong thread!");
1380}
1381
1382void MediaCodecVideoEncoder::ResetCodec() {
1383 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1384 codec_thread_->Invoke<int32_t>(Bind(
1385 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0)) !=
1386 WEBRTC_VIDEO_CODEC_OK) {
1387 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1388 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1389 // https://code.google.com/p/webrtc/issues/detail?id=2920
1390 }
1391}
1392
1393int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
1394 int width, int height, int kbps) {
1395 CheckOnCodecThread();
1396 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1397 ScopedLocalRefFrame local_ref_frame(jni);
1398
1399 if (width == 0) {
1400 width = width_;
1401 height = height_;
1402 kbps = last_set_bitrate_kbps_;
1403 }
1404
1405 width_ = width;
1406 height_ = height;
1407 last_set_bitrate_kbps_ = kbps;
1408 nv12_size_ = width_ * height_ * 3 / 2;
1409 // We enforce no extra stride/padding in the format creation step.
1410 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1411 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1412 j_init_encode_method_,
1413 width_,
1414 height_,
1415 kbps));
1416 CHECK_EXCEPTION(jni, "");
1417 if (IsNull(jni, input_buffers))
1418 return WEBRTC_VIDEO_CODEC_ERROR;
1419
1420 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1421 CHECK(input_buffers_.empty(), "Unexpected double InitEncode without Release");
1422 input_buffers_.resize(num_input_buffers);
1423 for (size_t i = 0; i < num_input_buffers; ++i) {
1424 input_buffers_[i] =
1425 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
1426 int64 nv12_buffer_capacity =
1427 jni->GetDirectBufferCapacity(input_buffers_[i]);
1428 CHECK_EXCEPTION(jni, "");
1429 CHECK(nv12_buffer_capacity >= nv12_size_, "Insufficient capacity");
1430 }
1431 CHECK_EXCEPTION(jni, "");
1432
1433 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1434 return WEBRTC_VIDEO_CODEC_OK;
1435}
1436
1437int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1438 const webrtc::I420VideoFrame& frame,
1439 const std::vector<webrtc::VideoFrameType>* frame_types) {
1440 CheckOnCodecThread();
1441 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1442 ScopedLocalRefFrame local_ref_frame(jni);
1443
1444 if (!DeliverPendingOutputs(jni)) {
1445 ResetCodec();
1446 // Continue as if everything's fine.
1447 }
1448
1449 if (drop_next_input_frame_) {
1450 drop_next_input_frame_ = false;
1451 return WEBRTC_VIDEO_CODEC_OK;
1452 }
1453
1454 CHECK(frame_types->size() == 1, "Unexpected stream count");
1455 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1456
1457 CHECK(frame.width() == width_, "Unexpected resolution change");
1458 CHECK(frame.height() == height_, "Unexpected resolution change");
1459
1460 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1461 j_dequeue_input_buffer_method_);
1462 CHECK_EXCEPTION(jni, "");
1463 if (j_input_buffer_index == -1)
1464 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
1465 if (j_input_buffer_index == -2) {
1466 ResetCodec();
1467 return WEBRTC_VIDEO_CODEC_ERROR;
1468 }
1469
1470 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
1471 uint8* nv12_buffer =
1472 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
1473 CHECK_EXCEPTION(jni, "");
1474 CHECK(nv12_buffer, "Indirect buffer??");
1475 CHECK(!libyuv::I420ToNV12(
1476 frame.buffer(webrtc::kYPlane),
1477 frame.stride(webrtc::kYPlane),
1478 frame.buffer(webrtc::kUPlane),
1479 frame.stride(webrtc::kUPlane),
1480 frame.buffer(webrtc::kVPlane),
1481 frame.stride(webrtc::kVPlane),
1482 nv12_buffer,
1483 frame.width(),
1484 nv12_buffer + frame.stride(webrtc::kYPlane) * frame.height(),
1485 frame.width(),
1486 frame.width(),
1487 frame.height()),
1488 "I420ToNV12 failed");
1489 jlong timestamp_us = frame.render_time_ms() * 1000;
1490 int64_t start = talk_base::Time();
1491 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1492 j_encode_method_,
1493 key_frame,
1494 j_input_buffer_index,
1495 nv12_size_,
1496 timestamp_us);
1497 CHECK_EXCEPTION(jni, "");
1498 if (!encode_status || !DeliverPendingOutputs(jni)) {
1499 ResetCodec();
1500 return WEBRTC_VIDEO_CODEC_ERROR;
1501 }
1502
1503 return WEBRTC_VIDEO_CODEC_OK;
1504}
1505
1506int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1507 webrtc::EncodedImageCallback* callback) {
1508 CheckOnCodecThread();
1509 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1510 ScopedLocalRefFrame local_ref_frame(jni);
1511 callback_ = callback;
1512 return WEBRTC_VIDEO_CODEC_OK;
1513}
1514
1515int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
1516 CheckOnCodecThread();
1517 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1518 ScopedLocalRefFrame local_ref_frame(jni);
1519 for (size_t i = 0; i < input_buffers_.size(); ++i)
1520 jni->DeleteGlobalRef(input_buffers_[i]);
1521 input_buffers_.clear();
1522 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1523 ResetParameters(jni);
1524 CHECK_EXCEPTION(jni, "");
1525 return WEBRTC_VIDEO_CODEC_OK;
1526}
1527
1528int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1529 uint32_t frame_rate) {
1530 CheckOnCodecThread();
1531 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1532 ScopedLocalRefFrame local_ref_frame(jni);
1533 last_set_bitrate_kbps_ = new_bit_rate;
1534 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1535 j_set_rates_method_,
1536 new_bit_rate,
1537 frame_rate);
1538 CHECK_EXCEPTION(jni, "");
1539 if (!ret) {
1540 ResetCodec();
1541 return WEBRTC_VIDEO_CODEC_ERROR;
1542 }
1543 return WEBRTC_VIDEO_CODEC_OK;
1544}
1545
1546void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
1547 talk_base::MessageQueueManager::Clear(this);
1548 width_ = 0;
1549 height_ = 0;
1550 nv12_size_ = 0;
1551 drop_next_input_frame_ = false;
1552 CHECK(input_buffers_.empty(),
1553 "ResetParameters called while holding input_buffers_!");
1554}
1555
1556int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1557 JNIEnv* jni,
1558 jobject j_output_buffer_info) {
1559 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1560}
1561
1562jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1563 JNIEnv* jni,
1564 jobject j_output_buffer_info) {
1565 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1566}
1567
1568bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1569 JNIEnv* jni,
1570 jobject j_output_buffer_info) {
1571 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1572}
1573
1574jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1575 JNIEnv* jni,
1576 jobject j_output_buffer_info) {
1577 return GetLongField(
1578 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1579}
1580
1581bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1582 while (true) {
1583 jobject j_output_buffer_info = jni->CallObjectMethod(
1584 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
1585 CHECK_EXCEPTION(jni, "");
1586 if (IsNull(jni, j_output_buffer_info))
1587 break;
1588
1589 int output_buffer_index =
1590 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1591 if (output_buffer_index == -1) {
1592 ResetCodec();
1593 return false;
1594 }
1595
1596 jlong capture_time_ms =
1597 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1598 1000;
1599
1600 int32_t callback_status = 0;
1601 if (callback_) {
1602 jobject j_output_buffer =
1603 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1604 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1605 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1606 uint8* payload = reinterpret_cast<uint8_t*>(
1607 jni->GetDirectBufferAddress(j_output_buffer));
1608 CHECK_EXCEPTION(jni, "");
1609 scoped_ptr<webrtc::EncodedImage> image(
1610 new webrtc::EncodedImage(payload, payload_size, payload_size));
1611 image->_encodedWidth = width_;
1612 image->_encodedHeight = height_;
1613 // Convert capture time to 90 kHz RTP timestamp.
1614 image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
1615 image->capture_time_ms_ = capture_time_ms;
1616 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1617 image->_completeFrame = true;
1618
1619 webrtc::CodecSpecificInfo info;
1620 memset(&info, 0, sizeof(info));
1621 info.codecType = kVideoCodecVP8;
1622 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1623 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1624 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1625
1626 // Generate a header describing a single fragment.
1627 webrtc::RTPFragmentationHeader header;
1628 memset(&header, 0, sizeof(header));
1629 header.VerifyAndAllocateFragmentationHeader(1);
1630 header.fragmentationOffset[0] = 0;
1631 header.fragmentationLength[0] = image->_length;
1632 header.fragmentationPlType[0] = 0;
1633 header.fragmentationTimeDiff[0] = 0;
1634
1635 callback_status = callback_->Encoded(*image, &info, &header);
1636 }
1637
1638 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1639 j_release_output_buffer_method_,
1640 output_buffer_index);
1641 CHECK_EXCEPTION(jni, "");
1642 if (!success) {
1643 ResetCodec();
1644 return false;
1645 }
1646
1647 if (callback_status > 0)
1648 drop_next_input_frame_ = true;
1649 // Theoretically could handle callback_status<0 here, but unclear what that
1650 // would mean for us.
1651 }
1652
1653 return true;
1654}
1655
1656// Simplest-possible implementation of an encoder factory, churns out
1657// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1658class MediaCodecVideoEncoderFactory
1659 : public cricket::WebRtcVideoEncoderFactory {
1660 public:
1661 MediaCodecVideoEncoderFactory();
1662 virtual ~MediaCodecVideoEncoderFactory();
1663
1664 // WebRtcVideoEncoderFactory implementation.
1665 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1666 OVERRIDE;
1667 virtual void AddObserver(Observer* observer) OVERRIDE;
1668 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1669 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1670 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1671
1672 private:
1673 // Empty if platform support is lacking, const after ctor returns.
1674 std::vector<VideoCodec> supported_codecs_;
1675};
1676
1677MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1678 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1679 ScopedLocalRefFrame local_ref_frame(jni);
1680 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1681 bool is_platform_supported = jni->CallStaticBooleanMethod(
1682 j_encoder_class,
1683 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
1684 CHECK_EXCEPTION(jni, "");
1685 if (!is_platform_supported)
1686 return;
1687
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001688 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1689 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1690 // reasonable defaults.
1691 supported_codecs_.push_back(
1692 VideoCodec(kVideoCodecVP8, "VP8", 1920, 1088, 30));
1693}
1694
1695MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1696
1697webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1698 webrtc::VideoCodecType type) {
1699 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1700 return NULL;
1701 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1702}
1703
1704// Since the available codec list is never going to change, we ignore the
1705// Observer-related interface here.
1706void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1707void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1708
1709const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1710MediaCodecVideoEncoderFactory::codecs() const {
1711 return supported_codecs_;
1712}
1713
1714void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1715 webrtc::VideoEncoder* encoder) {
1716 delete encoder;
1717}
1718
1719#endif // ANDROID
1720
1721} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001722
1723// Convenience macro defining JNI-accessible methods in the org.webrtc package.
1724// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1725#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1726 Java_org_webrtc_##name
1727
1728extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1729 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1730 g_jvm = jvm;
1731 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1732
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00001733 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey), "pthread_once");
1734
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001735 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1736
1737 JNIEnv* jni;
1738 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1739 return -1;
1740 g_class_reference_holder = new ClassReferenceHolder(jni);
1741
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001742 return JNI_VERSION_1_6;
1743}
1744
1745extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001746 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747 delete g_class_reference_holder;
1748 g_class_reference_holder = NULL;
1749 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00001750 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001751}
1752
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001753static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001754 jfieldID native_dc_id = GetFieldID(jni,
1755 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1756 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001757 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001758}
1759
1760JOW(jlong, DataChannel_registerObserverNative)(
1761 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001762 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001763 new DataChannelObserverWrapper(jni, j_observer));
1764 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00001765 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001766}
1767
1768JOW(void, DataChannel_unregisterObserverNative)(
1769 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1770 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1771 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1772}
1773
1774JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1775 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1776}
1777
1778JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1779 return JavaEnumFromIndex(
1780 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1781}
1782
1783JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1784 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1785 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1786 "buffered_amount overflowed jlong!");
1787 return static_cast<jlong>(buffered_amount);
1788}
1789
1790JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1791 ExtractNativeDC(jni, j_dc)->Close();
1792}
1793
1794JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1795 jbyteArray data, jboolean binary) {
1796 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1797 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1798 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1799 binary));
1800 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1801 return ret;
1802}
1803
1804JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001805 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001806}
1807
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001808JOW(void, Logging_nativeEnableTracing)(
1809 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1810 jint nativeSeverity) {
1811 std::string path = JavaToStdString(jni, j_path);
1812 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00001813 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00001814#ifdef ANDROID
1815 if (path != "logcat:") {
1816#endif
1817 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1818 "SetTraceFile failed");
1819#ifdef ANDROID
1820 } else {
1821 // Intentionally leak this to avoid needing to reason about its lifecycle.
1822 // It keeps no state and functions only as a dispatch point.
1823 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1824 }
1825#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001826 }
1827 talk_base::LogMessage::LogToDebug(nativeSeverity);
1828}
1829
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001830JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001831 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001832}
1833
1834JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1835 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1836 delete p;
1837}
1838
1839JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001840 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001841}
1842
1843JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1844 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1845}
1846
1847JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1848 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1849}
1850
1851JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001852 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001853}
1854
1855JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1856 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001857 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001858 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001859}
1860
1861JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1862 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001863 return reinterpret_cast<MediaStreamInterface*>(pointer)
1864 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001865}
1866
1867JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1868 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001869 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001870 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001871}
1872
1873JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1874 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001875 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001876 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001877}
1878
1879JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1880 return JavaStringFromStdString(
1881 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1882}
1883
1884JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001885 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001886}
1887
1888JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1889 JNIEnv * jni, jclass, jobject j_observer) {
1890 return (jlong)new PCOJava(jni, j_observer);
1891}
1892
1893#ifdef ANDROID
1894JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001895 JNIEnv* jni, jclass, jobject context,
1896 jboolean initialize_audio, jboolean initialize_video) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001897 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1898 bool failure = false;
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001899 if (initialize_video)
fischman@webrtc.org95127192014-06-06 18:40:44 +00001900 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00001901 if (initialize_audio)
1902 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001903 return !failure;
1904}
1905#endif // ANDROID
1906
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001907// Helper struct for working around the fact that CreatePeerConnectionFactory()
1908// comes in two flavors: either entirely automagical (constructing its own
1909// threads and deleting them on teardown, but no external codec factory support)
1910// or entirely manual (requires caller to delete threads after factory
1911// teardown). This struct takes ownership of its ctor's arguments to present a
1912// single thing for Java to hold and eventually free.
1913class OwnedFactoryAndThreads {
1914 public:
1915 OwnedFactoryAndThreads(Thread* worker_thread,
1916 Thread* signaling_thread,
1917 PeerConnectionFactoryInterface* factory)
1918 : worker_thread_(worker_thread),
1919 signaling_thread_(signaling_thread),
1920 factory_(factory) {}
1921
1922 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
1923
1924 PeerConnectionFactoryInterface* factory() { return factory_; }
1925
1926 private:
1927 const scoped_ptr<Thread> worker_thread_;
1928 const scoped_ptr<Thread> signaling_thread_;
1929 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
1930};
1931
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001932JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1933 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00001934 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
1935 // ThreadManager only WrapCurrentThread()s the thread where it is first
1936 // created. Since the semantics around when auto-wrapping happens in
1937 // talk/base/ are convoluted, we simply wrap here to avoid having to think
1938 // about ramifications of auto-wrapping there.
1939 talk_base::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001940 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001941 Thread* worker_thread = new Thread();
1942 worker_thread->SetName("worker_thread", NULL);
1943 Thread* signaling_thread = new Thread();
1944 signaling_thread->SetName("signaling_thread", NULL);
1945 CHECK(worker_thread->Start() && signaling_thread->Start(),
1946 "Failed to start threads");
1947 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
1948#ifdef ANDROID
1949 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
1950#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001951 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001952 webrtc::CreatePeerConnectionFactory(worker_thread,
1953 signaling_thread,
1954 NULL,
1955 encoder_factory.release(),
1956 NULL));
1957 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
1958 worker_thread, signaling_thread, factory.release());
1959 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001960}
1961
1962JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001963 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001964 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965}
1966
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001967static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
1968 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
1969}
1970
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1972 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1973 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001974 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001975 talk_base::scoped_refptr<MediaStreamInterface> stream(
1976 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1977 return (jlong)stream.release();
1978}
1979
1980JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1981 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1982 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001983 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001984 new ConstraintsWrapper(jni, j_constraints));
1985 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001986 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001987 talk_base::scoped_refptr<VideoSourceInterface> source(
1988 factory->CreateVideoSource(
1989 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1990 constraints.get()));
1991 return (jlong)source.release();
1992}
1993
1994JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1995 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1996 jlong native_source) {
1997 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001998 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001999 talk_base::scoped_refptr<VideoTrackInterface> track(
2000 factory->CreateVideoTrack(
2001 JavaToStdString(jni, id),
2002 reinterpret_cast<VideoSourceInterface*>(native_source)));
2003 return (jlong)track.release();
2004}
2005
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002006JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2007 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2008 scoped_ptr<ConstraintsWrapper> constraints(
2009 new ConstraintsWrapper(jni, j_constraints));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002010 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002011 factoryFromJava(native_factory));
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002012 talk_base::scoped_refptr<AudioSourceInterface> source(
2013 factory->CreateAudioSource(constraints.get()));
2014 return (jlong)source.release();
2015}
2016
2017JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2018 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2019 jlong native_source) {
2020 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
2021 factoryFromJava(native_factory));
2022 talk_base::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
2023 JavaToStdString(jni, id),
2024 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025 return (jlong)track.release();
2026}
2027
2028static void JavaIceServersToJsepIceServers(
2029 JNIEnv* jni, jobject j_ice_servers,
2030 PeerConnectionInterface::IceServers* ice_servers) {
2031 jclass list_class = GetObjectClass(jni, j_ice_servers);
2032 jmethodID iterator_id = GetMethodID(
2033 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2034 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
2035 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2036 jmethodID iterator_has_next = GetMethodID(
2037 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2038 jmethodID iterator_next = GetMethodID(
2039 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2040 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
2041 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2042 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
2043 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2044 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2045 jfieldID j_ice_server_uri_id =
2046 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2047 jfieldID j_ice_server_username_id =
2048 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2049 jfieldID j_ice_server_password_id =
2050 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2051 jstring uri = reinterpret_cast<jstring>(
2052 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2053 jstring username = reinterpret_cast<jstring>(
2054 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2055 jstring password = reinterpret_cast<jstring>(
2056 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2057 PeerConnectionInterface::IceServer server;
2058 server.uri = JavaToStdString(jni, uri);
2059 server.username = JavaToStdString(jni, username);
2060 server.password = JavaToStdString(jni, password);
2061 ice_servers->push_back(server);
2062 }
2063 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2064}
2065
2066JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2067 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2068 jobject j_constraints, jlong observer_p) {
2069 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002070 reinterpret_cast<PeerConnectionFactoryInterface*>(
2071 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002072 PeerConnectionInterface::IceServers servers;
2073 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2074 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2075 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
2076 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002077 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002078 return (jlong)pc.release();
2079}
2080
2081static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
2082 JNIEnv* jni, jobject j_pc) {
2083 jfieldID native_pc_id = GetFieldID(jni,
2084 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2085 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
2086 return talk_base::scoped_refptr<PeerConnectionInterface>(
2087 reinterpret_cast<PeerConnectionInterface*>(j_p));
2088}
2089
2090JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2091 const SessionDescriptionInterface* sdp =
2092 ExtractNativePC(jni, j_pc)->local_description();
2093 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2094}
2095
2096JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2097 const SessionDescriptionInterface* sdp =
2098 ExtractNativePC(jni, j_pc)->remote_description();
2099 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2100}
2101
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002102JOW(jobject, PeerConnection_createDataChannel)(
2103 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2104 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
2105 talk_base::scoped_refptr<DataChannelInterface> channel(
2106 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2107 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002108 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2109 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2110 // 32-bit parameter.
2111 jlong nativeChannelPtr = jlongFromPointer(channel.get());
2112 CHECK(nativeChannelPtr, "Failed to create DataChannel");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002113 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2114 jmethodID j_data_channel_ctor = GetMethodID(
2115 jni, j_data_channel_class, "<init>", "(J)V");
2116 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002117 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002118 CHECK_EXCEPTION(jni, "error during NewObject");
2119 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002120 int bumped_count = channel->AddRef();
2121 CHECK(bumped_count == 2, "Unexpected refcount");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002122 return j_channel;
2123}
2124
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002125JOW(void, PeerConnection_createOffer)(
2126 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2127 ConstraintsWrapper* constraints =
2128 new ConstraintsWrapper(jni, j_constraints);
2129 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2130 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2131 jni, j_observer, constraints));
2132 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2133}
2134
2135JOW(void, PeerConnection_createAnswer)(
2136 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2137 ConstraintsWrapper* constraints =
2138 new ConstraintsWrapper(jni, j_constraints);
2139 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2140 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2141 jni, j_observer, constraints));
2142 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2143}
2144
2145// Helper to create a SessionDescriptionInterface from a SessionDescription.
2146static SessionDescriptionInterface* JavaSdpToNativeSdp(
2147 JNIEnv* jni, jobject j_sdp) {
2148 jfieldID j_type_id = GetFieldID(
2149 jni, GetObjectClass(jni, j_sdp), "type",
2150 "Lorg/webrtc/SessionDescription$Type;");
2151 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2152 jmethodID j_canonical_form_id = GetMethodID(
2153 jni, GetObjectClass(jni, j_type), "canonicalForm",
2154 "()Ljava/lang/String;");
2155 jstring j_type_string = (jstring)jni->CallObjectMethod(
2156 j_type, j_canonical_form_id);
2157 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2158 std::string std_type = JavaToStdString(jni, j_type_string);
2159
2160 jfieldID j_description_id = GetFieldID(
2161 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2162 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2163 std::string std_description = JavaToStdString(jni, j_description);
2164
2165 return webrtc::CreateSessionDescription(
2166 std_type, std_description, NULL);
2167}
2168
2169JOW(void, PeerConnection_setLocalDescription)(
2170 JNIEnv* jni, jobject j_pc,
2171 jobject j_observer, jobject j_sdp) {
2172 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2173 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2174 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2175 ExtractNativePC(jni, j_pc)->SetLocalDescription(
2176 observer, JavaSdpToNativeSdp(jni, j_sdp));
2177}
2178
2179JOW(void, PeerConnection_setRemoteDescription)(
2180 JNIEnv* jni, jobject j_pc,
2181 jobject j_observer, jobject j_sdp) {
2182 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2183 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2184 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2185 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2186 observer, JavaSdpToNativeSdp(jni, j_sdp));
2187}
2188
2189JOW(jboolean, PeerConnection_updateIce)(
2190 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2191 PeerConnectionInterface::IceServers ice_servers;
2192 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002193 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002194 new ConstraintsWrapper(jni, j_constraints));
2195 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2196}
2197
2198JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2199 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2200 jint j_sdp_mline_index, jstring j_candidate_sdp) {
2201 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2202 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002203 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2205 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2206}
2207
2208JOW(jboolean, PeerConnection_nativeAddLocalStream)(
2209 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002210 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002211 new ConstraintsWrapper(jni, j_constraints));
2212 return ExtractNativePC(jni, j_pc)->AddStream(
2213 reinterpret_cast<MediaStreamInterface*>(native_stream),
2214 constraints.get());
2215}
2216
2217JOW(void, PeerConnection_nativeRemoveLocalStream)(
2218 JNIEnv* jni, jobject j_pc, jlong native_stream) {
2219 ExtractNativePC(jni, j_pc)->RemoveStream(
2220 reinterpret_cast<MediaStreamInterface*>(native_stream));
2221}
2222
2223JOW(bool, PeerConnection_nativeGetStats)(
2224 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
2225 talk_base::scoped_refptr<StatsObserverWrapper> observer(
2226 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
2227 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00002228 observer,
2229 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
2230 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002231}
2232
2233JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2234 PeerConnectionInterface::SignalingState state =
2235 ExtractNativePC(jni, j_pc)->signaling_state();
2236 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2237}
2238
2239JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2240 PeerConnectionInterface::IceConnectionState state =
2241 ExtractNativePC(jni, j_pc)->ice_connection_state();
2242 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2243}
2244
2245JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
2246 PeerConnectionInterface::IceGatheringState state =
2247 ExtractNativePC(jni, j_pc)->ice_gathering_state();
2248 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
2249}
2250
2251JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2252 ExtractNativePC(jni, j_pc)->Close();
2253 return;
2254}
2255
2256JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
2257 talk_base::scoped_refptr<MediaSourceInterface> p(
2258 reinterpret_cast<MediaSourceInterface*>(j_p));
2259 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2260}
2261
2262JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
2263 JNIEnv* jni, jclass, jstring j_device_name) {
2264 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002265 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002266 cricket::DeviceManagerFactory::Create());
2267 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
2268 cricket::Device device;
2269 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002270 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002271 return 0;
2272 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002273 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002274 device_manager->CreateVideoCapturer(device));
2275 return (jlong)capturer.release();
2276}
2277
2278JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2279 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002280 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2281 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002282 return (jlong)renderer.release();
2283}
2284
2285JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2286 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002287 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002288 new JavaVideoRendererWrapper(jni, j_callbacks));
2289 return (jlong)renderer.release();
2290}
2291
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002292JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2293 cricket::VideoCapturer* capturer =
2294 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002295 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002296 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2297 capturer->Stop();
2298 return jlongFromPointer(format.release());
2299}
2300
2301JOW(void, VideoSource_restart)(
2302 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002303 CHECK(j_p_source, "");
2304 CHECK(j_p_format, "");
2305 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002306 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2307 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2308 StartCapturing(cricket::VideoFormat(*format));
2309}
2310
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00002311JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002312 JNIEnv* jni, jclass, jlong j_p) {
2313 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2314}
2315
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002316JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002317 return JavaStringFromStdString(
2318 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002319}
2320
2321JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002322 return JavaStringFromStdString(
2323 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002324}
2325
2326JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002327 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002328}
2329
2330JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002331 return JavaEnumFromIndex(
2332 jni,
2333 "MediaStreamTrack$State",
2334 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002335}
2336
2337JOW(jboolean, MediaStreamTrack_nativeSetState)(
2338 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002339 MediaStreamTrackInterface::TrackState new_state =
2340 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002341 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2342 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002343}
2344
2345JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2346 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002347 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2348 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002349}
2350
2351JOW(void, VideoTrack_nativeAddRenderer)(
2352 JNIEnv* jni, jclass,
2353 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002354 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002355 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2356}
2357
2358JOW(void, VideoTrack_nativeRemoveRenderer)(
2359 JNIEnv* jni, jclass,
2360 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002361 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002362 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2363}