blob: 9b34fb596c276594ef03488db59b140170678518 [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>
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000060#include <sys/prctl.h>
61#include <sys/syscall.h>
fischman@webrtc.orgeb7def22013-12-09 21:34:30 +000062#include <unistd.h>
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000063#include <limits>
64#include <map>
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"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069#include "talk/media/base/videocapturer.h"
70#include "talk/media/base/videorenderer.h"
71#include "talk/media/devices/videorendererfactory.h"
72#include "talk/media/webrtc/webrtcvideocapturer.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000073#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000074#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000075#include "third_party/icu/source/common/unicode/unistr.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000076#include "third_party/libyuv/include/libyuv/convert.h"
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +000077#include "third_party/libyuv/include/libyuv/convert_from.h"
78#include "third_party/libyuv/include/libyuv/video_common.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000079#include "webrtc/base/bind.h"
80#include "webrtc/base/logging.h"
81#include "webrtc/base/messagequeue.h"
82#include "webrtc/base/ssladapter.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000083#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000084#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000085#include "webrtc/system_wrappers/interface/trace.h"
86#include "webrtc/video_engine/include/vie_base.h"
87#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000089#ifdef ANDROID
90#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000091using webrtc::CodecSpecificInfo;
92using webrtc::DecodedImageCallback;
93using webrtc::EncodedImage;
94using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000095using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000096using webrtc::RTPFragmentationHeader;
97using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000098#endif
99
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100using icu::UnicodeString;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000101using rtc::Bind;
102using rtc::Thread;
103using rtc::ThreadManager;
104using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105using webrtc::AudioSourceInterface;
106using webrtc::AudioTrackInterface;
107using webrtc::AudioTrackVector;
108using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000109using webrtc::DataBuffer;
110using webrtc::DataChannelInit;
111using webrtc::DataChannelInterface;
112using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113using webrtc::IceCandidateInterface;
114using webrtc::MediaConstraintsInterface;
115using webrtc::MediaSourceInterface;
116using webrtc::MediaStreamInterface;
117using webrtc::MediaStreamTrackInterface;
118using webrtc::PeerConnectionFactoryInterface;
119using webrtc::PeerConnectionInterface;
120using webrtc::PeerConnectionObserver;
121using webrtc::SessionDescriptionInterface;
122using webrtc::SetSessionDescriptionObserver;
123using webrtc::StatsObserver;
124using webrtc::StatsReport;
125using webrtc::VideoRendererInterface;
126using webrtc::VideoSourceInterface;
127using webrtc::VideoTrackInterface;
128using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000129using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000130
131// Abort the process if |x| is false, emitting |msg|.
132#define CHECK(x, msg) \
133 if (x) {} else { \
134 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
135 abort(); \
136 }
137// Abort the process if |jni| has a Java exception pending, emitting |msg|.
138#define CHECK_EXCEPTION(jni, msg) \
139 if (0) {} else { \
140 if (jni->ExceptionCheck()) { \
141 jni->ExceptionDescribe(); \
142 jni->ExceptionClear(); \
143 CHECK(0, msg); \
144 } \
145 }
146
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000147// Helper that calls ptr->Release() and logs a useful message if that didn't
148// actually delete *ptr because of extra refcounts.
149#define CHECK_RELEASE(ptr) \
150 do { \
151 int count = (ptr)->Release(); \
152 if (count != 0) { \
153 LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr) \
154 << ": " << count; \
155 } \
156 CHECK(!count, "Unexpected refcount"); \
157 } while (0)
158
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159namespace {
160
161static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
162
163static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000164// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
165// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
166// were attached by the JVM because of a Java->native call.
167static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000168
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000169// Return thread ID as a string.
170static std::string GetThreadId() {
171 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
172 CHECK(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)) <= sizeof(buf),
173 "Thread id is bigger than uint64??");
174 return std::string(buf);
175}
176
177// Return the current thread's name.
178static std::string GetThreadName() {
179 char name[17];
180 CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
181 name[16] = '\0';
182 return std::string(name);
183}
184
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000185// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
186static JNIEnv* GetEnv() {
187 void* env = NULL;
188 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
189 CHECK(((env != NULL) && (status == JNI_OK)) ||
190 ((env == NULL) && (status == JNI_EDETACHED)),
191 "Unexpected GetEnv return: " << status << ":" << env);
192 return reinterpret_cast<JNIEnv*>(env);
193}
194
195static void ThreadDestructor(void* prev_jni_ptr) {
196 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
197 // we were responsible for originally attaching the thread, so are responsible
198 // for detaching it now. However, because some JVM implementations (notably
199 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
200 // the JVMs accounting info for this thread may already be wiped out by the
201 // time this is called. Thus it may appear we are already detached even though
202 // it was our responsibility to detach! Oh well.
203 if (!GetEnv())
204 return;
205
206 CHECK(GetEnv() == prev_jni_ptr,
207 "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208 jint status = g_jvm->DetachCurrentThread();
209 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000210 CHECK(!GetEnv(), "Detaching was a successful no-op???");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211}
212
213static void CreateJNIPtrKey() {
214 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
215 "pthread_key_create");
216}
217
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000218// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000220 JNIEnv* jni = GetEnv();
221 if (jni)
222 return jni;
223 CHECK(!pthread_getspecific(g_jni_ptr), "TLS has a JNIEnv* but not attached?");
224
225 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
226 JavaVMAttachArgs args;
227 args.version = JNI_VERSION_1_6;
228 args.name = name;
229 args.group = NULL;
230 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000231#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000232 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000233#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000234 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000235#endif
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000236 CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
237 free(name);
238 CHECK(env, "AttachCurrentThread handed back NULL!");
239 jni = reinterpret_cast<JNIEnv*>(env);
240 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000241 return jni;
242}
243
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000244// Return a |jlong| that will correctly convert back to |ptr|. This is needed
245// because the alternative (of silently passing a 32-bit pointer to a vararg
246// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000247static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000248 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000249 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000250 // Going through intptr_t to be obvious about the definedness of the
251 // conversion from pointer to integral type. intptr_t to jlong is a standard
252 // widening by the COMPILE_ASSERT above.
253 jlong ret = reinterpret_cast<intptr_t>(ptr);
254 assert(reinterpret_cast<void*>(ret) == ptr);
255 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000256}
257
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258// Android's FindClass() is trickier than usual because the app-specific
259// ClassLoader is not consulted when there is no app-specific frame on the
260// stack. Consequently, we only look up classes once in JNI_OnLoad.
261// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
262class ClassReferenceHolder {
263 public:
264 explicit ClassReferenceHolder(JNIEnv* jni) {
265 LoadClass(jni, "java/nio/ByteBuffer");
266 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000267 LoadClass(jni, "org/webrtc/DataChannel");
268 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
269 LoadClass(jni, "org/webrtc/DataChannel$Init");
270 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 LoadClass(jni, "org/webrtc/IceCandidate");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000272#ifdef ANDROID
273 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
274 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000275 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000276#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000277 LoadClass(jni, "org/webrtc/MediaSource$State");
278 LoadClass(jni, "org/webrtc/MediaStream");
279 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
281 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000282 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 LoadClass(jni, "org/webrtc/SessionDescription");
284 LoadClass(jni, "org/webrtc/SessionDescription$Type");
285 LoadClass(jni, "org/webrtc/StatsReport");
286 LoadClass(jni, "org/webrtc/StatsReport$Value");
287 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
288 LoadClass(jni, "org/webrtc/VideoTrack");
289 }
290
291 ~ClassReferenceHolder() {
292 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
293 }
294
295 void FreeReferences(JNIEnv* jni) {
296 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
297 it != classes_.end(); ++it) {
298 jni->DeleteGlobalRef(it->second);
299 }
300 classes_.clear();
301 }
302
303 jclass GetClass(const std::string& name) {
304 std::map<std::string, jclass>::iterator it = classes_.find(name);
305 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
306 return it->second;
307 }
308
309 private:
310 void LoadClass(JNIEnv* jni, const std::string& name) {
311 jclass localRef = jni->FindClass(name.c_str());
312 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
313 CHECK(localRef, name);
314 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
315 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
316 CHECK(globalRef, name);
317 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
318 CHECK(inserted, "Duplicate class name: " << name);
319 }
320
321 std::map<std::string, jclass> classes_;
322};
323
324// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
325static ClassReferenceHolder* g_class_reference_holder = NULL;
326
327// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
328// object/class/method/field is non-null.
329jmethodID GetMethodID(
330 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
331 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
332 CHECK_EXCEPTION(jni,
333 "error during GetMethodID: " << name << ", " << signature);
334 CHECK(m, name << ", " << signature);
335 return m;
336}
337
338jmethodID GetStaticMethodID(
339 JNIEnv* jni, jclass c, const char* name, const char* signature) {
340 jmethodID m = jni->GetStaticMethodID(c, name, signature);
341 CHECK_EXCEPTION(jni,
342 "error during GetStaticMethodID: "
343 << name << ", " << signature);
344 CHECK(m, name << ", " << signature);
345 return m;
346}
347
348jfieldID GetFieldID(
349 JNIEnv* jni, jclass c, const char* name, const char* signature) {
350 jfieldID f = jni->GetFieldID(c, name, signature);
351 CHECK_EXCEPTION(jni, "error during GetFieldID");
352 CHECK(f, name << ", " << signature);
353 return f;
354}
355
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000356// Returns a global reference guaranteed to be valid for the lifetime of the
357// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000358jclass FindClass(JNIEnv* jni, const char* name) {
359 return g_class_reference_holder->GetClass(name);
360}
361
362jclass GetObjectClass(JNIEnv* jni, jobject object) {
363 jclass c = jni->GetObjectClass(object);
364 CHECK_EXCEPTION(jni, "error during GetObjectClass");
365 CHECK(c, "");
366 return c;
367}
368
369jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
370 jobject o = jni->GetObjectField(object, id);
371 CHECK_EXCEPTION(jni, "error during GetObjectField");
372 CHECK(o, "");
373 return o;
374}
375
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000376jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
377 return static_cast<jstring>(GetObjectField(jni, object, id));
378}
379
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000380jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
381 jlong l = jni->GetLongField(object, id);
382 CHECK_EXCEPTION(jni, "error during GetLongField");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000383 return l;
384}
385
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000386jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
387 jint i = jni->GetIntField(object, id);
388 CHECK_EXCEPTION(jni, "error during GetIntField");
389 return i;
390}
391
392bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
393 jboolean b = jni->GetBooleanField(object, id);
394 CHECK_EXCEPTION(jni, "error during GetBooleanField");
395 return b;
396}
397
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000398jobject NewGlobalRef(JNIEnv* jni, jobject o) {
399 jobject ret = jni->NewGlobalRef(o);
400 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
401 CHECK(ret, "");
402 return ret;
403}
404
405void DeleteGlobalRef(JNIEnv* jni, jobject o) {
406 jni->DeleteGlobalRef(o);
407 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
408}
409
410// Given a jweak reference, allocate a (strong) local reference scoped to the
411// lifetime of this object if the weak reference is still valid, or NULL
412// otherwise.
413class WeakRef {
414 public:
415 WeakRef(JNIEnv* jni, jweak ref)
416 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
417 CHECK_EXCEPTION(jni, "error during NewLocalRef");
418 }
419 ~WeakRef() {
420 if (obj_) {
421 jni_->DeleteLocalRef(obj_);
422 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
423 }
424 }
425 jobject obj() { return obj_; }
426
427 private:
428 JNIEnv* const jni_;
429 jobject const obj_;
430};
431
fischman@webrtc.org41776152014-01-09 00:31:17 +0000432// Scope Java local references to the lifetime of this object. Use in all C++
433// callbacks (i.e. entry points that don't originate in a Java callstack
434// through a "native" method call).
435class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000437 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
438 CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000440 ~ScopedLocalRefFrame() {
441 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000442 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000443
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 private:
445 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446};
447
448// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000449template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450class ScopedGlobalRef {
451 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000452 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000453 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454 ~ScopedGlobalRef() {
455 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
456 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000457 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458 return obj_;
459 }
460 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000461 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462};
463
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000464// Java references to "null" can only be distinguished as such in C++ by
465// creating a local reference, so this helper wraps that logic.
466static bool IsNull(JNIEnv* jni, jobject obj) {
467 ScopedLocalRefFrame local_ref_frame(jni);
468 return jni->NewLocalRef(obj) == NULL;
469}
470
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471// Return the (singleton) Java Enum object corresponding to |index|;
472// |state_class_fragment| is something like "MediaSource$State".
473jobject JavaEnumFromIndex(
474 JNIEnv* jni, const std::string& state_class_fragment, int index) {
475 std::string state_class_name = "org/webrtc/" + state_class_fragment;
476 jclass state_class = FindClass(jni, state_class_name.c_str());
477 jmethodID state_values_id = GetStaticMethodID(
478 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000479 jobjectArray state_values = static_cast<jobjectArray>(
480 jni->CallStaticObjectMethod(state_class, state_values_id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000482 jobject ret = jni->GetObjectArrayElement(state_values, index);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
484 return ret;
485}
486
487// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
488static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
489 UnicodeString ustr(UnicodeString::fromUTF8(native));
490 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
491 CHECK_EXCEPTION(jni, "error during NewString");
492 return jstr;
493}
494
495// Given a (UTF-16) jstring return a new UTF-8 native string.
496static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
497 const jchar* jchars = jni->GetStringChars(j_string, NULL);
498 CHECK_EXCEPTION(jni, "Error during GetStringChars");
499 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
500 CHECK_EXCEPTION(jni, "Error during GetStringLength");
501 jni->ReleaseStringChars(j_string, jchars);
502 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
503 std::string ret;
504 return ustr.toUTF8String(ret);
505}
506
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000507static DataChannelInit JavaDataChannelInitToNative(
508 JNIEnv* jni, jobject j_init) {
509 DataChannelInit init;
510
511 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
512 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
513 jfieldID max_retransmit_time_id =
514 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
515 jfieldID max_retransmits_id =
516 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
517 jfieldID protocol_id =
518 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
519 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
520 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
521
522 init.ordered = GetBooleanField(jni, j_init, ordered_id);
523 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
524 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
525 init.protocol = JavaToStdString(
526 jni, GetStringField(jni, j_init, protocol_id));
527 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
528 init.id = GetIntField(jni, j_init, id_id);
529
530 return init;
531}
532
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533class ConstraintsWrapper;
534
535// Adapter between the C++ PeerConnectionObserver interface and the Java
536// PeerConnection.Observer interface. Wraps an instance of the Java interface
537// and dispatches C++ callbacks to Java.
538class PCOJava : public PeerConnectionObserver {
539 public:
540 PCOJava(JNIEnv* jni, jobject j_observer)
541 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000542 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
543 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
544 j_media_stream_ctor_(GetMethodID(
545 jni, *j_media_stream_class_, "<init>", "(J)V")),
546 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000548 jni, *j_audio_track_class_, "<init>", "(J)V")),
549 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
550 j_video_track_ctor_(GetMethodID(
551 jni, *j_video_track_class_, "<init>", "(J)V")),
552 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
553 j_data_channel_ctor_(GetMethodID(
554 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 }
556
557 virtual ~PCOJava() {}
558
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000559 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000560 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 std::string sdp;
562 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
563 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
564 jmethodID ctor = GetMethodID(jni(), candidate_class,
565 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000566 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
567 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
568 jobject j_candidate = jni()->NewObject(
569 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000571 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000573 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
575 }
576
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000577 virtual void OnError() OVERRIDE {
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000578 ScopedLocalRefFrame local_ref_frame(jni());
579 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 jni()->CallVoidMethod(*j_observer_global_, m);
581 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
582 }
583
584 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000585 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000586 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000588 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000590 jobject new_state_enum =
591 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
592 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
594 }
595
596 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000597 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000598 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000600 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000602 jobject new_state_enum = JavaEnumFromIndex(
603 jni(), "PeerConnection$IceConnectionState", new_state);
604 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
606 }
607
608 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000609 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000610 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000611 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000612 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000614 jobject new_state_enum = JavaEnumFromIndex(
615 jni(), "PeerConnection$IceGatheringState", new_state);
616 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
618 }
619
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000620 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000621 ScopedLocalRefFrame local_ref_frame(jni());
622 jobject j_stream = jni()->NewObject(
623 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 CHECK_EXCEPTION(jni(), "error during NewObject");
625
626 AudioTrackVector audio_tracks = stream->GetAudioTracks();
627 for (size_t i = 0; i < audio_tracks.size(); ++i) {
628 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000629 jstring id = JavaStringFromStdString(jni(), track->id());
630 jobject j_track = jni()->NewObject(
631 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000633 jfieldID audio_tracks_id = GetFieldID(jni(),
634 *j_media_stream_class_,
635 "audioTracks",
636 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000637 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000639 GetObjectClass(jni(), audio_tracks),
640 "add",
641 "(Ljava/lang/Object;)Z");
642 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
644 CHECK(added, "");
645 }
646
647 VideoTrackVector video_tracks = stream->GetVideoTracks();
648 for (size_t i = 0; i < video_tracks.size(); ++i) {
649 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000650 jstring id = JavaStringFromStdString(jni(), track->id());
651 jobject j_track = jni()->NewObject(
652 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000654 jfieldID video_tracks_id = GetFieldID(jni(),
655 *j_media_stream_class_,
656 "videoTracks",
657 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000658 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000660 GetObjectClass(jni(), video_tracks),
661 "add",
662 "(Ljava/lang/Object;)Z");
663 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
665 CHECK(added, "");
666 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000667 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
669
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000670 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
671 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000672 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
674 }
675
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000676 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000677 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
679 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
680
681 WeakRef s(jni(), it->second);
682 streams_.erase(it);
683 if (!s.obj())
684 return;
685
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000686 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
687 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
689 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
690 }
691
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000692 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000693 ScopedLocalRefFrame local_ref_frame(jni());
694 jobject j_channel = jni()->NewObject(
695 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000696 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000697
698 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
699 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000700 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000701
702 // Channel is now owned by Java object, and will be freed from
703 // DataChannel.dispose(). Important that this be done _after_ the
704 // CallVoidMethod above as Java code might call back into native code and be
705 // surprised to see a refcount of 2.
706 int bumped_count = channel->AddRef();
707 CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
708
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000709 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
710 }
711
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000712 virtual void OnRenegotiationNeeded() OVERRIDE {
713 ScopedLocalRefFrame local_ref_frame(jni());
714 jmethodID m =
715 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
716 jni()->CallVoidMethod(*j_observer_global_, m);
717 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
718 }
719
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 void SetConstraints(ConstraintsWrapper* constraints) {
721 CHECK(!constraints_.get(), "constraints already set!");
722 constraints_.reset(constraints);
723 }
724
725 const ConstraintsWrapper* constraints() { return constraints_.get(); }
726
727 private:
728 JNIEnv* jni() {
729 return AttachCurrentThreadIfNeeded();
730 }
731
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000732 const ScopedGlobalRef<jobject> j_observer_global_;
733 const ScopedGlobalRef<jclass> j_observer_class_;
734 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000735 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000736 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000738 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000740 const ScopedGlobalRef<jclass> j_data_channel_class_;
741 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
743 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000744 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745};
746
747// Wrapper for a Java MediaConstraints object. Copies all needed data so when
748// the constructor returns the Java object is no longer needed.
749class ConstraintsWrapper : public MediaConstraintsInterface {
750 public:
751 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
752 PopulateConstraintsFromJavaPairList(
753 jni, j_constraints, "mandatory", &mandatory_);
754 PopulateConstraintsFromJavaPairList(
755 jni, j_constraints, "optional", &optional_);
756 }
757
758 virtual ~ConstraintsWrapper() {}
759
760 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000761 virtual const Constraints& GetMandatory() const OVERRIDE {
762 return mandatory_;
763 }
764
765 virtual const Constraints& GetOptional() const OVERRIDE {
766 return optional_;
767 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768
769 private:
770 // Helper for translating a List<Pair<String, String>> to a Constraints.
771 static void PopulateConstraintsFromJavaPairList(
772 JNIEnv* jni, jobject j_constraints,
773 const char* field_name, Constraints* field) {
774 jfieldID j_id = GetFieldID(jni,
775 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
776 jobject j_list = GetObjectField(jni, j_constraints, j_id);
777 jmethodID j_iterator_id = GetMethodID(jni,
778 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
779 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
780 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
781 jmethodID j_has_next = GetMethodID(jni,
782 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
783 jmethodID j_next = GetMethodID(jni,
784 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
785 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
786 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
787 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
788 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
789 jmethodID get_key = GetMethodID(jni,
790 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
791 jstring j_key = reinterpret_cast<jstring>(
792 jni->CallObjectMethod(entry, get_key));
793 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
794 jmethodID get_value = GetMethodID(jni,
795 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
796 jstring j_value = reinterpret_cast<jstring>(
797 jni->CallObjectMethod(entry, get_value));
798 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
799 field->push_back(Constraint(JavaToStdString(jni, j_key),
800 JavaToStdString(jni, j_value)));
801 }
802 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
803 }
804
805 Constraints mandatory_;
806 Constraints optional_;
807};
808
809static jobject JavaSdpFromNativeSdp(
810 JNIEnv* jni, const SessionDescriptionInterface* desc) {
811 std::string sdp;
812 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
fischman@webrtc.org41776152014-01-09 00:31:17 +0000813 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814
815 jclass j_type_class = FindClass(
816 jni, "org/webrtc/SessionDescription$Type");
817 jmethodID j_type_from_canonical = GetStaticMethodID(
818 jni, j_type_class, "fromCanonicalForm",
819 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000820 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000822 j_type_class, j_type_from_canonical, j_type_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
824
825 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
826 jmethodID j_sdp_ctor = GetMethodID(
827 jni, j_sdp_class, "<init>",
828 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
829 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000830 j_sdp_class, j_sdp_ctor, j_type, j_description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 CHECK_EXCEPTION(jni, "error during NewObject");
832 return j_sdp;
833}
834
835template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
836class SdpObserverWrapper : public T {
837 public:
838 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
839 ConstraintsWrapper* constraints)
840 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000841 j_observer_global_(jni, j_observer),
842 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 }
844
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000845 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000847 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000849 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000850 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
851 jni()->CallVoidMethod(*j_observer_global_, m);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
853 }
854
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000855 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000857 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000859 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000861 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
862 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
864 }
865
866 protected:
867 // Common implementation for failure of Set & Create types, distinguished by
868 // |op| being "Set" or "Create".
869 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000870 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
871 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000872 jstring j_error_string = JavaStringFromStdString(jni(), error);
873 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
875 }
876
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 JNIEnv* jni() {
878 return AttachCurrentThreadIfNeeded();
879 }
880
fischman@webrtc.org41776152014-01-09 00:31:17 +0000881 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000882 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000883 const ScopedGlobalRef<jobject> j_observer_global_;
884 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000885};
886
887class CreateSdpObserverWrapper
888 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
889 public:
890 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
891 ConstraintsWrapper* constraints)
892 : SdpObserverWrapper(jni, j_observer, constraints) {}
893
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000894 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000895 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896 SdpObserverWrapper::OnFailure(std::string("Create"), error);
897 }
898};
899
900class SetSdpObserverWrapper
901 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
902 public:
903 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
904 ConstraintsWrapper* constraints)
905 : SdpObserverWrapper(jni, j_observer, constraints) {}
906
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000907 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000908 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909 SdpObserverWrapper::OnFailure(std::string("Set"), error);
910 }
911};
912
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000913// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
914// and dispatching the callback from C++ back to Java.
915class DataChannelObserverWrapper : public DataChannelObserver {
916 public:
917 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
918 : j_observer_global_(jni, j_observer),
919 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
920 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
921 "onStateChange", "()V")),
922 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
923 "(Lorg/webrtc/DataChannel$Buffer;)V")),
924 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
925 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
926 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
927 }
928
929 virtual ~DataChannelObserverWrapper() {}
930
931 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000932 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000933 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
934 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
935 }
936
937 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000938 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000939 jobject byte_buffer =
940 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
941 buffer.data.length());
942 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
943 byte_buffer, buffer.binary);
944 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
945 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
946 }
947
948 private:
949 JNIEnv* jni() {
950 return AttachCurrentThreadIfNeeded();
951 }
952
953 const ScopedGlobalRef<jobject> j_observer_global_;
954 const ScopedGlobalRef<jclass> j_observer_class_;
955 const ScopedGlobalRef<jclass> j_buffer_class_;
956 const jmethodID j_on_state_change_mid_;
957 const jmethodID j_on_message_mid_;
958 const jmethodID j_buffer_ctor_;
959};
960
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
962// dispatching the callback from C++ back to Java.
963class StatsObserverWrapper : public StatsObserver {
964 public:
965 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000966 : j_observer_global_(jni, j_observer),
967 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
968 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000969 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000970 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000971 "(Ljava/lang/String;Ljava/lang/String;D"
972 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000973 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000974 jni, "org/webrtc/StatsReport$Value")),
975 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000976 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000977 "(Ljava/lang/String;Ljava/lang/String;)V")) {
978 }
979
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000980 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000982 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000983 ScopedLocalRefFrame local_ref_frame(jni());
984 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000985 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
986 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000987 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
989 }
990
991 private:
992 jobjectArray ReportsToJava(
993 JNIEnv* jni, const std::vector<StatsReport>& reports) {
994 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000995 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000996 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000997 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000999 jstring j_id = JavaStringFromStdString(jni, report.id);
1000 jstring j_type = JavaStringFromStdString(jni, report.type);
1001 jobjectArray j_values = ValuesToJava(jni, report.values);
1002 jobject j_report = jni->NewObject(*j_stats_report_class_,
1003 j_stats_report_ctor_,
1004 j_id,
1005 j_type,
1006 report.timestamp,
1007 j_values);
1008 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001009 }
1010 return reports_array;
1011 }
1012
1013 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1014 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001015 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001016 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001017 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001019 jstring j_name = JavaStringFromStdString(jni, value.name);
1020 jstring j_value = JavaStringFromStdString(jni, value.value);
1021 jobject j_element_value =
1022 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1023 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024 }
1025 return j_values;
1026 }
1027
1028 JNIEnv* jni() {
1029 return AttachCurrentThreadIfNeeded();
1030 }
1031
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001032 const ScopedGlobalRef<jobject> j_observer_global_;
1033 const ScopedGlobalRef<jclass> j_observer_class_;
1034 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001036 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 const jmethodID j_value_ctor_;
1038};
1039
1040// Adapter presenting a cricket::VideoRenderer as a
1041// webrtc::VideoRendererInterface.
1042class VideoRendererWrapper : public VideoRendererInterface {
1043 public:
1044 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1045 if (renderer)
1046 return new VideoRendererWrapper(renderer);
1047 return NULL;
1048 }
1049
1050 virtual ~VideoRendererWrapper() {}
1051
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001052 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001053 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001054 const bool kNotReserved = false; // What does this param mean??
1055 renderer_->SetSize(width, height, kNotReserved);
1056 }
1057
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001058 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001059 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060 renderer_->RenderFrame(frame);
1061 }
1062
1063 private:
1064 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1065 : renderer_(renderer) {}
1066
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001067 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068};
1069
1070// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1071// instance.
1072class JavaVideoRendererWrapper : public VideoRendererInterface {
1073 public:
1074 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001075 : j_callbacks_(jni, j_callbacks),
1076 j_set_size_id_(GetMethodID(
1077 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1078 j_render_frame_id_(GetMethodID(
1079 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1080 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1081 j_frame_class_(jni,
1082 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1083 j_frame_ctor_id_(GetMethodID(
1084 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1085 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001086 CHECK_EXCEPTION(jni, "");
1087 }
1088
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001089 virtual ~JavaVideoRendererWrapper() {}
1090
1091 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001092 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001093 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1094 CHECK_EXCEPTION(jni(), "");
1095 }
1096
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001097 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001098 ScopedLocalRefFrame local_ref_frame(jni());
1099 jobject j_frame = CricketToJavaFrame(frame);
1100 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001101 CHECK_EXCEPTION(jni(), "");
1102 }
1103
1104 private:
1105 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1106 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001107 jintArray strides = jni()->NewIntArray(3);
1108 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001109 strides_array[0] = frame->GetYPitch();
1110 strides_array[1] = frame->GetUPitch();
1111 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001112 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1113 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1114 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001115 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001116 frame->GetYPitch() * frame->GetHeight());
1117 jobject u_buffer = jni()->NewDirectByteBuffer(
1118 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1119 jobject v_buffer = jni()->NewDirectByteBuffer(
1120 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1121 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1122 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1123 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001125 *j_frame_class_, j_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001126 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001127 }
1128
1129 JNIEnv* jni() {
1130 return AttachCurrentThreadIfNeeded();
1131 }
1132
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001133 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134 jmethodID j_set_size_id_;
1135 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001136 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001138 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001139};
1140
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001141#ifdef ANDROID
1142// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1143// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1144// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001145
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001146#include <android/log.h>
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001147//#define TRACK_BUFFER_TIMING
1148#define TAG "MediaCodecVideo"
1149#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001150#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1151#else
1152#define ALOGV(...)
1153#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001154#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1155#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001156
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001157// Color formats supported by encoder - should mirror supportedColorList
1158// from MediaCodecVideoEncoder.java
1159enum COLOR_FORMATTYPE {
1160 COLOR_FormatYUV420Planar = 0x13,
1161 COLOR_FormatYUV420SemiPlanar = 0x15,
1162 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1163 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1164 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1165 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1166 // but requires some (16, 32?) byte alignment.
1167 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1168};
1169
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001170// Arbitrary interval to poll the codec for new outputs.
1171enum { kMediaCodecPollMs = 10 };
1172
1173// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1174// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1175// HW-backed video encode. This C++ class is implemented as a very thin shim,
1176// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1177// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1178// thread, currently the libjingle Worker thread.
1179class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001180 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001181 public:
1182 virtual ~MediaCodecVideoEncoder();
1183 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1184
1185 // webrtc::VideoEncoder implementation. Everything trampolines to
1186 // |codec_thread_| for execution.
1187 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1188 int32_t /* number_of_cores */,
1189 uint32_t /* max_payload_size */) OVERRIDE;
1190 virtual int32_t Encode(
1191 const webrtc::I420VideoFrame& input_image,
1192 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1193 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1194 virtual int32_t RegisterEncodeCompleteCallback(
1195 webrtc::EncodedImageCallback* callback) OVERRIDE;
1196 virtual int32_t Release() OVERRIDE;
1197 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1198 int /* rtt */) OVERRIDE;
1199 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1200
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001201 // rtc::MessageHandler implementation.
1202 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001203
1204 private:
1205 // CHECK-fail if not running on |codec_thread_|.
1206 void CheckOnCodecThread();
1207
1208 // Release() and InitEncode() in an attempt to restore the codec to an
1209 // operable state. Necessary after all manner of OMX-layer errors.
1210 void ResetCodec();
1211
1212 // Implementation of webrtc::VideoEncoder methods above, all running on the
1213 // codec thread exclusively.
1214 //
1215 // If width==0 then this is assumed to be a re-initialization and the
1216 // previously-current values are reused instead of the passed parameters
1217 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001218 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001219 int32_t EncodeOnCodecThread(
1220 const webrtc::I420VideoFrame& input_image,
1221 const std::vector<webrtc::VideoFrameType>* frame_types);
1222 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1223 webrtc::EncodedImageCallback* callback);
1224 int32_t ReleaseOnCodecThread();
1225 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1226
1227 // Reset parameters valid between InitEncode() & Release() (see below).
1228 void ResetParameters(JNIEnv* jni);
1229
1230 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1231 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1232 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1233 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1234 jlong GetOutputBufferInfoPresentationTimestampUs(
1235 JNIEnv* jni,
1236 jobject j_output_buffer_info);
1237
1238 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1239 // true on success.
1240 bool DeliverPendingOutputs(JNIEnv* jni);
1241
1242 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1243 // |codec_thread_| synchronously.
1244 webrtc::EncodedImageCallback* callback_;
1245
1246 // State that is constant for the lifetime of this object once the ctor
1247 // returns.
1248 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1249 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1250 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1251 jmethodID j_init_encode_method_;
1252 jmethodID j_dequeue_input_buffer_method_;
1253 jmethodID j_encode_method_;
1254 jmethodID j_release_method_;
1255 jmethodID j_set_rates_method_;
1256 jmethodID j_dequeue_output_buffer_method_;
1257 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001258 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001259 jfieldID j_info_index_field_;
1260 jfieldID j_info_buffer_field_;
1261 jfieldID j_info_is_key_frame_field_;
1262 jfieldID j_info_presentation_timestamp_us_field_;
1263
1264 // State that is valid only between InitEncode() and the next Release().
1265 // Touched only on codec_thread_ so no explicit synchronization necessary.
1266 int width_; // Frame width in pixels.
1267 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001268 bool inited_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001269 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001270 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001271 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001272 int frames_received_; // Number of frames received by encoder.
1273 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001274 int frames_in_queue_; // Number of frames in encoder queue.
1275 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1276 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001277 // Frame size in bytes fed to MediaCodec.
1278 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001279 // True only when between a callback_->Encoded() call return a positive value
1280 // and the next Encode() call being ignored.
1281 bool drop_next_input_frame_;
1282 // Global references; must be deleted in Release().
1283 std::vector<jobject> input_buffers_;
1284};
1285
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001286MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1287 // We depend on ResetParameters() to ensure no more callbacks to us after we
1288 // are deleted, so assert it here.
1289 CHECK(width_ == 0, "Release() should have been called");
1290}
1291
1292MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1293 : callback_(NULL),
1294 codec_thread_(new Thread()),
1295 j_media_codec_video_encoder_class_(
1296 jni,
1297 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1298 j_media_codec_video_encoder_(
1299 jni,
1300 jni->NewObject(*j_media_codec_video_encoder_class_,
1301 GetMethodID(jni,
1302 *j_media_codec_video_encoder_class_,
1303 "<init>",
1304 "()V"))) {
1305 ScopedLocalRefFrame local_ref_frame(jni);
1306 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1307 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1308 // 2732 means that deadlocks abound. This class synchronously trampolines
1309 // to |codec_thread_|, so if anything else can be coming to _us_ from
1310 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1311 // in the bug, we have a problem. For now work around that with a dedicated
1312 // thread.
1313 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
1314 CHECK(codec_thread_->Start(), "Failed to start MediaCodecVideoEncoder");
1315
1316 ResetParameters(jni);
1317
1318 jclass j_output_buffer_info_class =
1319 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1320 j_init_encode_method_ = GetMethodID(jni,
1321 *j_media_codec_video_encoder_class_,
1322 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001323 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001324 j_dequeue_input_buffer_method_ = GetMethodID(
1325 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1326 j_encode_method_ = GetMethodID(
1327 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1328 j_release_method_ =
1329 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1330 j_set_rates_method_ = GetMethodID(
1331 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1332 j_dequeue_output_buffer_method_ =
1333 GetMethodID(jni,
1334 *j_media_codec_video_encoder_class_,
1335 "dequeueOutputBuffer",
1336 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1337 j_release_output_buffer_method_ = GetMethodID(
1338 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1339
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001340 j_color_format_field_ =
1341 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001342 j_info_index_field_ =
1343 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1344 j_info_buffer_field_ = GetFieldID(
1345 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1346 j_info_is_key_frame_field_ =
1347 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1348 j_info_presentation_timestamp_us_field_ = GetFieldID(
1349 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
1350 CHECK_EXCEPTION(jni, "MediaCodecVideoEncoder ctor failed");
1351}
1352
1353int32_t MediaCodecVideoEncoder::InitEncode(
1354 const webrtc::VideoCodec* codec_settings,
1355 int32_t /* number_of_cores */,
1356 uint32_t /* max_payload_size */) {
1357 // Factory should guard against other codecs being used with us.
1358 CHECK(codec_settings->codecType == kVideoCodecVP8, "Unsupported codec");
1359
1360 return codec_thread_->Invoke<int32_t>(
1361 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1362 this,
1363 codec_settings->width,
1364 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001365 codec_settings->startBitrate,
1366 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001367}
1368
1369int32_t MediaCodecVideoEncoder::Encode(
1370 const webrtc::I420VideoFrame& frame,
1371 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1372 const std::vector<webrtc::VideoFrameType>* frame_types) {
1373 return codec_thread_->Invoke<int32_t>(Bind(
1374 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1375}
1376
1377int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1378 webrtc::EncodedImageCallback* callback) {
1379 return codec_thread_->Invoke<int32_t>(
1380 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1381 this,
1382 callback));
1383}
1384
1385int32_t MediaCodecVideoEncoder::Release() {
1386 return codec_thread_->Invoke<int32_t>(
1387 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1388}
1389
1390int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1391 int /* rtt */) {
1392 return WEBRTC_VIDEO_CODEC_OK;
1393}
1394
1395int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1396 uint32_t frame_rate) {
1397 return codec_thread_->Invoke<int32_t>(
1398 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1399 this,
1400 new_bit_rate,
1401 frame_rate));
1402}
1403
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001404void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001405 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1406 ScopedLocalRefFrame local_ref_frame(jni);
1407
1408 // We only ever send one message to |this| directly (not through a Bind()'d
1409 // functor), so expect no ID/data.
1410 CHECK(!msg->message_id, "Unexpected message!");
1411 CHECK(!msg->pdata, "Unexpected message!");
1412 CheckOnCodecThread();
1413
1414 // It would be nice to recover from a failure here if one happened, but it's
1415 // unclear how to signal such a failure to the app, so instead we stay silent
1416 // about it and let the next app-called API method reveal the borkedness.
1417 DeliverPendingOutputs(jni);
1418 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1419}
1420
1421void MediaCodecVideoEncoder::CheckOnCodecThread() {
1422 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread(),
1423 "Running on wrong thread!");
1424}
1425
1426void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001427 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001428 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1429 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001430 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0, 0))
1431 != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001432 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1433 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1434 // https://code.google.com/p/webrtc/issues/detail?id=2920
1435 }
1436}
1437
1438int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001439 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001440 CheckOnCodecThread();
1441 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1442 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001443 ALOGD("InitEncodeOnCodecThread %d x %d", width, height);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001444
1445 if (width == 0) {
1446 width = width_;
1447 height = height_;
1448 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001449 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001450 }
1451
1452 width_ = width;
1453 height_ = height;
1454 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001455 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001456 yuv_size_ = width_ * height_ * 3 / 2;
1457 frames_received_ = 0;
1458 frames_dropped_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001459 frames_in_queue_ = 0;
1460 last_input_timestamp_ms_ = -1;
1461 last_output_timestamp_ms_ = -1;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001462 // We enforce no extra stride/padding in the format creation step.
1463 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1464 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1465 j_init_encode_method_,
1466 width_,
1467 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001468 kbps,
1469 fps));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001470 CHECK_EXCEPTION(jni, "");
1471 if (IsNull(jni, input_buffers))
1472 return WEBRTC_VIDEO_CODEC_ERROR;
1473
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001474 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001475 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1476 j_color_format_field_)) {
1477 case COLOR_FormatYUV420Planar:
1478 encoder_fourcc_ = libyuv::FOURCC_YU12;
1479 break;
1480 case COLOR_FormatYUV420SemiPlanar:
1481 case COLOR_QCOM_FormatYUV420SemiPlanar:
1482 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1483 encoder_fourcc_ = libyuv::FOURCC_NV12;
1484 break;
1485 default:
1486 LOG(LS_ERROR) << "Wrong color format.";
1487 return WEBRTC_VIDEO_CODEC_ERROR;
1488 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001489 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1490 CHECK(input_buffers_.empty(), "Unexpected double InitEncode without Release");
1491 input_buffers_.resize(num_input_buffers);
1492 for (size_t i = 0; i < num_input_buffers; ++i) {
1493 input_buffers_[i] =
1494 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001495 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001496 jni->GetDirectBufferCapacity(input_buffers_[i]);
1497 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001498 CHECK(yuv_buffer_capacity >= yuv_size_, "Insufficient capacity");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001499 }
1500 CHECK_EXCEPTION(jni, "");
1501
1502 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1503 return WEBRTC_VIDEO_CODEC_OK;
1504}
1505
1506int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1507 const webrtc::I420VideoFrame& frame,
1508 const std::vector<webrtc::VideoFrameType>* frame_types) {
1509 CheckOnCodecThread();
1510 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1511 ScopedLocalRefFrame local_ref_frame(jni);
1512
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001513 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001514 if (!DeliverPendingOutputs(jni)) {
1515 ResetCodec();
1516 // Continue as if everything's fine.
1517 }
1518
1519 if (drop_next_input_frame_) {
1520 drop_next_input_frame_ = false;
1521 return WEBRTC_VIDEO_CODEC_OK;
1522 }
1523
1524 CHECK(frame_types->size() == 1, "Unexpected stream count");
1525 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1526
1527 CHECK(frame.width() == width_, "Unexpected resolution change");
1528 CHECK(frame.height() == height_, "Unexpected resolution change");
1529
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001530 // Check if we accumulated too many frames in encoder input buffers
1531 // so the encoder latency exceeds 100ms and drop frame if so.
1532 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ > 0 &&
1533 last_output_timestamp_ms_ > 0) {
1534 int encoder_latency_ms = last_input_timestamp_ms_ -
1535 last_output_timestamp_ms_;
1536 if (encoder_latency_ms > 100) {
1537 ALOGV("Drop frame - encoder is behind by %d ms. Q size: %d",
1538 encoder_latency_ms, frames_in_queue_);
1539 frames_dropped_++;
1540 return WEBRTC_VIDEO_CODEC_OK;
1541 }
1542 }
1543
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001544 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1545 j_dequeue_input_buffer_method_);
1546 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001547 if (j_input_buffer_index == -1) {
1548 // Video codec falls behind - no input buffer available.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001549 ALOGV("Drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001550 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001551 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001552 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001553 if (j_input_buffer_index == -2) {
1554 ResetCodec();
1555 return WEBRTC_VIDEO_CODEC_ERROR;
1556 }
1557
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001558 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001559 frames_received_, j_input_buffer_index, frame.render_time_ms());
1560
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001561 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001562 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001563 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
1564 CHECK_EXCEPTION(jni, "");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001565 CHECK(yuv_buffer, "Indirect buffer??");
1566 CHECK(!libyuv::ConvertFromI420(
1567 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1568 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1569 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1570 yuv_buffer, width_,
1571 width_, height_,
1572 encoder_fourcc_),
1573 "ConvertFromI420 failed");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001574 jlong timestamp_us = frame.render_time_ms() * 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001575 last_input_timestamp_ms_ = frame.render_time_ms();
1576 frames_in_queue_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001577 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1578 j_encode_method_,
1579 key_frame,
1580 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001581 yuv_size_,
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001582 timestamp_us);
1583 CHECK_EXCEPTION(jni, "");
1584 if (!encode_status || !DeliverPendingOutputs(jni)) {
1585 ResetCodec();
1586 return WEBRTC_VIDEO_CODEC_ERROR;
1587 }
1588
1589 return WEBRTC_VIDEO_CODEC_OK;
1590}
1591
1592int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1593 webrtc::EncodedImageCallback* callback) {
1594 CheckOnCodecThread();
1595 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1596 ScopedLocalRefFrame local_ref_frame(jni);
1597 callback_ = callback;
1598 return WEBRTC_VIDEO_CODEC_OK;
1599}
1600
1601int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001602 if (!inited_)
1603 return WEBRTC_VIDEO_CODEC_OK;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001604 CheckOnCodecThread();
1605 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001606 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1607 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001608 ScopedLocalRefFrame local_ref_frame(jni);
1609 for (size_t i = 0; i < input_buffers_.size(); ++i)
1610 jni->DeleteGlobalRef(input_buffers_[i]);
1611 input_buffers_.clear();
1612 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1613 ResetParameters(jni);
1614 CHECK_EXCEPTION(jni, "");
1615 return WEBRTC_VIDEO_CODEC_OK;
1616}
1617
1618int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1619 uint32_t frame_rate) {
1620 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001621 if (last_set_bitrate_kbps_ == new_bit_rate &&
1622 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001623 return WEBRTC_VIDEO_CODEC_OK;
1624 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001625 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1626 ScopedLocalRefFrame local_ref_frame(jni);
1627 last_set_bitrate_kbps_ = new_bit_rate;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001628 last_set_fps_ = frame_rate;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001629 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1630 j_set_rates_method_,
1631 new_bit_rate,
1632 frame_rate);
1633 CHECK_EXCEPTION(jni, "");
1634 if (!ret) {
1635 ResetCodec();
1636 return WEBRTC_VIDEO_CODEC_ERROR;
1637 }
1638 return WEBRTC_VIDEO_CODEC_OK;
1639}
1640
1641void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001642 rtc::MessageQueueManager::Clear(this);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001643 width_ = 0;
1644 height_ = 0;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001645 yuv_size_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001646 drop_next_input_frame_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001647 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001648 CHECK(input_buffers_.empty(),
1649 "ResetParameters called while holding input_buffers_!");
1650}
1651
1652int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1653 JNIEnv* jni,
1654 jobject j_output_buffer_info) {
1655 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1656}
1657
1658jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1659 JNIEnv* jni,
1660 jobject j_output_buffer_info) {
1661 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1662}
1663
1664bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1665 JNIEnv* jni,
1666 jobject j_output_buffer_info) {
1667 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1668}
1669
1670jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1671 JNIEnv* jni,
1672 jobject j_output_buffer_info) {
1673 return GetLongField(
1674 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1675}
1676
1677bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1678 while (true) {
1679 jobject j_output_buffer_info = jni->CallObjectMethod(
1680 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
1681 CHECK_EXCEPTION(jni, "");
1682 if (IsNull(jni, j_output_buffer_info))
1683 break;
1684
1685 int output_buffer_index =
1686 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1687 if (output_buffer_index == -1) {
1688 ResetCodec();
1689 return false;
1690 }
1691
1692 jlong capture_time_ms =
1693 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1694 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001695 last_output_timestamp_ms_ = capture_time_ms;
1696 frames_in_queue_--;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001697 ALOGV("Encoder got output buffer # %d. TS: %lld. Latency: %lld",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001698 output_buffer_index, last_output_timestamp_ms_,
1699 last_input_timestamp_ms_ - last_output_timestamp_ms_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001700
1701 int32_t callback_status = 0;
1702 if (callback_) {
1703 jobject j_output_buffer =
1704 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1705 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1706 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1707 uint8* payload = reinterpret_cast<uint8_t*>(
1708 jni->GetDirectBufferAddress(j_output_buffer));
1709 CHECK_EXCEPTION(jni, "");
1710 scoped_ptr<webrtc::EncodedImage> image(
1711 new webrtc::EncodedImage(payload, payload_size, payload_size));
1712 image->_encodedWidth = width_;
1713 image->_encodedHeight = height_;
1714 // Convert capture time to 90 kHz RTP timestamp.
1715 image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
1716 image->capture_time_ms_ = capture_time_ms;
1717 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1718 image->_completeFrame = true;
1719
1720 webrtc::CodecSpecificInfo info;
1721 memset(&info, 0, sizeof(info));
1722 info.codecType = kVideoCodecVP8;
1723 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1724 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1725 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1726
1727 // Generate a header describing a single fragment.
1728 webrtc::RTPFragmentationHeader header;
1729 memset(&header, 0, sizeof(header));
1730 header.VerifyAndAllocateFragmentationHeader(1);
1731 header.fragmentationOffset[0] = 0;
1732 header.fragmentationLength[0] = image->_length;
1733 header.fragmentationPlType[0] = 0;
1734 header.fragmentationTimeDiff[0] = 0;
1735
1736 callback_status = callback_->Encoded(*image, &info, &header);
1737 }
1738
1739 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1740 j_release_output_buffer_method_,
1741 output_buffer_index);
1742 CHECK_EXCEPTION(jni, "");
1743 if (!success) {
1744 ResetCodec();
1745 return false;
1746 }
1747
1748 if (callback_status > 0)
1749 drop_next_input_frame_ = true;
1750 // Theoretically could handle callback_status<0 here, but unclear what that
1751 // would mean for us.
1752 }
1753
1754 return true;
1755}
1756
1757// Simplest-possible implementation of an encoder factory, churns out
1758// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1759class MediaCodecVideoEncoderFactory
1760 : public cricket::WebRtcVideoEncoderFactory {
1761 public:
1762 MediaCodecVideoEncoderFactory();
1763 virtual ~MediaCodecVideoEncoderFactory();
1764
1765 // WebRtcVideoEncoderFactory implementation.
1766 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1767 OVERRIDE;
1768 virtual void AddObserver(Observer* observer) OVERRIDE;
1769 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1770 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1771 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1772
1773 private:
1774 // Empty if platform support is lacking, const after ctor returns.
1775 std::vector<VideoCodec> supported_codecs_;
1776};
1777
1778MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1779 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1780 ScopedLocalRefFrame local_ref_frame(jni);
1781 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1782 bool is_platform_supported = jni->CallStaticBooleanMethod(
1783 j_encoder_class,
1784 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
1785 CHECK_EXCEPTION(jni, "");
1786 if (!is_platform_supported)
1787 return;
1788
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001789 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1790 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1791 // reasonable defaults.
1792 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001793 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001794}
1795
1796MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1797
1798webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1799 webrtc::VideoCodecType type) {
1800 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1801 return NULL;
1802 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1803}
1804
1805// Since the available codec list is never going to change, we ignore the
1806// Observer-related interface here.
1807void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1808void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1809
1810const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1811MediaCodecVideoEncoderFactory::codecs() const {
1812 return supported_codecs_;
1813}
1814
1815void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1816 webrtc::VideoEncoder* encoder) {
1817 delete encoder;
1818}
1819
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001820class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001821 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001822 public:
1823 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1824 virtual ~MediaCodecVideoDecoder();
1825
1826 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1827 int32_t numberOfCores) OVERRIDE;
1828
1829 virtual int32_t
1830 Decode(const EncodedImage& inputImage, bool missingFrames,
1831 const RTPFragmentationHeader* fragmentation,
1832 const CodecSpecificInfo* codecSpecificInfo = NULL,
1833 int64_t renderTimeMs = -1) OVERRIDE;
1834
1835 virtual int32_t RegisterDecodeCompleteCallback(
1836 DecodedImageCallback* callback) OVERRIDE;
1837
1838 virtual int32_t Release() OVERRIDE;
1839
1840 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001841 // rtc::MessageHandler implementation.
1842 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001843
1844 private:
1845 // CHECK-fail if not running on |codec_thread_|.
1846 void CheckOnCodecThread();
1847
1848 int32_t InitDecodeOnCodecThread();
1849 int32_t ReleaseOnCodecThread();
1850 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
1851
1852 bool key_frame_required_;
1853 bool inited_;
1854 VideoCodec codec_;
1855 I420VideoFrame decoded_image_;
1856 DecodedImageCallback* callback_;
1857 int frames_received_; // Number of frames received by decoder.
1858
1859 // State that is constant for the lifetime of this object once the ctor
1860 // returns.
1861 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1862 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
1863 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
1864 jmethodID j_init_decode_method_;
1865 jmethodID j_release_method_;
1866 jmethodID j_dequeue_input_buffer_method_;
1867 jmethodID j_queue_input_buffer_method_;
1868 jmethodID j_dequeue_output_buffer_method_;
1869 jmethodID j_release_output_buffer_method_;
1870 jfieldID j_input_buffers_field_;
1871 jfieldID j_output_buffers_field_;
1872 jfieldID j_color_format_field_;
1873 jfieldID j_width_field_;
1874 jfieldID j_height_field_;
1875 jfieldID j_stride_field_;
1876 jfieldID j_slice_height_field_;
1877
1878 // Global references; must be deleted in Release().
1879 std::vector<jobject> input_buffers_;
1880};
1881
1882MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni) :
1883 key_frame_required_(true),
1884 inited_(false),
1885 codec_thread_(new Thread()),
1886 j_media_codec_video_decoder_class_(
1887 jni,
1888 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
1889 j_media_codec_video_decoder_(
1890 jni,
1891 jni->NewObject(*j_media_codec_video_decoder_class_,
1892 GetMethodID(jni,
1893 *j_media_codec_video_decoder_class_,
1894 "<init>",
1895 "()V"))) {
1896 ScopedLocalRefFrame local_ref_frame(jni);
1897 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
1898 CHECK(codec_thread_->Start(), "Failed to start MediaCodecVideoDecoder");
1899
1900 j_init_decode_method_ = GetMethodID(jni,
1901 *j_media_codec_video_decoder_class_,
1902 "initDecode", "(II)Z");
1903 j_release_method_ =
1904 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
1905 j_dequeue_input_buffer_method_ = GetMethodID(
1906 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
1907 j_queue_input_buffer_method_ = GetMethodID(
1908 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
1909 j_dequeue_output_buffer_method_ = GetMethodID(
1910 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer", "()I");
1911 j_release_output_buffer_method_ = GetMethodID(
1912 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(I)Z");
1913
1914 j_input_buffers_field_ = GetFieldID(
1915 jni, *j_media_codec_video_decoder_class_,
1916 "inputBuffers", "[Ljava/nio/ByteBuffer;");
1917 j_output_buffers_field_ = GetFieldID(
1918 jni, *j_media_codec_video_decoder_class_,
1919 "outputBuffers", "[Ljava/nio/ByteBuffer;");
1920 j_color_format_field_ = GetFieldID(
1921 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
1922 j_width_field_ = GetFieldID(
1923 jni, *j_media_codec_video_decoder_class_, "width", "I");
1924 j_height_field_ = GetFieldID(
1925 jni, *j_media_codec_video_decoder_class_, "height", "I");
1926 j_stride_field_ = GetFieldID(
1927 jni, *j_media_codec_video_decoder_class_, "stride", "I");
1928 j_slice_height_field_ = GetFieldID(
1929 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
1930
1931 CHECK_EXCEPTION(jni, "MediaCodecVideoDecoder ctor failed");
1932 memset(&codec_, 0, sizeof(codec_));
1933}
1934
1935MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
1936 Release();
1937}
1938
1939int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
1940 int32_t numberOfCores) {
1941 if (inst == NULL) {
1942 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
1943 }
1944 int ret_val = Release();
1945 if (ret_val < 0) {
1946 return ret_val;
1947 }
1948 // Save VideoCodec instance for later.
1949 if (&codec_ != inst) {
1950 codec_ = *inst;
1951 }
1952 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
1953
1954 // Always start with a complete key frame.
1955 key_frame_required_ = true;
1956 frames_received_ = 0;
1957
1958 // Call Java init.
1959 return codec_thread_->Invoke<int32_t>(
1960 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
1961}
1962
1963int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
1964 CheckOnCodecThread();
1965 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1966 ScopedLocalRefFrame local_ref_frame(jni);
1967 ALOGD("InitDecodeOnCodecThread: %d x %d. FPS: %d",
1968 codec_.width, codec_.height, codec_.maxFramerate);
1969
1970 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
1971 j_init_decode_method_,
1972 codec_.width,
1973 codec_.height);
1974 CHECK_EXCEPTION(jni, "");
1975 if (!success)
1976 return WEBRTC_VIDEO_CODEC_ERROR;
1977 inited_ = true;
1978
1979 jobjectArray input_buffers = (jobjectArray)GetObjectField(
1980 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
1981 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1982
1983 input_buffers_.resize(num_input_buffers);
1984 for (size_t i = 0; i < num_input_buffers; ++i) {
1985 input_buffers_[i] =
1986 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
1987 CHECK_EXCEPTION(jni, "");
1988 }
1989 return WEBRTC_VIDEO_CODEC_OK;
1990}
1991
1992int32_t MediaCodecVideoDecoder::Release() {
1993 return codec_thread_->Invoke<int32_t>(
1994 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
1995}
1996
1997int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
1998 if (!inited_)
1999 return WEBRTC_VIDEO_CODEC_OK;
2000 CheckOnCodecThread();
2001 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2002 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2003 ScopedLocalRefFrame local_ref_frame(jni);
2004 for (size_t i = 0; i < input_buffers_.size(); ++i)
2005 jni->DeleteGlobalRef(input_buffers_[i]);
2006 input_buffers_.clear();
2007 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
2008 CHECK_EXCEPTION(jni, "");
2009 inited_ = false;
2010 return WEBRTC_VIDEO_CODEC_OK;
2011}
2012
2013
2014void MediaCodecVideoDecoder::CheckOnCodecThread() {
2015 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread(),
2016 "Running on wrong thread!");
2017}
2018
2019int32_t MediaCodecVideoDecoder::Decode(
2020 const EncodedImage& inputImage,
2021 bool missingFrames,
2022 const RTPFragmentationHeader* fragmentation,
2023 const CodecSpecificInfo* codecSpecificInfo,
2024 int64_t renderTimeMs) {
2025 if (!inited_) {
2026 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2027 }
2028 if (callback_ == NULL) {
2029 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2030 }
2031 if (inputImage._buffer == NULL && inputImage._length > 0) {
2032 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2033 }
2034 // Check if encoded frame dimension has changed.
2035 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2036 (inputImage._encodedWidth != codec_.width ||
2037 inputImage._encodedHeight != codec_.height)) {
2038 codec_.width = inputImage._encodedWidth;
2039 codec_.height = inputImage._encodedHeight;
2040 InitDecode(&codec_, 1);
2041 }
2042
2043 // Always start with a complete key frame.
2044 if (key_frame_required_) {
2045 if (inputImage._frameType != webrtc::kKeyFrame) {
2046 return WEBRTC_VIDEO_CODEC_ERROR;
2047 }
2048 if (!inputImage._completeFrame) {
2049 return WEBRTC_VIDEO_CODEC_ERROR;
2050 }
2051 key_frame_required_ = false;
2052 }
2053 if (inputImage._length == 0) {
2054 return WEBRTC_VIDEO_CODEC_ERROR;
2055 }
2056
2057 return codec_thread_->Invoke<int32_t>(Bind(
2058 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2059}
2060
2061int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2062 const EncodedImage& inputImage) {
2063 static uint8_t yVal_ = 0x7f;
2064
2065 CheckOnCodecThread();
2066 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2067 ScopedLocalRefFrame local_ref_frame(jni);
2068
2069 // Get input buffer.
2070 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2071 j_dequeue_input_buffer_method_);
2072 CHECK_EXCEPTION(jni, "");
2073 if (j_input_buffer_index < 0) {
2074 ALOGE("dequeueInputBuffer error");
2075 Reset();
2076 return WEBRTC_VIDEO_CODEC_ERROR;
2077 }
2078
2079 // Copy encoded data to Java ByteBuffer.
2080 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2081 uint8* buffer =
2082 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
2083 CHECK(buffer, "Indirect buffer??");
2084 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
2085 CHECK_EXCEPTION(jni, "");
2086 if (buffer_capacity < inputImage._length) {
2087 ALOGE("Input frame size %d is bigger than buffer size %d.",
2088 inputImage._length, buffer_capacity);
2089 Reset();
2090 return WEBRTC_VIDEO_CODEC_ERROR;
2091 }
2092 ALOGV("Decode frame # %d. Buffer # %d. Size: %d",
2093 frames_received_, j_input_buffer_index, inputImage._length);
2094 memcpy(buffer, inputImage._buffer, inputImage._length);
2095
2096 // Feed input to decoder.
2097 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2098 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2099 j_queue_input_buffer_method_,
2100 j_input_buffer_index,
2101 inputImage._length,
2102 timestamp_us);
2103 CHECK_EXCEPTION(jni, "");
2104 if (!success) {
2105 ALOGE("queueInputBuffer error");
2106 Reset();
2107 return WEBRTC_VIDEO_CODEC_ERROR;
2108 }
2109
2110 // Get output index.
2111 int j_output_buffer_index =
2112 jni->CallIntMethod(*j_media_codec_video_decoder_,
2113 j_dequeue_output_buffer_method_);
2114 CHECK_EXCEPTION(jni, "");
2115 if (j_output_buffer_index < 0) {
2116 ALOGE("dequeueOutputBuffer error");
2117 Reset();
2118 return WEBRTC_VIDEO_CODEC_ERROR;
2119 }
2120
2121 // Extract data from Java ByteBuffer.
2122 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2123 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2124 jobject output_buffer =
2125 jni->GetObjectArrayElement(output_buffers, j_output_buffer_index);
2126 buffer_capacity = jni->GetDirectBufferCapacity(output_buffer);
2127 uint8_t* payload =
2128 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(output_buffer));
2129 CHECK_EXCEPTION(jni, "");
2130 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2131 j_color_format_field_);
2132 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2133 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2134 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2135 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2136 j_slice_height_field_);
2137 if (buffer_capacity < width * height * 3 / 2) {
2138 ALOGE("Insufficient output buffer capacity: %d", buffer_capacity);
2139 Reset();
2140 return WEBRTC_VIDEO_CODEC_ERROR;
2141 }
2142 ALOGV("Decoder got output buffer %d x %d. %d x %d. Color: 0x%x. Size: %d",
2143 width, height, stride, slice_height, color_format, buffer_capacity);
2144
2145 if (color_format == COLOR_FormatYUV420Planar) {
2146 decoded_image_.CreateFrame(
2147 stride * slice_height, payload,
2148 (stride * slice_height) / 4, payload + (stride * slice_height),
2149 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2150 width, height,
2151 stride, stride / 2, stride / 2);
2152 } else {
2153 // All other supported formats are nv12.
2154 decoded_image_.CreateEmptyFrame(width, height, width, width / 2, width / 2);
2155 libyuv::NV12ToI420(
2156 payload, stride,
2157 payload + stride * slice_height, stride,
2158 decoded_image_.buffer(webrtc::kYPlane),
2159 decoded_image_.stride(webrtc::kYPlane),
2160 decoded_image_.buffer(webrtc::kUPlane),
2161 decoded_image_.stride(webrtc::kUPlane),
2162 decoded_image_.buffer(webrtc::kVPlane),
2163 decoded_image_.stride(webrtc::kVPlane),
2164 width, height);
2165 }
2166
2167 // Return output buffer back to codec.
2168 success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2169 j_release_output_buffer_method_,
2170 j_output_buffer_index);
2171 CHECK_EXCEPTION(jni, "");
2172 if (!success) {
2173 ALOGE("releaseOutputBuffer error");
2174 Reset();
2175 return WEBRTC_VIDEO_CODEC_ERROR;
2176 }
2177
2178 // Callback.
2179 decoded_image_.set_timestamp(inputImage._timeStamp);
2180 decoded_image_.set_ntp_time_ms(inputImage.ntp_time_ms_);
2181 frames_received_++;
2182 return callback_->Decoded(decoded_image_);
2183}
2184
2185int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2186 DecodedImageCallback* callback) {
2187 callback_ = callback;
2188 return WEBRTC_VIDEO_CODEC_OK;
2189}
2190
2191int32_t MediaCodecVideoDecoder::Reset() {
2192 ALOGD("DecoderReset");
2193 if (!inited_) {
2194 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2195 }
2196 return InitDecode(&codec_, 1);
2197}
2198
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002199void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002200}
2201
2202class MediaCodecVideoDecoderFactory
2203 : public cricket::WebRtcVideoDecoderFactory {
2204 public:
2205 MediaCodecVideoDecoderFactory();
2206 virtual ~MediaCodecVideoDecoderFactory();
2207 // WebRtcVideoDecoderFactory implementation.
2208 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2209 webrtc::VideoCodecType type) OVERRIDE;
2210
2211 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2212
2213 private:
2214 bool is_platform_supported_;
2215};
2216
2217MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2218 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2219 ScopedLocalRefFrame local_ref_frame(jni);
2220 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2221 is_platform_supported_ = jni->CallStaticBooleanMethod(
2222 j_decoder_class,
2223 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
2224 CHECK_EXCEPTION(jni, "");
2225}
2226
2227MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2228
2229webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2230 webrtc::VideoCodecType type) {
2231 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2232 return NULL;
2233 }
2234 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2235}
2236
2237
2238void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2239 webrtc::VideoDecoder* decoder) {
2240 delete decoder;
2241}
2242
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002243#endif // ANDROID
2244
2245} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002246
2247// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2248// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2249#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2250 Java_org_webrtc_##name
2251
2252extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
2253 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
2254 g_jvm = jvm;
2255 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
2256
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002257 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey), "pthread_once");
2258
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002259 CHECK(rtc::InitializeSSL(), "Failed to InitializeSSL()");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002260
2261 JNIEnv* jni;
2262 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2263 return -1;
2264 g_class_reference_holder = new ClassReferenceHolder(jni);
2265
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002266 return JNI_VERSION_1_6;
2267}
2268
2269extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002270 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002271 delete g_class_reference_holder;
2272 g_class_reference_holder = NULL;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002273 CHECK(rtc::CleanupSSL(), "Failed to CleanupSSL()");
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002274 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002275}
2276
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002277static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002278 jfieldID native_dc_id = GetFieldID(jni,
2279 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2280 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002281 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002282}
2283
2284JOW(jlong, DataChannel_registerObserverNative)(
2285 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002286 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002287 new DataChannelObserverWrapper(jni, j_observer));
2288 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002289 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002290}
2291
2292JOW(void, DataChannel_unregisterObserverNative)(
2293 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2294 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2295 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2296}
2297
2298JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2299 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2300}
2301
2302JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2303 return JavaEnumFromIndex(
2304 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2305}
2306
2307JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2308 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
2309 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
2310 "buffered_amount overflowed jlong!");
2311 return static_cast<jlong>(buffered_amount);
2312}
2313
2314JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2315 ExtractNativeDC(jni, j_dc)->Close();
2316}
2317
2318JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2319 jbyteArray data, jboolean binary) {
2320 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2321 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002322 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002323 binary));
2324 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2325 return ret;
2326}
2327
2328JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002329 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002330}
2331
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002332JOW(void, Logging_nativeEnableTracing)(
2333 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2334 jint nativeSeverity) {
2335 std::string path = JavaToStdString(jni, j_path);
2336 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002337 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002338#ifdef ANDROID
2339 if (path != "logcat:") {
2340#endif
2341 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
2342 "SetTraceFile failed");
2343#ifdef ANDROID
2344 } else {
2345 // Intentionally leak this to avoid needing to reason about its lifecycle.
2346 // It keeps no state and functions only as a dispatch point.
2347 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2348 }
2349#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002350 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002351 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002352}
2353
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002354JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002355 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002356}
2357
2358JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2359 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2360 delete p;
2361}
2362
2363JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002364 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002365}
2366
2367JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2368 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2369}
2370
2371JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
2372 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2373}
2374
2375JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002376 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002377}
2378
2379JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2380 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002381 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002382 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383}
2384
2385JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2386 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002387 return reinterpret_cast<MediaStreamInterface*>(pointer)
2388 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002389}
2390
2391JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2392 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002393 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002394 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002395}
2396
2397JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2398 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002399 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002400 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002401}
2402
2403JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2404 return JavaStringFromStdString(
2405 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2406}
2407
2408JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002409 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002410}
2411
2412JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2413 JNIEnv * jni, jclass, jobject j_observer) {
2414 return (jlong)new PCOJava(jni, j_observer);
2415}
2416
2417#ifdef ANDROID
2418JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002419 JNIEnv* jni, jclass, jobject context,
2420 jboolean initialize_audio, jboolean initialize_video) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002421 CHECK(g_jvm, "JNI_OnLoad failed to run?");
2422 bool failure = false;
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002423 if (initialize_video)
fischman@webrtc.org95127192014-06-06 18:40:44 +00002424 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002425 if (initialize_audio)
2426 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002427 return !failure;
2428}
2429#endif // ANDROID
2430
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002431// Helper struct for working around the fact that CreatePeerConnectionFactory()
2432// comes in two flavors: either entirely automagical (constructing its own
2433// threads and deleting them on teardown, but no external codec factory support)
2434// or entirely manual (requires caller to delete threads after factory
2435// teardown). This struct takes ownership of its ctor's arguments to present a
2436// single thing for Java to hold and eventually free.
2437class OwnedFactoryAndThreads {
2438 public:
2439 OwnedFactoryAndThreads(Thread* worker_thread,
2440 Thread* signaling_thread,
2441 PeerConnectionFactoryInterface* factory)
2442 : worker_thread_(worker_thread),
2443 signaling_thread_(signaling_thread),
2444 factory_(factory) {}
2445
2446 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2447
2448 PeerConnectionFactoryInterface* factory() { return factory_; }
2449
2450 private:
2451 const scoped_ptr<Thread> worker_thread_;
2452 const scoped_ptr<Thread> signaling_thread_;
2453 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2454};
2455
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002456JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2457 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002458 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2459 // ThreadManager only WrapCurrentThread()s the thread where it is first
2460 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002461 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002462 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002463 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002464 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002465 Thread* worker_thread = new Thread();
2466 worker_thread->SetName("worker_thread", NULL);
2467 Thread* signaling_thread = new Thread();
2468 signaling_thread->SetName("signaling_thread", NULL);
2469 CHECK(worker_thread->Start() && signaling_thread->Start(),
2470 "Failed to start threads");
2471 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002472 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002473#ifdef ANDROID
2474 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002475 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002476#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002477 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002478 webrtc::CreatePeerConnectionFactory(worker_thread,
2479 signaling_thread,
2480 NULL,
2481 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002482 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002483 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2484 worker_thread, signaling_thread, factory.release());
2485 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002486}
2487
2488JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002489 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002490 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002491}
2492
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002493static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2494 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2495}
2496
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002497JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2498 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002499 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002500 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002501 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002502 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2503 return (jlong)stream.release();
2504}
2505
2506JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2507 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2508 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002509 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002510 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002511 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002512 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002513 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002514 factory->CreateVideoSource(
2515 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2516 constraints.get()));
2517 return (jlong)source.release();
2518}
2519
2520JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2521 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2522 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002523 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002524 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002525 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002526 factory->CreateVideoTrack(
2527 JavaToStdString(jni, id),
2528 reinterpret_cast<VideoSourceInterface*>(native_source)));
2529 return (jlong)track.release();
2530}
2531
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002532JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2533 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2534 scoped_ptr<ConstraintsWrapper> constraints(
2535 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002536 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002537 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002538 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002539 factory->CreateAudioSource(constraints.get()));
2540 return (jlong)source.release();
2541}
2542
2543JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2544 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2545 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002546 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002547 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002548 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002549 JavaToStdString(jni, id),
2550 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002551 return (jlong)track.release();
2552}
2553
2554static void JavaIceServersToJsepIceServers(
2555 JNIEnv* jni, jobject j_ice_servers,
2556 PeerConnectionInterface::IceServers* ice_servers) {
2557 jclass list_class = GetObjectClass(jni, j_ice_servers);
2558 jmethodID iterator_id = GetMethodID(
2559 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2560 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
2561 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2562 jmethodID iterator_has_next = GetMethodID(
2563 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2564 jmethodID iterator_next = GetMethodID(
2565 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2566 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
2567 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2568 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
2569 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2570 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2571 jfieldID j_ice_server_uri_id =
2572 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2573 jfieldID j_ice_server_username_id =
2574 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2575 jfieldID j_ice_server_password_id =
2576 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2577 jstring uri = reinterpret_cast<jstring>(
2578 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2579 jstring username = reinterpret_cast<jstring>(
2580 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2581 jstring password = reinterpret_cast<jstring>(
2582 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2583 PeerConnectionInterface::IceServer server;
2584 server.uri = JavaToStdString(jni, uri);
2585 server.username = JavaToStdString(jni, username);
2586 server.password = JavaToStdString(jni, password);
2587 ice_servers->push_back(server);
2588 }
2589 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2590}
2591
2592JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2593 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2594 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002595 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002596 reinterpret_cast<PeerConnectionFactoryInterface*>(
2597 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002598 PeerConnectionInterface::IceServers servers;
2599 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2600 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2601 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002602 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002603 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002604 return (jlong)pc.release();
2605}
2606
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002607static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002608 JNIEnv* jni, jobject j_pc) {
2609 jfieldID native_pc_id = GetFieldID(jni,
2610 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2611 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002612 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002613 reinterpret_cast<PeerConnectionInterface*>(j_p));
2614}
2615
2616JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2617 const SessionDescriptionInterface* sdp =
2618 ExtractNativePC(jni, j_pc)->local_description();
2619 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2620}
2621
2622JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2623 const SessionDescriptionInterface* sdp =
2624 ExtractNativePC(jni, j_pc)->remote_description();
2625 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2626}
2627
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002628JOW(jobject, PeerConnection_createDataChannel)(
2629 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2630 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002631 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002632 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2633 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002634 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2635 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2636 // 32-bit parameter.
2637 jlong nativeChannelPtr = jlongFromPointer(channel.get());
2638 CHECK(nativeChannelPtr, "Failed to create DataChannel");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002639 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2640 jmethodID j_data_channel_ctor = GetMethodID(
2641 jni, j_data_channel_class, "<init>", "(J)V");
2642 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002643 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002644 CHECK_EXCEPTION(jni, "error during NewObject");
2645 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002646 int bumped_count = channel->AddRef();
2647 CHECK(bumped_count == 2, "Unexpected refcount");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002648 return j_channel;
2649}
2650
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002651JOW(void, PeerConnection_createOffer)(
2652 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2653 ConstraintsWrapper* constraints =
2654 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002655 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
2656 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002657 jni, j_observer, constraints));
2658 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2659}
2660
2661JOW(void, PeerConnection_createAnswer)(
2662 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2663 ConstraintsWrapper* constraints =
2664 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002665 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
2666 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667 jni, j_observer, constraints));
2668 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2669}
2670
2671// Helper to create a SessionDescriptionInterface from a SessionDescription.
2672static SessionDescriptionInterface* JavaSdpToNativeSdp(
2673 JNIEnv* jni, jobject j_sdp) {
2674 jfieldID j_type_id = GetFieldID(
2675 jni, GetObjectClass(jni, j_sdp), "type",
2676 "Lorg/webrtc/SessionDescription$Type;");
2677 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2678 jmethodID j_canonical_form_id = GetMethodID(
2679 jni, GetObjectClass(jni, j_type), "canonicalForm",
2680 "()Ljava/lang/String;");
2681 jstring j_type_string = (jstring)jni->CallObjectMethod(
2682 j_type, j_canonical_form_id);
2683 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2684 std::string std_type = JavaToStdString(jni, j_type_string);
2685
2686 jfieldID j_description_id = GetFieldID(
2687 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2688 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2689 std::string std_description = JavaToStdString(jni, j_description);
2690
2691 return webrtc::CreateSessionDescription(
2692 std_type, std_description, NULL);
2693}
2694
2695JOW(void, PeerConnection_setLocalDescription)(
2696 JNIEnv* jni, jobject j_pc,
2697 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002698 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
2699 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002700 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2701 ExtractNativePC(jni, j_pc)->SetLocalDescription(
2702 observer, JavaSdpToNativeSdp(jni, j_sdp));
2703}
2704
2705JOW(void, PeerConnection_setRemoteDescription)(
2706 JNIEnv* jni, jobject j_pc,
2707 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002708 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
2709 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002710 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2711 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2712 observer, JavaSdpToNativeSdp(jni, j_sdp));
2713}
2714
2715JOW(jboolean, PeerConnection_updateIce)(
2716 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2717 PeerConnectionInterface::IceServers ice_servers;
2718 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002719 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720 new ConstraintsWrapper(jni, j_constraints));
2721 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2722}
2723
2724JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2725 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2726 jint j_sdp_mline_index, jstring j_candidate_sdp) {
2727 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2728 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002729 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2731 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2732}
2733
2734JOW(jboolean, PeerConnection_nativeAddLocalStream)(
2735 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002736 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 new ConstraintsWrapper(jni, j_constraints));
2738 return ExtractNativePC(jni, j_pc)->AddStream(
2739 reinterpret_cast<MediaStreamInterface*>(native_stream),
2740 constraints.get());
2741}
2742
2743JOW(void, PeerConnection_nativeRemoveLocalStream)(
2744 JNIEnv* jni, jobject j_pc, jlong native_stream) {
2745 ExtractNativePC(jni, j_pc)->RemoveStream(
2746 reinterpret_cast<MediaStreamInterface*>(native_stream));
2747}
2748
2749JOW(bool, PeerConnection_nativeGetStats)(
2750 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002751 rtc::scoped_refptr<StatsObserverWrapper> observer(
2752 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002753 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00002754 observer,
2755 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
2756 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002757}
2758
2759JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2760 PeerConnectionInterface::SignalingState state =
2761 ExtractNativePC(jni, j_pc)->signaling_state();
2762 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2763}
2764
2765JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2766 PeerConnectionInterface::IceConnectionState state =
2767 ExtractNativePC(jni, j_pc)->ice_connection_state();
2768 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2769}
2770
2771JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
2772 PeerConnectionInterface::IceGatheringState state =
2773 ExtractNativePC(jni, j_pc)->ice_gathering_state();
2774 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
2775}
2776
2777JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2778 ExtractNativePC(jni, j_pc)->Close();
2779 return;
2780}
2781
2782JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002783 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002784 reinterpret_cast<MediaSourceInterface*>(j_p));
2785 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2786}
2787
2788JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
2789 JNIEnv* jni, jclass, jstring j_device_name) {
2790 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002791 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002792 cricket::DeviceManagerFactory::Create());
2793 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
2794 cricket::Device device;
2795 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002796 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002797 return 0;
2798 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002799 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002800 device_manager->CreateVideoCapturer(device));
2801 return (jlong)capturer.release();
2802}
2803
2804JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2805 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002806 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2807 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002808 return (jlong)renderer.release();
2809}
2810
2811JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2812 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002813 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814 new JavaVideoRendererWrapper(jni, j_callbacks));
2815 return (jlong)renderer.release();
2816}
2817
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002818JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2819 cricket::VideoCapturer* capturer =
2820 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002821 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002822 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2823 capturer->Stop();
2824 return jlongFromPointer(format.release());
2825}
2826
2827JOW(void, VideoSource_restart)(
2828 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002829 CHECK(j_p_source, "");
2830 CHECK(j_p_format, "");
2831 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002832 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2833 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2834 StartCapturing(cricket::VideoFormat(*format));
2835}
2836
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00002837JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002838 JNIEnv* jni, jclass, jlong j_p) {
2839 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2840}
2841
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002842JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002843 return JavaStringFromStdString(
2844 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002845}
2846
2847JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002848 return JavaStringFromStdString(
2849 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002850}
2851
2852JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002853 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002854}
2855
2856JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002857 return JavaEnumFromIndex(
2858 jni,
2859 "MediaStreamTrack$State",
2860 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861}
2862
2863JOW(jboolean, MediaStreamTrack_nativeSetState)(
2864 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002865 MediaStreamTrackInterface::TrackState new_state =
2866 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002867 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2868 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002869}
2870
2871JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2872 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002873 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2874 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002875}
2876
2877JOW(void, VideoTrack_nativeAddRenderer)(
2878 JNIEnv* jni, jclass,
2879 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002880 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002881 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2882}
2883
2884JOW(void, VideoTrack_nativeRemoveRenderer)(
2885 JNIEnv* jni, jclass,
2886 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002887 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002888 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2889}