blob: f55948ad511f390205cc6a77a0b9593c7d0e8f81 [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"
andresp@webrtc.org4d19e052014-09-09 11:45:44 +000080#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000081#include "webrtc/base/logging.h"
82#include "webrtc/base/messagequeue.h"
83#include "webrtc/base/ssladapter.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000084#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000085#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000086#include "webrtc/system_wrappers/interface/trace.h"
87#include "webrtc/video_engine/include/vie_base.h"
88#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000090#ifdef ANDROID
91#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000092using webrtc::CodecSpecificInfo;
93using webrtc::DecodedImageCallback;
94using webrtc::EncodedImage;
95using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000096using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000097using webrtc::RTPFragmentationHeader;
98using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000099#endif
100
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101using icu::UnicodeString;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000102using rtc::Bind;
103using rtc::Thread;
104using rtc::ThreadManager;
105using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106using webrtc::AudioSourceInterface;
107using webrtc::AudioTrackInterface;
108using webrtc::AudioTrackVector;
109using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000110using webrtc::DataBuffer;
111using webrtc::DataChannelInit;
112using webrtc::DataChannelInterface;
113using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114using webrtc::IceCandidateInterface;
115using webrtc::MediaConstraintsInterface;
116using webrtc::MediaSourceInterface;
117using webrtc::MediaStreamInterface;
118using webrtc::MediaStreamTrackInterface;
119using webrtc::PeerConnectionFactoryInterface;
120using webrtc::PeerConnectionInterface;
121using webrtc::PeerConnectionObserver;
122using webrtc::SessionDescriptionInterface;
123using webrtc::SetSessionDescriptionObserver;
124using webrtc::StatsObserver;
125using webrtc::StatsReport;
126using webrtc::VideoRendererInterface;
127using webrtc::VideoSourceInterface;
128using webrtc::VideoTrackInterface;
129using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000130using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000132// Abort the process if |jni| has a Java exception pending.
133// This macros uses the comma operator to execute ExceptionDescribe
134// and ExceptionClear ignoring their return values and sending ""
135// to the error stream.
136#define CHECK_EXCEPTION(jni) \
137 CHECK(!jni->ExceptionCheck()) \
138 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000140// Helper that calls ptr->Release() and aborts the process with a useful
141// message if that didn't actually delete *ptr because of extra refcounts.
142#define CHECK_RELEASE(ptr) \
143 CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000144
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145namespace {
146
147static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
148
149static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000150// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
151// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
152// were attached by the JVM because of a Java->native call.
153static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000155// Return thread ID as a string.
156static std::string GetThreadId() {
157 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000158 CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
159 sizeof(buf))
160 << "Thread id is bigger than uint64??";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000161 return std::string(buf);
162}
163
164// Return the current thread's name.
165static std::string GetThreadName() {
166 char name[17];
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000167 CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000168 name[16] = '\0';
169 return std::string(name);
170}
171
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000172// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
173static JNIEnv* GetEnv() {
174 void* env = NULL;
175 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
176 CHECK(((env != NULL) && (status == JNI_OK)) ||
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000177 ((env == NULL) && (status == JNI_EDETACHED)))
178 << "Unexpected GetEnv return: " << status << ":" << env;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000179 return reinterpret_cast<JNIEnv*>(env);
180}
181
182static void ThreadDestructor(void* prev_jni_ptr) {
183 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
184 // we were responsible for originally attaching the thread, so are responsible
185 // for detaching it now. However, because some JVM implementations (notably
186 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
187 // the JVMs accounting info for this thread may already be wiped out by the
188 // time this is called. Thus it may appear we are already detached even though
189 // it was our responsibility to detach! Oh well.
190 if (!GetEnv())
191 return;
192
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000193 CHECK(GetEnv() == prev_jni_ptr)
194 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000195 jint status = g_jvm->DetachCurrentThread();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000196 CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
197 CHECK(!GetEnv()) << "Detaching was a successful no-op???";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198}
199
200static void CreateJNIPtrKey() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000201 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
202 << "pthread_key_create";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203}
204
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000205// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000207 JNIEnv* jni = GetEnv();
208 if (jni)
209 return jni;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000210 CHECK(!pthread_getspecific(g_jni_ptr))
211 << "TLS has a JNIEnv* but not attached?";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000212
213 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
214 JavaVMAttachArgs args;
215 args.version = JNI_VERSION_1_6;
216 args.name = name;
217 args.group = NULL;
218 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000220 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000222 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000224 CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000225 free(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000226 CHECK(env) << "AttachCurrentThread handed back NULL!";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000227 jni = reinterpret_cast<JNIEnv*>(env);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000228 CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000229 return jni;
230}
231
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000232// Return a |jlong| that will correctly convert back to |ptr|. This is needed
233// because the alternative (of silently passing a 32-bit pointer to a vararg
234// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000235static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000236 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000237 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000238 // Going through intptr_t to be obvious about the definedness of the
239 // conversion from pointer to integral type. intptr_t to jlong is a standard
240 // widening by the COMPILE_ASSERT above.
241 jlong ret = reinterpret_cast<intptr_t>(ptr);
242 assert(reinterpret_cast<void*>(ret) == ptr);
243 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000244}
245
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000246// Android's FindClass() is trickier than usual because the app-specific
247// ClassLoader is not consulted when there is no app-specific frame on the
248// stack. Consequently, we only look up classes once in JNI_OnLoad.
249// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
250class ClassReferenceHolder {
251 public:
252 explicit ClassReferenceHolder(JNIEnv* jni) {
253 LoadClass(jni, "java/nio/ByteBuffer");
254 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000255 LoadClass(jni, "org/webrtc/DataChannel");
256 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
257 LoadClass(jni, "org/webrtc/DataChannel$Init");
258 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259 LoadClass(jni, "org/webrtc/IceCandidate");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000260#ifdef ANDROID
261 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
262 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000263 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000264#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 LoadClass(jni, "org/webrtc/MediaSource$State");
266 LoadClass(jni, "org/webrtc/MediaStream");
267 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000268 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
269 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000270 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 LoadClass(jni, "org/webrtc/SessionDescription");
272 LoadClass(jni, "org/webrtc/SessionDescription$Type");
273 LoadClass(jni, "org/webrtc/StatsReport");
274 LoadClass(jni, "org/webrtc/StatsReport$Value");
275 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
276 LoadClass(jni, "org/webrtc/VideoTrack");
277 }
278
279 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000280 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000281 }
282
283 void FreeReferences(JNIEnv* jni) {
284 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
285 it != classes_.end(); ++it) {
286 jni->DeleteGlobalRef(it->second);
287 }
288 classes_.clear();
289 }
290
291 jclass GetClass(const std::string& name) {
292 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000293 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 return it->second;
295 }
296
297 private:
298 void LoadClass(JNIEnv* jni, const std::string& name) {
299 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000300 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
301 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000302 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000303 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
304 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000306 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 }
308
309 std::map<std::string, jclass> classes_;
310};
311
312// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
313static ClassReferenceHolder* g_class_reference_holder = NULL;
314
315// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
316// object/class/method/field is non-null.
317jmethodID GetMethodID(
318 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
319 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000320 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
321 << signature;
322 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000323 return m;
324}
325
326jmethodID GetStaticMethodID(
327 JNIEnv* jni, jclass c, const char* name, const char* signature) {
328 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000329 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
330 << signature;
331 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 return m;
333}
334
335jfieldID GetFieldID(
336 JNIEnv* jni, jclass c, const char* name, const char* signature) {
337 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000338 CHECK_EXCEPTION(jni) << "error during GetFieldID";
339 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340 return f;
341}
342
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000343// Returns a global reference guaranteed to be valid for the lifetime of the
344// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000345jclass FindClass(JNIEnv* jni, const char* name) {
346 return g_class_reference_holder->GetClass(name);
347}
348
349jclass GetObjectClass(JNIEnv* jni, jobject object) {
350 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000351 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
352 CHECK(c);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353 return c;
354}
355
356jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
357 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000358 CHECK_EXCEPTION(jni) << "error during GetObjectField";
359 CHECK(o);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000360 return o;
361}
362
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000363jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
364 return static_cast<jstring>(GetObjectField(jni, object, id));
365}
366
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
368 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000369 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370 return l;
371}
372
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000373jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
374 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000375 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000376 return i;
377}
378
379bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
380 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000381 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000382 return b;
383}
384
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385jobject NewGlobalRef(JNIEnv* jni, jobject o) {
386 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000387 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
388 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000389 return ret;
390}
391
392void DeleteGlobalRef(JNIEnv* jni, jobject o) {
393 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000394 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395}
396
397// Given a jweak reference, allocate a (strong) local reference scoped to the
398// lifetime of this object if the weak reference is still valid, or NULL
399// otherwise.
400class WeakRef {
401 public:
402 WeakRef(JNIEnv* jni, jweak ref)
403 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000404 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000405 }
406 ~WeakRef() {
407 if (obj_) {
408 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000409 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 }
411 }
412 jobject obj() { return obj_; }
413
414 private:
415 JNIEnv* const jni_;
416 jobject const obj_;
417};
418
fischman@webrtc.org41776152014-01-09 00:31:17 +0000419// Scope Java local references to the lifetime of this object. Use in all C++
420// callbacks (i.e. entry points that don't originate in a Java callstack
421// through a "native" method call).
422class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000424 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000425 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000427 ~ScopedLocalRefFrame() {
428 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000430
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431 private:
432 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433};
434
435// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000436template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437class ScopedGlobalRef {
438 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000439 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000440 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441 ~ScopedGlobalRef() {
442 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
443 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000444 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000445 return obj_;
446 }
447 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000448 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449};
450
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000451// Java references to "null" can only be distinguished as such in C++ by
452// creating a local reference, so this helper wraps that logic.
453static bool IsNull(JNIEnv* jni, jobject obj) {
454 ScopedLocalRefFrame local_ref_frame(jni);
455 return jni->NewLocalRef(obj) == NULL;
456}
457
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458// Return the (singleton) Java Enum object corresponding to |index|;
459// |state_class_fragment| is something like "MediaSource$State".
460jobject JavaEnumFromIndex(
461 JNIEnv* jni, const std::string& state_class_fragment, int index) {
462 std::string state_class_name = "org/webrtc/" + state_class_fragment;
463 jclass state_class = FindClass(jni, state_class_name.c_str());
464 jmethodID state_values_id = GetStaticMethodID(
465 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000466 jobjectArray state_values = static_cast<jobjectArray>(
467 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000468 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000469 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000470 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 return ret;
472}
473
474// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
475static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
476 UnicodeString ustr(UnicodeString::fromUTF8(native));
477 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000478 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000479 return jstr;
480}
481
482// Given a (UTF-16) jstring return a new UTF-8 native string.
483static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
484 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000485 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000486 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000487 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000488 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000489 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490 std::string ret;
491 return ustr.toUTF8String(ret);
492}
493
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000494static DataChannelInit JavaDataChannelInitToNative(
495 JNIEnv* jni, jobject j_init) {
496 DataChannelInit init;
497
498 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
499 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
500 jfieldID max_retransmit_time_id =
501 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
502 jfieldID max_retransmits_id =
503 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
504 jfieldID protocol_id =
505 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
506 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
507 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
508
509 init.ordered = GetBooleanField(jni, j_init, ordered_id);
510 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
511 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
512 init.protocol = JavaToStdString(
513 jni, GetStringField(jni, j_init, protocol_id));
514 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
515 init.id = GetIntField(jni, j_init, id_id);
516
517 return init;
518}
519
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000520class ConstraintsWrapper;
521
522// Adapter between the C++ PeerConnectionObserver interface and the Java
523// PeerConnection.Observer interface. Wraps an instance of the Java interface
524// and dispatches C++ callbacks to Java.
525class PCOJava : public PeerConnectionObserver {
526 public:
527 PCOJava(JNIEnv* jni, jobject j_observer)
528 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000529 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
530 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
531 j_media_stream_ctor_(GetMethodID(
532 jni, *j_media_stream_class_, "<init>", "(J)V")),
533 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000535 jni, *j_audio_track_class_, "<init>", "(J)V")),
536 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
537 j_video_track_ctor_(GetMethodID(
538 jni, *j_video_track_class_, "<init>", "(J)V")),
539 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
540 j_data_channel_ctor_(GetMethodID(
541 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000542 }
543
544 virtual ~PCOJava() {}
545
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000546 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000547 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000548 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000549 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
551 jmethodID ctor = GetMethodID(jni(), candidate_class,
552 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000553 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
554 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
555 jobject j_candidate = jni()->NewObject(
556 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000557 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000558 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000560 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000561 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 }
563
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000564 virtual void OnError() OVERRIDE {
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000565 ScopedLocalRefFrame local_ref_frame(jni());
566 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000568 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 }
570
571 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000572 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000573 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000575 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000577 jobject new_state_enum =
578 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
579 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000580 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 }
582
583 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000584 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000585 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000587 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000589 jobject new_state_enum = JavaEnumFromIndex(
590 jni(), "PeerConnection$IceConnectionState", new_state);
591 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000592 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 }
594
595 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000596 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000597 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000599 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000601 jobject new_state_enum = JavaEnumFromIndex(
602 jni(), "PeerConnection$IceGatheringState", new_state);
603 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000604 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 }
606
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000607 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000608 ScopedLocalRefFrame local_ref_frame(jni());
609 jobject j_stream = jni()->NewObject(
610 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000611 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612
613 AudioTrackVector audio_tracks = stream->GetAudioTracks();
614 for (size_t i = 0; i < audio_tracks.size(); ++i) {
615 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000616 jstring id = JavaStringFromStdString(jni(), track->id());
617 jobject j_track = jni()->NewObject(
618 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000619 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000620 jfieldID audio_tracks_id = GetFieldID(jni(),
621 *j_media_stream_class_,
622 "audioTracks",
623 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000624 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000626 GetObjectClass(jni(), audio_tracks),
627 "add",
628 "(Ljava/lang/Object;)Z");
629 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000630 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
631 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 }
633
634 VideoTrackVector video_tracks = stream->GetVideoTracks();
635 for (size_t i = 0; i < video_tracks.size(); ++i) {
636 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000637 jstring id = JavaStringFromStdString(jni(), track->id());
638 jobject j_track = jni()->NewObject(
639 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000640 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000641 jfieldID video_tracks_id = GetFieldID(jni(),
642 *j_media_stream_class_,
643 "videoTracks",
644 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000645 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000646 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000647 GetObjectClass(jni(), video_tracks),
648 "add",
649 "(Ljava/lang/Object;)Z");
650 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000651 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
652 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000654 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000655 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000657 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
658 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000659 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000660 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 }
662
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000663 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000664 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000666 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667
668 WeakRef s(jni(), it->second);
669 streams_.erase(it);
670 if (!s.obj())
671 return;
672
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000673 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
674 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000676 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 }
678
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000679 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000680 ScopedLocalRefFrame local_ref_frame(jni());
681 jobject j_channel = jni()->NewObject(
682 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000683 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000684
685 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
686 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000687 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000688
689 // Channel is now owned by Java object, and will be freed from
690 // DataChannel.dispose(). Important that this be done _after_ the
691 // CallVoidMethod above as Java code might call back into native code and be
692 // surprised to see a refcount of 2.
693 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000694 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000695
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000696 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000697 }
698
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000699 virtual void OnRenegotiationNeeded() OVERRIDE {
700 ScopedLocalRefFrame local_ref_frame(jni());
701 jmethodID m =
702 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
703 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000704 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000705 }
706
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000708 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709 constraints_.reset(constraints);
710 }
711
712 const ConstraintsWrapper* constraints() { return constraints_.get(); }
713
714 private:
715 JNIEnv* jni() {
716 return AttachCurrentThreadIfNeeded();
717 }
718
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000719 const ScopedGlobalRef<jobject> j_observer_global_;
720 const ScopedGlobalRef<jclass> j_observer_class_;
721 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000723 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000725 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000727 const ScopedGlobalRef<jclass> j_data_channel_class_;
728 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
730 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000731 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732};
733
734// Wrapper for a Java MediaConstraints object. Copies all needed data so when
735// the constructor returns the Java object is no longer needed.
736class ConstraintsWrapper : public MediaConstraintsInterface {
737 public:
738 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
739 PopulateConstraintsFromJavaPairList(
740 jni, j_constraints, "mandatory", &mandatory_);
741 PopulateConstraintsFromJavaPairList(
742 jni, j_constraints, "optional", &optional_);
743 }
744
745 virtual ~ConstraintsWrapper() {}
746
747 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000748 virtual const Constraints& GetMandatory() const OVERRIDE {
749 return mandatory_;
750 }
751
752 virtual const Constraints& GetOptional() const OVERRIDE {
753 return optional_;
754 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000755
756 private:
757 // Helper for translating a List<Pair<String, String>> to a Constraints.
758 static void PopulateConstraintsFromJavaPairList(
759 JNIEnv* jni, jobject j_constraints,
760 const char* field_name, Constraints* field) {
761 jfieldID j_id = GetFieldID(jni,
762 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
763 jobject j_list = GetObjectField(jni, j_constraints, j_id);
764 jmethodID j_iterator_id = GetMethodID(jni,
765 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
766 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000767 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 jmethodID j_has_next = GetMethodID(jni,
769 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
770 jmethodID j_next = GetMethodID(jni,
771 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
772 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000773 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000775 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000776 jmethodID get_key = GetMethodID(jni,
777 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
778 jstring j_key = reinterpret_cast<jstring>(
779 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000780 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781 jmethodID get_value = GetMethodID(jni,
782 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
783 jstring j_value = reinterpret_cast<jstring>(
784 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000785 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 field->push_back(Constraint(JavaToStdString(jni, j_key),
787 JavaToStdString(jni, j_value)));
788 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000789 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790 }
791
792 Constraints mandatory_;
793 Constraints optional_;
794};
795
796static jobject JavaSdpFromNativeSdp(
797 JNIEnv* jni, const SessionDescriptionInterface* desc) {
798 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000799 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000800 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801
802 jclass j_type_class = FindClass(
803 jni, "org/webrtc/SessionDescription$Type");
804 jmethodID j_type_from_canonical = GetStaticMethodID(
805 jni, j_type_class, "fromCanonicalForm",
806 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000807 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000809 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000810 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811
812 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
813 jmethodID j_sdp_ctor = GetMethodID(
814 jni, j_sdp_class, "<init>",
815 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
816 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000817 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000818 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 return j_sdp;
820}
821
822template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
823class SdpObserverWrapper : public T {
824 public:
825 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
826 ConstraintsWrapper* constraints)
827 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000828 j_observer_global_(jni, j_observer),
829 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 }
831
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000832 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000834 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000836 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000837 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
838 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000839 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 }
841
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000842 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000844 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000846 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000848 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
849 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000850 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 }
852
853 protected:
854 // Common implementation for failure of Set & Create types, distinguished by
855 // |op| being "Set" or "Create".
856 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000857 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
858 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000859 jstring j_error_string = JavaStringFromStdString(jni(), error);
860 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000861 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 }
863
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 JNIEnv* jni() {
865 return AttachCurrentThreadIfNeeded();
866 }
867
fischman@webrtc.org41776152014-01-09 00:31:17 +0000868 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000869 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000870 const ScopedGlobalRef<jobject> j_observer_global_;
871 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872};
873
874class CreateSdpObserverWrapper
875 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
876 public:
877 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
878 ConstraintsWrapper* constraints)
879 : SdpObserverWrapper(jni, j_observer, constraints) {}
880
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000881 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000882 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 SdpObserverWrapper::OnFailure(std::string("Create"), error);
884 }
885};
886
887class SetSdpObserverWrapper
888 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
889 public:
890 SetSdpObserverWrapper(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("Set"), error);
897 }
898};
899
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000900// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
901// and dispatching the callback from C++ back to Java.
902class DataChannelObserverWrapper : public DataChannelObserver {
903 public:
904 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
905 : j_observer_global_(jni, j_observer),
906 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000907 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000908 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
909 "onStateChange", "()V")),
910 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
911 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000912 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
913 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
914 }
915
916 virtual ~DataChannelObserverWrapper() {}
917
918 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000919 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000920 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000921 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000922 }
923
924 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000925 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000926 jobject byte_buffer =
927 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
928 buffer.data.length());
929 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
930 byte_buffer, buffer.binary);
931 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000932 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000933 }
934
935 private:
936 JNIEnv* jni() {
937 return AttachCurrentThreadIfNeeded();
938 }
939
940 const ScopedGlobalRef<jobject> j_observer_global_;
941 const ScopedGlobalRef<jclass> j_observer_class_;
942 const ScopedGlobalRef<jclass> j_buffer_class_;
943 const jmethodID j_on_state_change_mid_;
944 const jmethodID j_on_message_mid_;
945 const jmethodID j_buffer_ctor_;
946};
947
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
949// dispatching the callback from C++ back to Java.
950class StatsObserverWrapper : public StatsObserver {
951 public:
952 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000953 : j_observer_global_(jni, j_observer),
954 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
955 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000957 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000958 "(Ljava/lang/String;Ljava/lang/String;D"
959 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000960 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961 jni, "org/webrtc/StatsReport$Value")),
962 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000963 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000964 "(Ljava/lang/String;Ljava/lang/String;)V")) {
965 }
966
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000967 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000968
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000969 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000970 ScopedLocalRefFrame local_ref_frame(jni());
971 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000972 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
973 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000974 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000975 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976 }
977
978 private:
979 jobjectArray ReportsToJava(
980 JNIEnv* jni, const std::vector<StatsReport>& reports) {
981 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000982 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000984 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000986 jstring j_id = JavaStringFromStdString(jni, report.id);
987 jstring j_type = JavaStringFromStdString(jni, report.type);
988 jobjectArray j_values = ValuesToJava(jni, report.values);
989 jobject j_report = jni->NewObject(*j_stats_report_class_,
990 j_stats_report_ctor_,
991 j_id,
992 j_type,
993 report.timestamp,
994 j_values);
995 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000996 }
997 return reports_array;
998 }
999
1000 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1001 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001002 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001004 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001006 jstring j_name = JavaStringFromStdString(jni, value.name);
1007 jstring j_value = JavaStringFromStdString(jni, value.value);
1008 jobject j_element_value =
1009 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1010 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001011 }
1012 return j_values;
1013 }
1014
1015 JNIEnv* jni() {
1016 return AttachCurrentThreadIfNeeded();
1017 }
1018
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001019 const ScopedGlobalRef<jobject> j_observer_global_;
1020 const ScopedGlobalRef<jclass> j_observer_class_;
1021 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001023 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024 const jmethodID j_value_ctor_;
1025};
1026
1027// Adapter presenting a cricket::VideoRenderer as a
1028// webrtc::VideoRendererInterface.
1029class VideoRendererWrapper : public VideoRendererInterface {
1030 public:
1031 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1032 if (renderer)
1033 return new VideoRendererWrapper(renderer);
1034 return NULL;
1035 }
1036
1037 virtual ~VideoRendererWrapper() {}
1038
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001039 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001040 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001041 const bool kNotReserved = false; // What does this param mean??
1042 renderer_->SetSize(width, height, kNotReserved);
1043 }
1044
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001045 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001046 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001047 renderer_->RenderFrame(frame);
1048 }
1049
1050 private:
1051 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1052 : renderer_(renderer) {}
1053
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001054 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001055};
1056
1057// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1058// instance.
1059class JavaVideoRendererWrapper : public VideoRendererInterface {
1060 public:
1061 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001062 : j_callbacks_(jni, j_callbacks),
1063 j_set_size_id_(GetMethodID(
1064 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1065 j_render_frame_id_(GetMethodID(
1066 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1067 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1068 j_frame_class_(jni,
1069 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1070 j_frame_ctor_id_(GetMethodID(
1071 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1072 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001073 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001074 }
1075
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001076 virtual ~JavaVideoRendererWrapper() {}
1077
1078 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001079 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001080 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001081 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001082 }
1083
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001084 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001085 ScopedLocalRefFrame local_ref_frame(jni());
1086 jobject j_frame = CricketToJavaFrame(frame);
1087 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001088 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001089 }
1090
1091 private:
1092 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1093 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001094 jintArray strides = jni()->NewIntArray(3);
1095 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001096 strides_array[0] = frame->GetYPitch();
1097 strides_array[1] = frame->GetUPitch();
1098 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001099 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1100 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1101 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001102 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001103 frame->GetYPitch() * frame->GetHeight());
1104 jobject u_buffer = jni()->NewDirectByteBuffer(
1105 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1106 jobject v_buffer = jni()->NewDirectByteBuffer(
1107 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1108 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1109 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1110 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001112 *j_frame_class_, j_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001113 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001114 }
1115
1116 JNIEnv* jni() {
1117 return AttachCurrentThreadIfNeeded();
1118 }
1119
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001120 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001121 jmethodID j_set_size_id_;
1122 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001123 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001125 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126};
1127
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001128#ifdef ANDROID
1129// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1130// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1131// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001133#include <android/log.h>
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001134//#define TRACK_BUFFER_TIMING
1135#define TAG "MediaCodecVideo"
1136#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001137#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1138#else
1139#define ALOGV(...)
1140#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001141#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1142#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001143
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001144// Color formats supported by encoder - should mirror supportedColorList
1145// from MediaCodecVideoEncoder.java
1146enum COLOR_FORMATTYPE {
1147 COLOR_FormatYUV420Planar = 0x13,
1148 COLOR_FormatYUV420SemiPlanar = 0x15,
1149 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1150 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1151 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1152 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1153 // but requires some (16, 32?) byte alignment.
1154 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1155};
1156
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001157// Arbitrary interval to poll the codec for new outputs.
1158enum { kMediaCodecPollMs = 10 };
1159
1160// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1161// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1162// HW-backed video encode. This C++ class is implemented as a very thin shim,
1163// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1164// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1165// thread, currently the libjingle Worker thread.
1166class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001167 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001168 public:
1169 virtual ~MediaCodecVideoEncoder();
1170 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1171
1172 // webrtc::VideoEncoder implementation. Everything trampolines to
1173 // |codec_thread_| for execution.
1174 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1175 int32_t /* number_of_cores */,
1176 uint32_t /* max_payload_size */) OVERRIDE;
1177 virtual int32_t Encode(
1178 const webrtc::I420VideoFrame& input_image,
1179 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1180 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1181 virtual int32_t RegisterEncodeCompleteCallback(
1182 webrtc::EncodedImageCallback* callback) OVERRIDE;
1183 virtual int32_t Release() OVERRIDE;
1184 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1185 int /* rtt */) OVERRIDE;
1186 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1187
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001188 // rtc::MessageHandler implementation.
1189 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001190
1191 private:
1192 // CHECK-fail if not running on |codec_thread_|.
1193 void CheckOnCodecThread();
1194
1195 // Release() and InitEncode() in an attempt to restore the codec to an
1196 // operable state. Necessary after all manner of OMX-layer errors.
1197 void ResetCodec();
1198
1199 // Implementation of webrtc::VideoEncoder methods above, all running on the
1200 // codec thread exclusively.
1201 //
1202 // If width==0 then this is assumed to be a re-initialization and the
1203 // previously-current values are reused instead of the passed parameters
1204 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001205 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001206 int32_t EncodeOnCodecThread(
1207 const webrtc::I420VideoFrame& input_image,
1208 const std::vector<webrtc::VideoFrameType>* frame_types);
1209 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1210 webrtc::EncodedImageCallback* callback);
1211 int32_t ReleaseOnCodecThread();
1212 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1213
1214 // Reset parameters valid between InitEncode() & Release() (see below).
1215 void ResetParameters(JNIEnv* jni);
1216
1217 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1218 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1219 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1220 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1221 jlong GetOutputBufferInfoPresentationTimestampUs(
1222 JNIEnv* jni,
1223 jobject j_output_buffer_info);
1224
1225 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1226 // true on success.
1227 bool DeliverPendingOutputs(JNIEnv* jni);
1228
1229 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1230 // |codec_thread_| synchronously.
1231 webrtc::EncodedImageCallback* callback_;
1232
1233 // State that is constant for the lifetime of this object once the ctor
1234 // returns.
1235 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1236 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1237 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1238 jmethodID j_init_encode_method_;
1239 jmethodID j_dequeue_input_buffer_method_;
1240 jmethodID j_encode_method_;
1241 jmethodID j_release_method_;
1242 jmethodID j_set_rates_method_;
1243 jmethodID j_dequeue_output_buffer_method_;
1244 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001245 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001246 jfieldID j_info_index_field_;
1247 jfieldID j_info_buffer_field_;
1248 jfieldID j_info_is_key_frame_field_;
1249 jfieldID j_info_presentation_timestamp_us_field_;
1250
1251 // State that is valid only between InitEncode() and the next Release().
1252 // Touched only on codec_thread_ so no explicit synchronization necessary.
1253 int width_; // Frame width in pixels.
1254 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001255 bool inited_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001256 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001257 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001258 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001259 int frames_received_; // Number of frames received by encoder.
1260 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001261 int frames_in_queue_; // Number of frames in encoder queue.
1262 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1263 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001264 // Frame size in bytes fed to MediaCodec.
1265 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001266 // True only when between a callback_->Encoded() call return a positive value
1267 // and the next Encode() call being ignored.
1268 bool drop_next_input_frame_;
1269 // Global references; must be deleted in Release().
1270 std::vector<jobject> input_buffers_;
1271};
1272
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001273MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1274 // We depend on ResetParameters() to ensure no more callbacks to us after we
1275 // are deleted, so assert it here.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001276 CHECK(width_ == 0) << "Release() should have been called";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001277}
1278
1279MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1280 : callback_(NULL),
1281 codec_thread_(new Thread()),
1282 j_media_codec_video_encoder_class_(
1283 jni,
1284 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1285 j_media_codec_video_encoder_(
1286 jni,
1287 jni->NewObject(*j_media_codec_video_encoder_class_,
1288 GetMethodID(jni,
1289 *j_media_codec_video_encoder_class_,
1290 "<init>",
1291 "()V"))) {
1292 ScopedLocalRefFrame local_ref_frame(jni);
1293 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1294 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1295 // 2732 means that deadlocks abound. This class synchronously trampolines
1296 // to |codec_thread_|, so if anything else can be coming to _us_ from
1297 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1298 // in the bug, we have a problem. For now work around that with a dedicated
1299 // thread.
1300 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001301 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001302
1303 ResetParameters(jni);
1304
1305 jclass j_output_buffer_info_class =
1306 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1307 j_init_encode_method_ = GetMethodID(jni,
1308 *j_media_codec_video_encoder_class_,
1309 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001310 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001311 j_dequeue_input_buffer_method_ = GetMethodID(
1312 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1313 j_encode_method_ = GetMethodID(
1314 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1315 j_release_method_ =
1316 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1317 j_set_rates_method_ = GetMethodID(
1318 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1319 j_dequeue_output_buffer_method_ =
1320 GetMethodID(jni,
1321 *j_media_codec_video_encoder_class_,
1322 "dequeueOutputBuffer",
1323 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1324 j_release_output_buffer_method_ = GetMethodID(
1325 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1326
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001327 j_color_format_field_ =
1328 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001329 j_info_index_field_ =
1330 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1331 j_info_buffer_field_ = GetFieldID(
1332 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1333 j_info_is_key_frame_field_ =
1334 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1335 j_info_presentation_timestamp_us_field_ = GetFieldID(
1336 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001337 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001338}
1339
1340int32_t MediaCodecVideoEncoder::InitEncode(
1341 const webrtc::VideoCodec* codec_settings,
1342 int32_t /* number_of_cores */,
1343 uint32_t /* max_payload_size */) {
1344 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001345 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001346
1347 return codec_thread_->Invoke<int32_t>(
1348 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1349 this,
1350 codec_settings->width,
1351 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001352 codec_settings->startBitrate,
1353 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001354}
1355
1356int32_t MediaCodecVideoEncoder::Encode(
1357 const webrtc::I420VideoFrame& frame,
1358 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1359 const std::vector<webrtc::VideoFrameType>* frame_types) {
1360 return codec_thread_->Invoke<int32_t>(Bind(
1361 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1362}
1363
1364int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1365 webrtc::EncodedImageCallback* callback) {
1366 return codec_thread_->Invoke<int32_t>(
1367 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1368 this,
1369 callback));
1370}
1371
1372int32_t MediaCodecVideoEncoder::Release() {
1373 return codec_thread_->Invoke<int32_t>(
1374 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1375}
1376
1377int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1378 int /* rtt */) {
1379 return WEBRTC_VIDEO_CODEC_OK;
1380}
1381
1382int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1383 uint32_t frame_rate) {
1384 return codec_thread_->Invoke<int32_t>(
1385 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1386 this,
1387 new_bit_rate,
1388 frame_rate));
1389}
1390
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001391void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001392 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1393 ScopedLocalRefFrame local_ref_frame(jni);
1394
1395 // We only ever send one message to |this| directly (not through a Bind()'d
1396 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001397 CHECK(!msg->message_id) << "Unexpected message!";
1398 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001399 CheckOnCodecThread();
1400
1401 // It would be nice to recover from a failure here if one happened, but it's
1402 // unclear how to signal such a failure to the app, so instead we stay silent
1403 // about it and let the next app-called API method reveal the borkedness.
1404 DeliverPendingOutputs(jni);
1405 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1406}
1407
1408void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001409 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1410 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001411}
1412
1413void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001414 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001415 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1416 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001417 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0, 0))
1418 != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001419 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1420 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1421 // https://code.google.com/p/webrtc/issues/detail?id=2920
1422 }
1423}
1424
1425int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001426 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001427 CheckOnCodecThread();
1428 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1429 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001430 ALOGD("InitEncodeOnCodecThread %d x %d", width, height);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001431
1432 if (width == 0) {
1433 width = width_;
1434 height = height_;
1435 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001436 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001437 }
1438
1439 width_ = width;
1440 height_ = height;
1441 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001442 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001443 yuv_size_ = width_ * height_ * 3 / 2;
1444 frames_received_ = 0;
1445 frames_dropped_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001446 frames_in_queue_ = 0;
1447 last_input_timestamp_ms_ = -1;
1448 last_output_timestamp_ms_ = -1;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001449 // We enforce no extra stride/padding in the format creation step.
1450 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1451 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1452 j_init_encode_method_,
1453 width_,
1454 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001455 kbps,
1456 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001457 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001458 if (IsNull(jni, input_buffers))
1459 return WEBRTC_VIDEO_CODEC_ERROR;
1460
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001461 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001462 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1463 j_color_format_field_)) {
1464 case COLOR_FormatYUV420Planar:
1465 encoder_fourcc_ = libyuv::FOURCC_YU12;
1466 break;
1467 case COLOR_FormatYUV420SemiPlanar:
1468 case COLOR_QCOM_FormatYUV420SemiPlanar:
1469 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1470 encoder_fourcc_ = libyuv::FOURCC_NV12;
1471 break;
1472 default:
1473 LOG(LS_ERROR) << "Wrong color format.";
1474 return WEBRTC_VIDEO_CODEC_ERROR;
1475 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001476 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001477 CHECK(input_buffers_.empty())
1478 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001479 input_buffers_.resize(num_input_buffers);
1480 for (size_t i = 0; i < num_input_buffers; ++i) {
1481 input_buffers_[i] =
1482 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001483 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001484 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001485 CHECK_EXCEPTION(jni);
1486 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001487 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001488 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001489
1490 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1491 return WEBRTC_VIDEO_CODEC_OK;
1492}
1493
1494int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1495 const webrtc::I420VideoFrame& frame,
1496 const std::vector<webrtc::VideoFrameType>* frame_types) {
1497 CheckOnCodecThread();
1498 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1499 ScopedLocalRefFrame local_ref_frame(jni);
1500
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001501 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001502 if (!DeliverPendingOutputs(jni)) {
1503 ResetCodec();
1504 // Continue as if everything's fine.
1505 }
1506
1507 if (drop_next_input_frame_) {
1508 drop_next_input_frame_ = false;
1509 return WEBRTC_VIDEO_CODEC_OK;
1510 }
1511
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001512 CHECK(frame_types->size() == 1) << "Unexpected stream count";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001513 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1514
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001515 CHECK(frame.width() == width_) << "Unexpected resolution change";
1516 CHECK(frame.height() == height_) << "Unexpected resolution change";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001517
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001518 // Check if we accumulated too many frames in encoder input buffers
1519 // so the encoder latency exceeds 100ms and drop frame if so.
1520 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ > 0 &&
1521 last_output_timestamp_ms_ > 0) {
1522 int encoder_latency_ms = last_input_timestamp_ms_ -
1523 last_output_timestamp_ms_;
1524 if (encoder_latency_ms > 100) {
1525 ALOGV("Drop frame - encoder is behind by %d ms. Q size: %d",
1526 encoder_latency_ms, frames_in_queue_);
1527 frames_dropped_++;
1528 return WEBRTC_VIDEO_CODEC_OK;
1529 }
1530 }
1531
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001532 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1533 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001534 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001535 if (j_input_buffer_index == -1) {
1536 // Video codec falls behind - no input buffer available.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001537 ALOGV("Drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001538 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001539 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001540 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001541 if (j_input_buffer_index == -2) {
1542 ResetCodec();
1543 return WEBRTC_VIDEO_CODEC_ERROR;
1544 }
1545
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001546 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001547 frames_received_, j_input_buffer_index, frame.render_time_ms());
1548
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001549 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001550 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001551 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001552 CHECK_EXCEPTION(jni);
1553 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001554 CHECK(!libyuv::ConvertFromI420(
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001555 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1556 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1557 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1558 yuv_buffer, width_, width_, height_, encoder_fourcc_))
1559 << "ConvertFromI420 failed";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001560 jlong timestamp_us = frame.render_time_ms() * 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001561 last_input_timestamp_ms_ = frame.render_time_ms();
1562 frames_in_queue_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001563 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1564 j_encode_method_,
1565 key_frame,
1566 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001567 yuv_size_,
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001568 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001569 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001570 if (!encode_status || !DeliverPendingOutputs(jni)) {
1571 ResetCodec();
1572 return WEBRTC_VIDEO_CODEC_ERROR;
1573 }
1574
1575 return WEBRTC_VIDEO_CODEC_OK;
1576}
1577
1578int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1579 webrtc::EncodedImageCallback* callback) {
1580 CheckOnCodecThread();
1581 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1582 ScopedLocalRefFrame local_ref_frame(jni);
1583 callback_ = callback;
1584 return WEBRTC_VIDEO_CODEC_OK;
1585}
1586
1587int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001588 if (!inited_)
1589 return WEBRTC_VIDEO_CODEC_OK;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001590 CheckOnCodecThread();
1591 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001592 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1593 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001594 ScopedLocalRefFrame local_ref_frame(jni);
1595 for (size_t i = 0; i < input_buffers_.size(); ++i)
1596 jni->DeleteGlobalRef(input_buffers_[i]);
1597 input_buffers_.clear();
1598 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1599 ResetParameters(jni);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001600 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001601 return WEBRTC_VIDEO_CODEC_OK;
1602}
1603
1604int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1605 uint32_t frame_rate) {
1606 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001607 if (last_set_bitrate_kbps_ == new_bit_rate &&
1608 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001609 return WEBRTC_VIDEO_CODEC_OK;
1610 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001611 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1612 ScopedLocalRefFrame local_ref_frame(jni);
1613 last_set_bitrate_kbps_ = new_bit_rate;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001614 last_set_fps_ = frame_rate;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001615 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1616 j_set_rates_method_,
1617 new_bit_rate,
1618 frame_rate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001619 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001620 if (!ret) {
1621 ResetCodec();
1622 return WEBRTC_VIDEO_CODEC_ERROR;
1623 }
1624 return WEBRTC_VIDEO_CODEC_OK;
1625}
1626
1627void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001628 rtc::MessageQueueManager::Clear(this);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001629 width_ = 0;
1630 height_ = 0;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001631 yuv_size_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001632 drop_next_input_frame_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001633 inited_ = false;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001634 CHECK(input_buffers_.empty())
1635 << "ResetParameters called while holding input_buffers_!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001636}
1637
1638int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1639 JNIEnv* jni,
1640 jobject j_output_buffer_info) {
1641 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1642}
1643
1644jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1645 JNIEnv* jni,
1646 jobject j_output_buffer_info) {
1647 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1648}
1649
1650bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1651 JNIEnv* jni,
1652 jobject j_output_buffer_info) {
1653 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1654}
1655
1656jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1657 JNIEnv* jni,
1658 jobject j_output_buffer_info) {
1659 return GetLongField(
1660 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1661}
1662
1663bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1664 while (true) {
1665 jobject j_output_buffer_info = jni->CallObjectMethod(
1666 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001667 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001668 if (IsNull(jni, j_output_buffer_info))
1669 break;
1670
1671 int output_buffer_index =
1672 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1673 if (output_buffer_index == -1) {
1674 ResetCodec();
1675 return false;
1676 }
1677
1678 jlong capture_time_ms =
1679 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1680 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001681 last_output_timestamp_ms_ = capture_time_ms;
1682 frames_in_queue_--;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001683 ALOGV("Encoder got output buffer # %d. TS: %lld. Latency: %lld",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001684 output_buffer_index, last_output_timestamp_ms_,
1685 last_input_timestamp_ms_ - last_output_timestamp_ms_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001686
1687 int32_t callback_status = 0;
1688 if (callback_) {
1689 jobject j_output_buffer =
1690 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1691 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1692 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1693 uint8* payload = reinterpret_cast<uint8_t*>(
1694 jni->GetDirectBufferAddress(j_output_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001695 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001696 scoped_ptr<webrtc::EncodedImage> image(
1697 new webrtc::EncodedImage(payload, payload_size, payload_size));
1698 image->_encodedWidth = width_;
1699 image->_encodedHeight = height_;
1700 // Convert capture time to 90 kHz RTP timestamp.
1701 image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
1702 image->capture_time_ms_ = capture_time_ms;
1703 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1704 image->_completeFrame = true;
1705
1706 webrtc::CodecSpecificInfo info;
1707 memset(&info, 0, sizeof(info));
1708 info.codecType = kVideoCodecVP8;
1709 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1710 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1711 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1712
1713 // Generate a header describing a single fragment.
1714 webrtc::RTPFragmentationHeader header;
1715 memset(&header, 0, sizeof(header));
1716 header.VerifyAndAllocateFragmentationHeader(1);
1717 header.fragmentationOffset[0] = 0;
1718 header.fragmentationLength[0] = image->_length;
1719 header.fragmentationPlType[0] = 0;
1720 header.fragmentationTimeDiff[0] = 0;
1721
1722 callback_status = callback_->Encoded(*image, &info, &header);
1723 }
1724
1725 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1726 j_release_output_buffer_method_,
1727 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001728 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001729 if (!success) {
1730 ResetCodec();
1731 return false;
1732 }
1733
1734 if (callback_status > 0)
1735 drop_next_input_frame_ = true;
1736 // Theoretically could handle callback_status<0 here, but unclear what that
1737 // would mean for us.
1738 }
1739
1740 return true;
1741}
1742
1743// Simplest-possible implementation of an encoder factory, churns out
1744// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1745class MediaCodecVideoEncoderFactory
1746 : public cricket::WebRtcVideoEncoderFactory {
1747 public:
1748 MediaCodecVideoEncoderFactory();
1749 virtual ~MediaCodecVideoEncoderFactory();
1750
1751 // WebRtcVideoEncoderFactory implementation.
1752 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1753 OVERRIDE;
1754 virtual void AddObserver(Observer* observer) OVERRIDE;
1755 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1756 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1757 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1758
1759 private:
1760 // Empty if platform support is lacking, const after ctor returns.
1761 std::vector<VideoCodec> supported_codecs_;
1762};
1763
1764MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1765 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1766 ScopedLocalRefFrame local_ref_frame(jni);
1767 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1768 bool is_platform_supported = jni->CallStaticBooleanMethod(
1769 j_encoder_class,
1770 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001771 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001772 if (!is_platform_supported)
1773 return;
1774
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001775 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1776 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1777 // reasonable defaults.
1778 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001779 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001780}
1781
1782MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1783
1784webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1785 webrtc::VideoCodecType type) {
1786 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1787 return NULL;
1788 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1789}
1790
1791// Since the available codec list is never going to change, we ignore the
1792// Observer-related interface here.
1793void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1794void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1795
1796const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1797MediaCodecVideoEncoderFactory::codecs() const {
1798 return supported_codecs_;
1799}
1800
1801void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1802 webrtc::VideoEncoder* encoder) {
1803 delete encoder;
1804}
1805
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001806class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001807 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001808 public:
1809 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1810 virtual ~MediaCodecVideoDecoder();
1811
1812 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1813 int32_t numberOfCores) OVERRIDE;
1814
1815 virtual int32_t
1816 Decode(const EncodedImage& inputImage, bool missingFrames,
1817 const RTPFragmentationHeader* fragmentation,
1818 const CodecSpecificInfo* codecSpecificInfo = NULL,
1819 int64_t renderTimeMs = -1) OVERRIDE;
1820
1821 virtual int32_t RegisterDecodeCompleteCallback(
1822 DecodedImageCallback* callback) OVERRIDE;
1823
1824 virtual int32_t Release() OVERRIDE;
1825
1826 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001827 // rtc::MessageHandler implementation.
1828 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001829
1830 private:
1831 // CHECK-fail if not running on |codec_thread_|.
1832 void CheckOnCodecThread();
1833
1834 int32_t InitDecodeOnCodecThread();
1835 int32_t ReleaseOnCodecThread();
1836 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
1837
1838 bool key_frame_required_;
1839 bool inited_;
1840 VideoCodec codec_;
1841 I420VideoFrame decoded_image_;
1842 DecodedImageCallback* callback_;
1843 int frames_received_; // Number of frames received by decoder.
1844
1845 // State that is constant for the lifetime of this object once the ctor
1846 // returns.
1847 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1848 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
1849 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
1850 jmethodID j_init_decode_method_;
1851 jmethodID j_release_method_;
1852 jmethodID j_dequeue_input_buffer_method_;
1853 jmethodID j_queue_input_buffer_method_;
1854 jmethodID j_dequeue_output_buffer_method_;
1855 jmethodID j_release_output_buffer_method_;
1856 jfieldID j_input_buffers_field_;
1857 jfieldID j_output_buffers_field_;
1858 jfieldID j_color_format_field_;
1859 jfieldID j_width_field_;
1860 jfieldID j_height_field_;
1861 jfieldID j_stride_field_;
1862 jfieldID j_slice_height_field_;
1863
1864 // Global references; must be deleted in Release().
1865 std::vector<jobject> input_buffers_;
1866};
1867
1868MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni) :
1869 key_frame_required_(true),
1870 inited_(false),
1871 codec_thread_(new Thread()),
1872 j_media_codec_video_decoder_class_(
1873 jni,
1874 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
1875 j_media_codec_video_decoder_(
1876 jni,
1877 jni->NewObject(*j_media_codec_video_decoder_class_,
1878 GetMethodID(jni,
1879 *j_media_codec_video_decoder_class_,
1880 "<init>",
1881 "()V"))) {
1882 ScopedLocalRefFrame local_ref_frame(jni);
1883 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001884 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001885
1886 j_init_decode_method_ = GetMethodID(jni,
1887 *j_media_codec_video_decoder_class_,
1888 "initDecode", "(II)Z");
1889 j_release_method_ =
1890 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
1891 j_dequeue_input_buffer_method_ = GetMethodID(
1892 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
1893 j_queue_input_buffer_method_ = GetMethodID(
1894 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
1895 j_dequeue_output_buffer_method_ = GetMethodID(
1896 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer", "()I");
1897 j_release_output_buffer_method_ = GetMethodID(
1898 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(I)Z");
1899
1900 j_input_buffers_field_ = GetFieldID(
1901 jni, *j_media_codec_video_decoder_class_,
1902 "inputBuffers", "[Ljava/nio/ByteBuffer;");
1903 j_output_buffers_field_ = GetFieldID(
1904 jni, *j_media_codec_video_decoder_class_,
1905 "outputBuffers", "[Ljava/nio/ByteBuffer;");
1906 j_color_format_field_ = GetFieldID(
1907 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
1908 j_width_field_ = GetFieldID(
1909 jni, *j_media_codec_video_decoder_class_, "width", "I");
1910 j_height_field_ = GetFieldID(
1911 jni, *j_media_codec_video_decoder_class_, "height", "I");
1912 j_stride_field_ = GetFieldID(
1913 jni, *j_media_codec_video_decoder_class_, "stride", "I");
1914 j_slice_height_field_ = GetFieldID(
1915 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
1916
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001917 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001918 memset(&codec_, 0, sizeof(codec_));
1919}
1920
1921MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
1922 Release();
1923}
1924
1925int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
1926 int32_t numberOfCores) {
1927 if (inst == NULL) {
1928 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
1929 }
1930 int ret_val = Release();
1931 if (ret_val < 0) {
1932 return ret_val;
1933 }
1934 // Save VideoCodec instance for later.
1935 if (&codec_ != inst) {
1936 codec_ = *inst;
1937 }
1938 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
1939
1940 // Always start with a complete key frame.
1941 key_frame_required_ = true;
1942 frames_received_ = 0;
1943
1944 // Call Java init.
1945 return codec_thread_->Invoke<int32_t>(
1946 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
1947}
1948
1949int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
1950 CheckOnCodecThread();
1951 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1952 ScopedLocalRefFrame local_ref_frame(jni);
1953 ALOGD("InitDecodeOnCodecThread: %d x %d. FPS: %d",
1954 codec_.width, codec_.height, codec_.maxFramerate);
1955
1956 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
1957 j_init_decode_method_,
1958 codec_.width,
1959 codec_.height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001960 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001961 if (!success)
1962 return WEBRTC_VIDEO_CODEC_ERROR;
1963 inited_ = true;
1964
1965 jobjectArray input_buffers = (jobjectArray)GetObjectField(
1966 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
1967 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1968
1969 input_buffers_.resize(num_input_buffers);
1970 for (size_t i = 0; i < num_input_buffers; ++i) {
1971 input_buffers_[i] =
1972 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001973 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001974 }
1975 return WEBRTC_VIDEO_CODEC_OK;
1976}
1977
1978int32_t MediaCodecVideoDecoder::Release() {
1979 return codec_thread_->Invoke<int32_t>(
1980 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
1981}
1982
1983int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
1984 if (!inited_)
1985 return WEBRTC_VIDEO_CODEC_OK;
1986 CheckOnCodecThread();
1987 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1988 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
1989 ScopedLocalRefFrame local_ref_frame(jni);
1990 for (size_t i = 0; i < input_buffers_.size(); ++i)
1991 jni->DeleteGlobalRef(input_buffers_[i]);
1992 input_buffers_.clear();
1993 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001994 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001995 inited_ = false;
1996 return WEBRTC_VIDEO_CODEC_OK;
1997}
1998
1999
2000void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002001 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2002 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002003}
2004
2005int32_t MediaCodecVideoDecoder::Decode(
2006 const EncodedImage& inputImage,
2007 bool missingFrames,
2008 const RTPFragmentationHeader* fragmentation,
2009 const CodecSpecificInfo* codecSpecificInfo,
2010 int64_t renderTimeMs) {
2011 if (!inited_) {
2012 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2013 }
2014 if (callback_ == NULL) {
2015 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2016 }
2017 if (inputImage._buffer == NULL && inputImage._length > 0) {
2018 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2019 }
2020 // Check if encoded frame dimension has changed.
2021 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2022 (inputImage._encodedWidth != codec_.width ||
2023 inputImage._encodedHeight != codec_.height)) {
2024 codec_.width = inputImage._encodedWidth;
2025 codec_.height = inputImage._encodedHeight;
2026 InitDecode(&codec_, 1);
2027 }
2028
2029 // Always start with a complete key frame.
2030 if (key_frame_required_) {
2031 if (inputImage._frameType != webrtc::kKeyFrame) {
2032 return WEBRTC_VIDEO_CODEC_ERROR;
2033 }
2034 if (!inputImage._completeFrame) {
2035 return WEBRTC_VIDEO_CODEC_ERROR;
2036 }
2037 key_frame_required_ = false;
2038 }
2039 if (inputImage._length == 0) {
2040 return WEBRTC_VIDEO_CODEC_ERROR;
2041 }
2042
2043 return codec_thread_->Invoke<int32_t>(Bind(
2044 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2045}
2046
2047int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2048 const EncodedImage& inputImage) {
2049 static uint8_t yVal_ = 0x7f;
2050
2051 CheckOnCodecThread();
2052 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2053 ScopedLocalRefFrame local_ref_frame(jni);
2054
2055 // Get input buffer.
2056 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2057 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002058 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002059 if (j_input_buffer_index < 0) {
2060 ALOGE("dequeueInputBuffer error");
2061 Reset();
2062 return WEBRTC_VIDEO_CODEC_ERROR;
2063 }
2064
2065 // Copy encoded data to Java ByteBuffer.
2066 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2067 uint8* buffer =
2068 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002069 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002070 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002071 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002072 if (buffer_capacity < inputImage._length) {
2073 ALOGE("Input frame size %d is bigger than buffer size %d.",
2074 inputImage._length, buffer_capacity);
2075 Reset();
2076 return WEBRTC_VIDEO_CODEC_ERROR;
2077 }
2078 ALOGV("Decode frame # %d. Buffer # %d. Size: %d",
2079 frames_received_, j_input_buffer_index, inputImage._length);
2080 memcpy(buffer, inputImage._buffer, inputImage._length);
2081
2082 // Feed input to decoder.
2083 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2084 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2085 j_queue_input_buffer_method_,
2086 j_input_buffer_index,
2087 inputImage._length,
2088 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002089 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002090 if (!success) {
2091 ALOGE("queueInputBuffer error");
2092 Reset();
2093 return WEBRTC_VIDEO_CODEC_ERROR;
2094 }
2095
2096 // Get output index.
2097 int j_output_buffer_index =
2098 jni->CallIntMethod(*j_media_codec_video_decoder_,
2099 j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002100 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002101 if (j_output_buffer_index < 0) {
2102 ALOGE("dequeueOutputBuffer error");
2103 Reset();
2104 return WEBRTC_VIDEO_CODEC_ERROR;
2105 }
2106
2107 // Extract data from Java ByteBuffer.
2108 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2109 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2110 jobject output_buffer =
2111 jni->GetObjectArrayElement(output_buffers, j_output_buffer_index);
2112 buffer_capacity = jni->GetDirectBufferCapacity(output_buffer);
2113 uint8_t* payload =
2114 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(output_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002115 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002116 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2117 j_color_format_field_);
2118 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2119 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2120 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2121 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2122 j_slice_height_field_);
2123 if (buffer_capacity < width * height * 3 / 2) {
2124 ALOGE("Insufficient output buffer capacity: %d", buffer_capacity);
2125 Reset();
2126 return WEBRTC_VIDEO_CODEC_ERROR;
2127 }
2128 ALOGV("Decoder got output buffer %d x %d. %d x %d. Color: 0x%x. Size: %d",
2129 width, height, stride, slice_height, color_format, buffer_capacity);
2130
2131 if (color_format == COLOR_FormatYUV420Planar) {
2132 decoded_image_.CreateFrame(
2133 stride * slice_height, payload,
2134 (stride * slice_height) / 4, payload + (stride * slice_height),
2135 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2136 width, height,
2137 stride, stride / 2, stride / 2);
2138 } else {
2139 // All other supported formats are nv12.
2140 decoded_image_.CreateEmptyFrame(width, height, width, width / 2, width / 2);
2141 libyuv::NV12ToI420(
2142 payload, stride,
2143 payload + stride * slice_height, stride,
2144 decoded_image_.buffer(webrtc::kYPlane),
2145 decoded_image_.stride(webrtc::kYPlane),
2146 decoded_image_.buffer(webrtc::kUPlane),
2147 decoded_image_.stride(webrtc::kUPlane),
2148 decoded_image_.buffer(webrtc::kVPlane),
2149 decoded_image_.stride(webrtc::kVPlane),
2150 width, height);
2151 }
2152
2153 // Return output buffer back to codec.
2154 success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2155 j_release_output_buffer_method_,
2156 j_output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002157 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002158 if (!success) {
2159 ALOGE("releaseOutputBuffer error");
2160 Reset();
2161 return WEBRTC_VIDEO_CODEC_ERROR;
2162 }
2163
2164 // Callback.
2165 decoded_image_.set_timestamp(inputImage._timeStamp);
2166 decoded_image_.set_ntp_time_ms(inputImage.ntp_time_ms_);
2167 frames_received_++;
2168 return callback_->Decoded(decoded_image_);
2169}
2170
2171int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2172 DecodedImageCallback* callback) {
2173 callback_ = callback;
2174 return WEBRTC_VIDEO_CODEC_OK;
2175}
2176
2177int32_t MediaCodecVideoDecoder::Reset() {
2178 ALOGD("DecoderReset");
2179 if (!inited_) {
2180 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2181 }
2182 return InitDecode(&codec_, 1);
2183}
2184
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002185void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002186}
2187
2188class MediaCodecVideoDecoderFactory
2189 : public cricket::WebRtcVideoDecoderFactory {
2190 public:
2191 MediaCodecVideoDecoderFactory();
2192 virtual ~MediaCodecVideoDecoderFactory();
2193 // WebRtcVideoDecoderFactory implementation.
2194 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2195 webrtc::VideoCodecType type) OVERRIDE;
2196
2197 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2198
2199 private:
2200 bool is_platform_supported_;
2201};
2202
2203MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2204 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2205 ScopedLocalRefFrame local_ref_frame(jni);
2206 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2207 is_platform_supported_ = jni->CallStaticBooleanMethod(
2208 j_decoder_class,
2209 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002210 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002211}
2212
2213MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2214
2215webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2216 webrtc::VideoCodecType type) {
2217 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2218 return NULL;
2219 }
2220 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2221}
2222
2223
2224void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2225 webrtc::VideoDecoder* decoder) {
2226 delete decoder;
2227}
2228
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002229#endif // ANDROID
2230
2231} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002232
2233// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2234// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2235#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2236 Java_org_webrtc_##name
2237
2238extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002239 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002240 g_jvm = jvm;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002241 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002242
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002243 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002244
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002245 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002246
2247 JNIEnv* jni;
2248 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2249 return -1;
2250 g_class_reference_holder = new ClassReferenceHolder(jni);
2251
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002252 return JNI_VERSION_1_6;
2253}
2254
2255extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002256 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002257 delete g_class_reference_holder;
2258 g_class_reference_holder = NULL;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002259 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002260 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002261}
2262
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002263static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002264 jfieldID native_dc_id = GetFieldID(jni,
2265 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2266 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002267 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002268}
2269
2270JOW(jlong, DataChannel_registerObserverNative)(
2271 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002272 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002273 new DataChannelObserverWrapper(jni, j_observer));
2274 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002275 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002276}
2277
2278JOW(void, DataChannel_unregisterObserverNative)(
2279 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2280 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2281 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2282}
2283
2284JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2285 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2286}
2287
2288JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2289 return JavaEnumFromIndex(
2290 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2291}
2292
2293JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2294 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002295 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2296 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002297 return static_cast<jlong>(buffered_amount);
2298}
2299
2300JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2301 ExtractNativeDC(jni, j_dc)->Close();
2302}
2303
2304JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2305 jbyteArray data, jboolean binary) {
2306 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2307 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002308 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002309 binary));
2310 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2311 return ret;
2312}
2313
2314JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002315 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002316}
2317
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002318JOW(void, Logging_nativeEnableTracing)(
2319 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2320 jint nativeSeverity) {
2321 std::string path = JavaToStdString(jni, j_path);
2322 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002323 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002324#ifdef ANDROID
2325 if (path != "logcat:") {
2326#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002327 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2328 << "SetTraceFile failed";
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002329#ifdef ANDROID
2330 } else {
2331 // Intentionally leak this to avoid needing to reason about its lifecycle.
2332 // It keeps no state and functions only as a dispatch point.
2333 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2334 }
2335#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002336 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002337 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002338}
2339
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002340JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002341 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002342}
2343
2344JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2345 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2346 delete p;
2347}
2348
2349JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002350 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002351}
2352
2353JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2354 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2355}
2356
2357JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
2358 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2359}
2360
2361JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002362 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002363}
2364
2365JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2366 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002367 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002368 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369}
2370
2371JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2372 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002373 return reinterpret_cast<MediaStreamInterface*>(pointer)
2374 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002375}
2376
2377JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2378 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002379 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002380 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002381}
2382
2383JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2384 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002385 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002386 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002387}
2388
2389JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2390 return JavaStringFromStdString(
2391 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2392}
2393
2394JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002395 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002396}
2397
2398JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2399 JNIEnv * jni, jclass, jobject j_observer) {
2400 return (jlong)new PCOJava(jni, j_observer);
2401}
2402
2403#ifdef ANDROID
2404JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002405 JNIEnv* jni, jclass, jobject context,
2406 jboolean initialize_audio, jboolean initialize_video) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002407 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002408 bool failure = false;
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002409 if (initialize_video)
fischman@webrtc.org95127192014-06-06 18:40:44 +00002410 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002411 if (initialize_audio)
2412 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002413 return !failure;
2414}
2415#endif // ANDROID
2416
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002417// Helper struct for working around the fact that CreatePeerConnectionFactory()
2418// comes in two flavors: either entirely automagical (constructing its own
2419// threads and deleting them on teardown, but no external codec factory support)
2420// or entirely manual (requires caller to delete threads after factory
2421// teardown). This struct takes ownership of its ctor's arguments to present a
2422// single thing for Java to hold and eventually free.
2423class OwnedFactoryAndThreads {
2424 public:
2425 OwnedFactoryAndThreads(Thread* worker_thread,
2426 Thread* signaling_thread,
2427 PeerConnectionFactoryInterface* factory)
2428 : worker_thread_(worker_thread),
2429 signaling_thread_(signaling_thread),
2430 factory_(factory) {}
2431
2432 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2433
2434 PeerConnectionFactoryInterface* factory() { return factory_; }
2435
2436 private:
2437 const scoped_ptr<Thread> worker_thread_;
2438 const scoped_ptr<Thread> signaling_thread_;
2439 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2440};
2441
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002442JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2443 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002444 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2445 // ThreadManager only WrapCurrentThread()s the thread where it is first
2446 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002447 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002448 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002449 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002450 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002451 Thread* worker_thread = new Thread();
2452 worker_thread->SetName("worker_thread", NULL);
2453 Thread* signaling_thread = new Thread();
2454 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002455 CHECK(worker_thread->Start() && signaling_thread->Start())
2456 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002457 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002458 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002459#ifdef ANDROID
2460 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002461 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002462#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002463 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002464 webrtc::CreatePeerConnectionFactory(worker_thread,
2465 signaling_thread,
2466 NULL,
2467 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002468 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002469 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2470 worker_thread, signaling_thread, factory.release());
2471 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002472}
2473
2474JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002475 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002476 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002477}
2478
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002479static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2480 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2481}
2482
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002483JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2484 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002485 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002486 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002487 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002488 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2489 return (jlong)stream.release();
2490}
2491
2492JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2493 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2494 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002495 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002496 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002497 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002498 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002499 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002500 factory->CreateVideoSource(
2501 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2502 constraints.get()));
2503 return (jlong)source.release();
2504}
2505
2506JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2507 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2508 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002509 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002510 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002511 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002512 factory->CreateVideoTrack(
2513 JavaToStdString(jni, id),
2514 reinterpret_cast<VideoSourceInterface*>(native_source)));
2515 return (jlong)track.release();
2516}
2517
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002518JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2519 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2520 scoped_ptr<ConstraintsWrapper> constraints(
2521 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002522 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002523 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002524 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002525 factory->CreateAudioSource(constraints.get()));
2526 return (jlong)source.release();
2527}
2528
2529JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2530 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2531 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002532 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002533 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002534 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002535 JavaToStdString(jni, id),
2536 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002537 return (jlong)track.release();
2538}
2539
2540static void JavaIceServersToJsepIceServers(
2541 JNIEnv* jni, jobject j_ice_servers,
2542 PeerConnectionInterface::IceServers* ice_servers) {
2543 jclass list_class = GetObjectClass(jni, j_ice_servers);
2544 jmethodID iterator_id = GetMethodID(
2545 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2546 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002547 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002548 jmethodID iterator_has_next = GetMethodID(
2549 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2550 jmethodID iterator_next = GetMethodID(
2551 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2552 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002553 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002554 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002555 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002556 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2557 jfieldID j_ice_server_uri_id =
2558 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2559 jfieldID j_ice_server_username_id =
2560 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2561 jfieldID j_ice_server_password_id =
2562 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2563 jstring uri = reinterpret_cast<jstring>(
2564 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2565 jstring username = reinterpret_cast<jstring>(
2566 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2567 jstring password = reinterpret_cast<jstring>(
2568 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2569 PeerConnectionInterface::IceServer server;
2570 server.uri = JavaToStdString(jni, uri);
2571 server.username = JavaToStdString(jni, username);
2572 server.password = JavaToStdString(jni, password);
2573 ice_servers->push_back(server);
2574 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002575 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002576}
2577
2578JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2579 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2580 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002581 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002582 reinterpret_cast<PeerConnectionFactoryInterface*>(
2583 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002584 PeerConnectionInterface::IceServers servers;
2585 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2586 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2587 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002588 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002589 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002590 return (jlong)pc.release();
2591}
2592
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002593static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002594 JNIEnv* jni, jobject j_pc) {
2595 jfieldID native_pc_id = GetFieldID(jni,
2596 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2597 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002598 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002599 reinterpret_cast<PeerConnectionInterface*>(j_p));
2600}
2601
2602JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2603 const SessionDescriptionInterface* sdp =
2604 ExtractNativePC(jni, j_pc)->local_description();
2605 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2606}
2607
2608JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2609 const SessionDescriptionInterface* sdp =
2610 ExtractNativePC(jni, j_pc)->remote_description();
2611 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2612}
2613
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002614JOW(jobject, PeerConnection_createDataChannel)(
2615 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2616 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002617 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002618 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2619 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002620 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2621 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2622 // 32-bit parameter.
2623 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002624 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002625 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2626 jmethodID j_data_channel_ctor = GetMethodID(
2627 jni, j_data_channel_class, "<init>", "(J)V");
2628 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002629 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002630 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002631 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002632 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002633 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002634 return j_channel;
2635}
2636
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002637JOW(void, PeerConnection_createOffer)(
2638 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2639 ConstraintsWrapper* constraints =
2640 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002641 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
2642 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002643 jni, j_observer, constraints));
2644 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2645}
2646
2647JOW(void, PeerConnection_createAnswer)(
2648 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2649 ConstraintsWrapper* constraints =
2650 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002651 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
2652 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002653 jni, j_observer, constraints));
2654 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2655}
2656
2657// Helper to create a SessionDescriptionInterface from a SessionDescription.
2658static SessionDescriptionInterface* JavaSdpToNativeSdp(
2659 JNIEnv* jni, jobject j_sdp) {
2660 jfieldID j_type_id = GetFieldID(
2661 jni, GetObjectClass(jni, j_sdp), "type",
2662 "Lorg/webrtc/SessionDescription$Type;");
2663 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2664 jmethodID j_canonical_form_id = GetMethodID(
2665 jni, GetObjectClass(jni, j_type), "canonicalForm",
2666 "()Ljava/lang/String;");
2667 jstring j_type_string = (jstring)jni->CallObjectMethod(
2668 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002669 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670 std::string std_type = JavaToStdString(jni, j_type_string);
2671
2672 jfieldID j_description_id = GetFieldID(
2673 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2674 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2675 std::string std_description = JavaToStdString(jni, j_description);
2676
2677 return webrtc::CreateSessionDescription(
2678 std_type, std_description, NULL);
2679}
2680
2681JOW(void, PeerConnection_setLocalDescription)(
2682 JNIEnv* jni, jobject j_pc,
2683 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002684 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
2685 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002686 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2687 ExtractNativePC(jni, j_pc)->SetLocalDescription(
2688 observer, JavaSdpToNativeSdp(jni, j_sdp));
2689}
2690
2691JOW(void, PeerConnection_setRemoteDescription)(
2692 JNIEnv* jni, jobject j_pc,
2693 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002694 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
2695 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002696 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2697 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2698 observer, JavaSdpToNativeSdp(jni, j_sdp));
2699}
2700
2701JOW(jboolean, PeerConnection_updateIce)(
2702 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2703 PeerConnectionInterface::IceServers ice_servers;
2704 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002705 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002706 new ConstraintsWrapper(jni, j_constraints));
2707 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2708}
2709
2710JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2711 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2712 jint j_sdp_mline_index, jstring j_candidate_sdp) {
2713 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2714 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002715 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2717 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2718}
2719
2720JOW(jboolean, PeerConnection_nativeAddLocalStream)(
2721 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002722 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002723 new ConstraintsWrapper(jni, j_constraints));
2724 return ExtractNativePC(jni, j_pc)->AddStream(
2725 reinterpret_cast<MediaStreamInterface*>(native_stream),
2726 constraints.get());
2727}
2728
2729JOW(void, PeerConnection_nativeRemoveLocalStream)(
2730 JNIEnv* jni, jobject j_pc, jlong native_stream) {
2731 ExtractNativePC(jni, j_pc)->RemoveStream(
2732 reinterpret_cast<MediaStreamInterface*>(native_stream));
2733}
2734
2735JOW(bool, PeerConnection_nativeGetStats)(
2736 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002737 rtc::scoped_refptr<StatsObserverWrapper> observer(
2738 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002739 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00002740 observer,
2741 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
2742 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002743}
2744
2745JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2746 PeerConnectionInterface::SignalingState state =
2747 ExtractNativePC(jni, j_pc)->signaling_state();
2748 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2749}
2750
2751JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2752 PeerConnectionInterface::IceConnectionState state =
2753 ExtractNativePC(jni, j_pc)->ice_connection_state();
2754 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2755}
2756
2757JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
2758 PeerConnectionInterface::IceGatheringState state =
2759 ExtractNativePC(jni, j_pc)->ice_gathering_state();
2760 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
2761}
2762
2763JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2764 ExtractNativePC(jni, j_pc)->Close();
2765 return;
2766}
2767
2768JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002769 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002770 reinterpret_cast<MediaSourceInterface*>(j_p));
2771 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2772}
2773
2774JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
2775 JNIEnv* jni, jclass, jstring j_device_name) {
2776 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002777 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002778 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002779 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002780 cricket::Device device;
2781 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002782 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783 return 0;
2784 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002785 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786 device_manager->CreateVideoCapturer(device));
2787 return (jlong)capturer.release();
2788}
2789
2790JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2791 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002792 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2793 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002794 return (jlong)renderer.release();
2795}
2796
2797JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2798 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002799 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002800 new JavaVideoRendererWrapper(jni, j_callbacks));
2801 return (jlong)renderer.release();
2802}
2803
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002804JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2805 cricket::VideoCapturer* capturer =
2806 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002807 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002808 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2809 capturer->Stop();
2810 return jlongFromPointer(format.release());
2811}
2812
2813JOW(void, VideoSource_restart)(
2814 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002815 CHECK(j_p_source);
2816 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002817 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002818 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2819 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2820 StartCapturing(cricket::VideoFormat(*format));
2821}
2822
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00002823JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002824 JNIEnv* jni, jclass, jlong j_p) {
2825 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2826}
2827
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002828JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002829 return JavaStringFromStdString(
2830 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002831}
2832
2833JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002834 return JavaStringFromStdString(
2835 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002836}
2837
2838JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002839 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840}
2841
2842JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002843 return JavaEnumFromIndex(
2844 jni,
2845 "MediaStreamTrack$State",
2846 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002847}
2848
2849JOW(jboolean, MediaStreamTrack_nativeSetState)(
2850 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002851 MediaStreamTrackInterface::TrackState new_state =
2852 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002853 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2854 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002855}
2856
2857JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2858 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002859 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2860 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861}
2862
2863JOW(void, VideoTrack_nativeAddRenderer)(
2864 JNIEnv* jni, jclass,
2865 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002866 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002867 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2868}
2869
2870JOW(void, VideoTrack_nativeRemoveRenderer)(
2871 JNIEnv* jni, jclass,
2872 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002873 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2875}