blob: 4a06364d8a0f783b2bd86f971028a9695556f7e2 [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"
kwiberg@webrtc.org3df38b42015-01-13 11:37:48 +000081#include "webrtc/base/compile_assert.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000082#include "webrtc/base/logging.h"
83#include "webrtc/base/messagequeue.h"
84#include "webrtc/base/ssladapter.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000085#include "webrtc/common_video/interface/texture_video_frame.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000086#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000087#include "webrtc/system_wrappers/interface/trace.h"
88#include "webrtc/video_engine/include/vie_base.h"
89#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090
glaznev@webrtc.org99678452014-09-15 17:52:42 +000091#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
92#include <android/log.h>
andresp@webrtc.org85ef7702014-09-17 11:44:51 +000093#include "webrtc/modules/video_capture/video_capture_internal.h"
94#include "webrtc/modules/video_render/video_render_internal.h"
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000095#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000096#include "webrtc/system_wrappers/interface/tick_util.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000097using webrtc::CodecSpecificInfo;
98using webrtc::DecodedImageCallback;
99using webrtc::EncodedImage;
100using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000101using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000102using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000103using webrtc::TextureVideoFrame;
104using webrtc::TickTime;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000105using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000106#endif
107
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108using icu::UnicodeString;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000109using rtc::Bind;
110using rtc::Thread;
111using rtc::ThreadManager;
112using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113using webrtc::AudioSourceInterface;
114using webrtc::AudioTrackInterface;
115using webrtc::AudioTrackVector;
116using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000117using webrtc::DataBuffer;
118using webrtc::DataChannelInit;
119using webrtc::DataChannelInterface;
120using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121using webrtc::IceCandidateInterface;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000122using webrtc::NativeHandle;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123using webrtc::MediaConstraintsInterface;
124using webrtc::MediaSourceInterface;
125using webrtc::MediaStreamInterface;
126using webrtc::MediaStreamTrackInterface;
127using webrtc::PeerConnectionFactoryInterface;
128using webrtc::PeerConnectionInterface;
129using webrtc::PeerConnectionObserver;
130using webrtc::SessionDescriptionInterface;
131using webrtc::SetSessionDescriptionObserver;
132using webrtc::StatsObserver;
133using webrtc::StatsReport;
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000134using webrtc::StatsReports;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135using webrtc::VideoRendererInterface;
136using webrtc::VideoSourceInterface;
137using webrtc::VideoTrackInterface;
138using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000139using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000141// Abort the process if |jni| has a Java exception pending.
142// This macros uses the comma operator to execute ExceptionDescribe
143// and ExceptionClear ignoring their return values and sending ""
144// to the error stream.
145#define CHECK_EXCEPTION(jni) \
146 CHECK(!jni->ExceptionCheck()) \
147 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000149// Helper that calls ptr->Release() and aborts the process with a useful
150// message if that didn't actually delete *ptr because of extra refcounts.
151#define CHECK_RELEASE(ptr) \
152 CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000153
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000154namespace {
155
156static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
157
158static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000159// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
160// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
161// were attached by the JVM because of a Java->native call.
162static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000164#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
165// Set in PeerConnectionFactory_initializeAndroidGlobals().
166static bool factory_static_initialized = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +0000167static bool vp8_hw_acceleration_enabled = true;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000168#endif
169
170
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000171// Return thread ID as a string.
172static std::string GetThreadId() {
173 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000174 CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
175 sizeof(buf))
176 << "Thread id is bigger than uint64??";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000177 return std::string(buf);
178}
179
180// Return the current thread's name.
181static std::string GetThreadName() {
182 char name[17];
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000183 CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000184 name[16] = '\0';
185 return std::string(name);
186}
187
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000188// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
189static JNIEnv* GetEnv() {
190 void* env = NULL;
191 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
192 CHECK(((env != NULL) && (status == JNI_OK)) ||
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000193 ((env == NULL) && (status == JNI_EDETACHED)))
194 << "Unexpected GetEnv return: " << status << ":" << env;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000195 return reinterpret_cast<JNIEnv*>(env);
196}
197
198static void ThreadDestructor(void* prev_jni_ptr) {
199 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
200 // we were responsible for originally attaching the thread, so are responsible
201 // for detaching it now. However, because some JVM implementations (notably
202 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
203 // the JVMs accounting info for this thread may already be wiped out by the
204 // time this is called. Thus it may appear we are already detached even though
205 // it was our responsibility to detach! Oh well.
206 if (!GetEnv())
207 return;
208
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000209 CHECK(GetEnv() == prev_jni_ptr)
210 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211 jint status = g_jvm->DetachCurrentThread();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000212 CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
213 CHECK(!GetEnv()) << "Detaching was a successful no-op???";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000214}
215
216static void CreateJNIPtrKey() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000217 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
218 << "pthread_key_create";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219}
220
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000221// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000222static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000223 JNIEnv* jni = GetEnv();
224 if (jni)
225 return jni;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000226 CHECK(!pthread_getspecific(g_jni_ptr))
227 << "TLS has a JNIEnv* but not attached?";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000228
229 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
230 JavaVMAttachArgs args;
231 args.version = JNI_VERSION_1_6;
232 args.name = name;
233 args.group = NULL;
234 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000235#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000236 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000237#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000238 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000239#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000240 CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000241 free(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000242 CHECK(env) << "AttachCurrentThread handed back NULL!";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000243 jni = reinterpret_cast<JNIEnv*>(env);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000244 CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245 return jni;
246}
247
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000248// Return a |jlong| that will correctly convert back to |ptr|. This is needed
249// because the alternative (of silently passing a 32-bit pointer to a vararg
250// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000251static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000252 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000253 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000254 // Going through intptr_t to be obvious about the definedness of the
255 // conversion from pointer to integral type. intptr_t to jlong is a standard
256 // widening by the COMPILE_ASSERT above.
257 jlong ret = reinterpret_cast<intptr_t>(ptr);
258 assert(reinterpret_cast<void*>(ret) == ptr);
259 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000260}
261
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262// Android's FindClass() is trickier than usual because the app-specific
263// ClassLoader is not consulted when there is no app-specific frame on the
264// stack. Consequently, we only look up classes once in JNI_OnLoad.
265// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
266class ClassReferenceHolder {
267 public:
268 explicit ClassReferenceHolder(JNIEnv* jni) {
269 LoadClass(jni, "java/nio/ByteBuffer");
270 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000271 LoadClass(jni, "org/webrtc/DataChannel");
272 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
273 LoadClass(jni, "org/webrtc/DataChannel$Init");
274 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275 LoadClass(jni, "org/webrtc/IceCandidate");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000276#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
277 LoadClass(jni, "android/graphics/SurfaceTexture");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000278 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
279 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000280 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000281 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
glaznev@webrtc.orga8c0edd2014-10-20 19:08:05 +0000282 jclass j_decoder_class = GetClass("org/webrtc/MediaCodecVideoDecoder");
283 jmethodID j_is_egl14_supported_method = jni->GetStaticMethodID(
284 j_decoder_class, "isEGL14Supported", "()Z");
285 bool is_egl14_supported = jni->CallStaticBooleanMethod(
286 j_decoder_class, j_is_egl14_supported_method);
287 CHECK_EXCEPTION(jni);
288 if (is_egl14_supported) {
289 LoadClass(jni, "android/opengl/EGLContext");
290 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000291#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000292 LoadClass(jni, "org/webrtc/MediaSource$State");
293 LoadClass(jni, "org/webrtc/MediaStream");
294 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000295 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
296 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000297 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298 LoadClass(jni, "org/webrtc/SessionDescription");
299 LoadClass(jni, "org/webrtc/SessionDescription$Type");
300 LoadClass(jni, "org/webrtc/StatsReport");
301 LoadClass(jni, "org/webrtc/StatsReport$Value");
302 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
303 LoadClass(jni, "org/webrtc/VideoTrack");
304 }
305
306 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000307 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000308 }
309
310 void FreeReferences(JNIEnv* jni) {
311 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
312 it != classes_.end(); ++it) {
313 jni->DeleteGlobalRef(it->second);
314 }
315 classes_.clear();
316 }
317
318 jclass GetClass(const std::string& name) {
319 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000320 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321 return it->second;
322 }
323
324 private:
325 void LoadClass(JNIEnv* jni, const std::string& name) {
326 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000327 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
328 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000329 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000330 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
331 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000332 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000333 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000334 }
335
336 std::map<std::string, jclass> classes_;
337};
338
339// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
340static ClassReferenceHolder* g_class_reference_holder = NULL;
341
342// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
343// object/class/method/field is non-null.
344jmethodID GetMethodID(
345 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
346 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000347 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
348 << signature;
349 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 return m;
351}
352
353jmethodID GetStaticMethodID(
354 JNIEnv* jni, jclass c, const char* name, const char* signature) {
355 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000356 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
357 << signature;
358 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359 return m;
360}
361
362jfieldID GetFieldID(
363 JNIEnv* jni, jclass c, const char* name, const char* signature) {
364 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000365 CHECK_EXCEPTION(jni) << "error during GetFieldID";
366 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 return f;
368}
369
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000370// Returns a global reference guaranteed to be valid for the lifetime of the
371// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000372jclass FindClass(JNIEnv* jni, const char* name) {
373 return g_class_reference_holder->GetClass(name);
374}
375
376jclass GetObjectClass(JNIEnv* jni, jobject object) {
377 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000378 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000379 CHECK(c) << "GetObjectClass returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000380 return c;
381}
382
383jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
384 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000385 CHECK_EXCEPTION(jni) << "error during GetObjectField";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000386 CHECK(o) << "GetObjectField returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 return o;
388}
389
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000390jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
391 return static_cast<jstring>(GetObjectField(jni, object, id));
392}
393
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000394jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
395 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000396 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000397 return l;
398}
399
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000400jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
401 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000402 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000403 return i;
404}
405
406bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
407 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000408 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000409 return b;
410}
411
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000412jobject NewGlobalRef(JNIEnv* jni, jobject o) {
413 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000414 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
415 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 return ret;
417}
418
419void DeleteGlobalRef(JNIEnv* jni, jobject o) {
420 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000421 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422}
423
424// Given a jweak reference, allocate a (strong) local reference scoped to the
425// lifetime of this object if the weak reference is still valid, or NULL
426// otherwise.
427class WeakRef {
428 public:
429 WeakRef(JNIEnv* jni, jweak ref)
430 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000431 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000432 }
433 ~WeakRef() {
434 if (obj_) {
435 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000436 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437 }
438 }
439 jobject obj() { return obj_; }
440
441 private:
442 JNIEnv* const jni_;
443 jobject const obj_;
444};
445
fischman@webrtc.org41776152014-01-09 00:31:17 +0000446// Scope Java local references to the lifetime of this object. Use in all C++
447// callbacks (i.e. entry points that don't originate in a Java callstack
448// through a "native" method call).
449class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000451 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000452 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000454 ~ScopedLocalRefFrame() {
455 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000457
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458 private:
459 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460};
461
462// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000463template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464class ScopedGlobalRef {
465 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000466 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000467 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000468 ~ScopedGlobalRef() {
469 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
470 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000471 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 return obj_;
473 }
474 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000475 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476};
477
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000478// Java references to "null" can only be distinguished as such in C++ by
479// creating a local reference, so this helper wraps that logic.
480static bool IsNull(JNIEnv* jni, jobject obj) {
481 ScopedLocalRefFrame local_ref_frame(jni);
482 return jni->NewLocalRef(obj) == NULL;
483}
484
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000485// Return the (singleton) Java Enum object corresponding to |index|;
486// |state_class_fragment| is something like "MediaSource$State".
487jobject JavaEnumFromIndex(
488 JNIEnv* jni, const std::string& state_class_fragment, int index) {
489 std::string state_class_name = "org/webrtc/" + state_class_fragment;
490 jclass state_class = FindClass(jni, state_class_name.c_str());
491 jmethodID state_values_id = GetStaticMethodID(
492 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000493 jobjectArray state_values = static_cast<jobjectArray>(
494 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000495 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000496 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000497 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 return ret;
499}
500
501// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
502static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
503 UnicodeString ustr(UnicodeString::fromUTF8(native));
504 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000505 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000506 return jstr;
507}
508
509// Given a (UTF-16) jstring return a new UTF-8 native string.
510static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
511 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000512 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000514 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000516 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 std::string ret;
518 return ustr.toUTF8String(ret);
519}
520
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000521static DataChannelInit JavaDataChannelInitToNative(
522 JNIEnv* jni, jobject j_init) {
523 DataChannelInit init;
524
525 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
526 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
527 jfieldID max_retransmit_time_id =
528 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
529 jfieldID max_retransmits_id =
530 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
531 jfieldID protocol_id =
532 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
533 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
534 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
535
536 init.ordered = GetBooleanField(jni, j_init, ordered_id);
537 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
538 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
539 init.protocol = JavaToStdString(
540 jni, GetStringField(jni, j_init, protocol_id));
541 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
542 init.id = GetIntField(jni, j_init, id_id);
543
544 return init;
545}
546
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547class ConstraintsWrapper;
548
549// Adapter between the C++ PeerConnectionObserver interface and the Java
550// PeerConnection.Observer interface. Wraps an instance of the Java interface
551// and dispatches C++ callbacks to Java.
552class PCOJava : public PeerConnectionObserver {
553 public:
554 PCOJava(JNIEnv* jni, jobject j_observer)
555 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000556 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
557 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
558 j_media_stream_ctor_(GetMethodID(
559 jni, *j_media_stream_class_, "<init>", "(J)V")),
560 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000561 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000562 jni, *j_audio_track_class_, "<init>", "(J)V")),
563 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
564 j_video_track_ctor_(GetMethodID(
565 jni, *j_video_track_class_, "<init>", "(J)V")),
566 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
567 j_data_channel_ctor_(GetMethodID(
568 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000569 }
570
571 virtual ~PCOJava() {}
572
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000573 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000574 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000576 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
578 jmethodID ctor = GetMethodID(jni(), candidate_class,
579 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000580 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
581 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
582 jobject j_candidate = jni()->NewObject(
583 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000584 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000585 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000587 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000588 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 }
590
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000592 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000593 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000595 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000597 jobject new_state_enum =
598 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
599 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000600 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 }
602
603 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000604 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000605 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000607 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000609 jobject new_state_enum = JavaEnumFromIndex(
610 jni(), "PeerConnection$IceConnectionState", new_state);
611 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000612 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 }
614
615 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000616 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000617 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000619 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000621 jobject new_state_enum = JavaEnumFromIndex(
622 jni(), "PeerConnection$IceGatheringState", new_state);
623 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000624 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 }
626
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000627 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000628 ScopedLocalRefFrame local_ref_frame(jni());
629 jobject j_stream = jni()->NewObject(
630 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000631 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632
633 AudioTrackVector audio_tracks = stream->GetAudioTracks();
634 for (size_t i = 0; i < audio_tracks.size(); ++i) {
635 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000636 jstring id = JavaStringFromStdString(jni(), track->id());
637 jobject j_track = jni()->NewObject(
638 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000639 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000640 jfieldID audio_tracks_id = GetFieldID(jni(),
641 *j_media_stream_class_,
642 "audioTracks",
643 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000644 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000646 GetObjectClass(jni(), audio_tracks),
647 "add",
648 "(Ljava/lang/Object;)Z");
649 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000650 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
651 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 }
653
654 VideoTrackVector video_tracks = stream->GetVideoTracks();
655 for (size_t i = 0; i < video_tracks.size(); ++i) {
656 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000657 jstring id = JavaStringFromStdString(jni(), track->id());
658 jobject j_track = jni()->NewObject(
659 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000660 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000661 jfieldID video_tracks_id = GetFieldID(jni(),
662 *j_media_stream_class_,
663 "videoTracks",
664 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000665 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000667 GetObjectClass(jni(), video_tracks),
668 "add",
669 "(Ljava/lang/Object;)Z");
670 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000671 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
672 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000674 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000675 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000676
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000677 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
678 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000679 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000680 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 }
682
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000683 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000684 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000686 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687
688 WeakRef s(jni(), it->second);
689 streams_.erase(it);
690 if (!s.obj())
691 return;
692
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000693 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
694 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000695 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000696 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697 }
698
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000699 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000700 ScopedLocalRefFrame local_ref_frame(jni());
701 jobject j_channel = jni()->NewObject(
702 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000703 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000704
705 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
706 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000707 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000708
709 // Channel is now owned by Java object, and will be freed from
710 // DataChannel.dispose(). Important that this be done _after_ the
711 // CallVoidMethod above as Java code might call back into native code and be
712 // surprised to see a refcount of 2.
713 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000714 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000715
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000716 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000717 }
718
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000719 virtual void OnRenegotiationNeeded() OVERRIDE {
720 ScopedLocalRefFrame local_ref_frame(jni());
721 jmethodID m =
722 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
723 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000724 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000725 }
726
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000728 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 constraints_.reset(constraints);
730 }
731
732 const ConstraintsWrapper* constraints() { return constraints_.get(); }
733
734 private:
735 JNIEnv* jni() {
736 return AttachCurrentThreadIfNeeded();
737 }
738
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000739 const ScopedGlobalRef<jobject> j_observer_global_;
740 const ScopedGlobalRef<jclass> j_observer_class_;
741 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000743 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000745 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000747 const ScopedGlobalRef<jclass> j_data_channel_class_;
748 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
750 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000751 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752};
753
754// Wrapper for a Java MediaConstraints object. Copies all needed data so when
755// the constructor returns the Java object is no longer needed.
756class ConstraintsWrapper : public MediaConstraintsInterface {
757 public:
758 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
759 PopulateConstraintsFromJavaPairList(
760 jni, j_constraints, "mandatory", &mandatory_);
761 PopulateConstraintsFromJavaPairList(
762 jni, j_constraints, "optional", &optional_);
763 }
764
765 virtual ~ConstraintsWrapper() {}
766
767 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000768 virtual const Constraints& GetMandatory() const OVERRIDE {
769 return mandatory_;
770 }
771
772 virtual const Constraints& GetOptional() const OVERRIDE {
773 return optional_;
774 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775
776 private:
777 // Helper for translating a List<Pair<String, String>> to a Constraints.
778 static void PopulateConstraintsFromJavaPairList(
779 JNIEnv* jni, jobject j_constraints,
780 const char* field_name, Constraints* field) {
781 jfieldID j_id = GetFieldID(jni,
782 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
783 jobject j_list = GetObjectField(jni, j_constraints, j_id);
784 jmethodID j_iterator_id = GetMethodID(jni,
785 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
786 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000787 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000788 jmethodID j_has_next = GetMethodID(jni,
789 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
790 jmethodID j_next = GetMethodID(jni,
791 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
792 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000793 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000795 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 jmethodID get_key = GetMethodID(jni,
797 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
798 jstring j_key = reinterpret_cast<jstring>(
799 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000800 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 jmethodID get_value = GetMethodID(jni,
802 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
803 jstring j_value = reinterpret_cast<jstring>(
804 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000805 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 field->push_back(Constraint(JavaToStdString(jni, j_key),
807 JavaToStdString(jni, j_value)));
808 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000809 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810 }
811
812 Constraints mandatory_;
813 Constraints optional_;
814};
815
816static jobject JavaSdpFromNativeSdp(
817 JNIEnv* jni, const SessionDescriptionInterface* desc) {
818 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000819 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000820 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821
822 jclass j_type_class = FindClass(
823 jni, "org/webrtc/SessionDescription$Type");
824 jmethodID j_type_from_canonical = GetStaticMethodID(
825 jni, j_type_class, "fromCanonicalForm",
826 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000827 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000829 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000830 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831
832 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
833 jmethodID j_sdp_ctor = GetMethodID(
834 jni, j_sdp_class, "<init>",
835 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
836 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000837 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000838 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839 return j_sdp;
840}
841
842template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
843class SdpObserverWrapper : public T {
844 public:
845 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
846 ConstraintsWrapper* constraints)
847 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000848 j_observer_global_(jni, j_observer),
849 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 }
851
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000852 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000854 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000856 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000857 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
858 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000859 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 }
861
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000862 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000864 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000866 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000868 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
869 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000870 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871 }
872
873 protected:
874 // Common implementation for failure of Set & Create types, distinguished by
875 // |op| being "Set" or "Create".
876 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000877 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
878 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000879 jstring j_error_string = JavaStringFromStdString(jni(), error);
880 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000881 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882 }
883
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000884 JNIEnv* jni() {
885 return AttachCurrentThreadIfNeeded();
886 }
887
fischman@webrtc.org41776152014-01-09 00:31:17 +0000888 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000889 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000890 const ScopedGlobalRef<jobject> j_observer_global_;
891 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892};
893
894class CreateSdpObserverWrapper
895 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
896 public:
897 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
898 ConstraintsWrapper* constraints)
899 : SdpObserverWrapper(jni, j_observer, constraints) {}
900
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000901 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000902 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903 SdpObserverWrapper::OnFailure(std::string("Create"), error);
904 }
905};
906
907class SetSdpObserverWrapper
908 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
909 public:
910 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
911 ConstraintsWrapper* constraints)
912 : SdpObserverWrapper(jni, j_observer, constraints) {}
913
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000914 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000915 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916 SdpObserverWrapper::OnFailure(std::string("Set"), error);
917 }
918};
919
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000920// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
921// and dispatching the callback from C++ back to Java.
922class DataChannelObserverWrapper : public DataChannelObserver {
923 public:
924 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
925 : j_observer_global_(jni, j_observer),
926 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000927 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000928 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
929 "onStateChange", "()V")),
930 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
931 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000932 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
933 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
934 }
935
936 virtual ~DataChannelObserverWrapper() {}
937
938 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000939 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000940 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000941 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000942 }
943
944 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000945 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000946 jobject byte_buffer =
947 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
948 buffer.data.length());
949 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
950 byte_buffer, buffer.binary);
951 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000952 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000953 }
954
955 private:
956 JNIEnv* jni() {
957 return AttachCurrentThreadIfNeeded();
958 }
959
960 const ScopedGlobalRef<jobject> j_observer_global_;
961 const ScopedGlobalRef<jclass> j_observer_class_;
962 const ScopedGlobalRef<jclass> j_buffer_class_;
963 const jmethodID j_on_state_change_mid_;
964 const jmethodID j_on_message_mid_;
965 const jmethodID j_buffer_ctor_;
966};
967
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000968// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
969// dispatching the callback from C++ back to Java.
970class StatsObserverWrapper : public StatsObserver {
971 public:
972 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000973 : j_observer_global_(jni, j_observer),
974 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
975 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000977 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000978 "(Ljava/lang/String;Ljava/lang/String;D"
979 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000980 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981 jni, "org/webrtc/StatsReport$Value")),
982 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000983 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000984 "(Ljava/lang/String;Ljava/lang/String;)V")) {
985 }
986
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000987 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000989 virtual void OnComplete(const StatsReports& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000990 ScopedLocalRefFrame local_ref_frame(jni());
991 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000992 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
993 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000994 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000995 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000996 }
997
998 private:
999 jobjectArray ReportsToJava(
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001000 JNIEnv* jni, const StatsReports& reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001001 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001002 reports.size(), *j_stats_report_class_, NULL);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001003 int i = 0;
1004 for (const auto* report : reports) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001005 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001006 jstring j_id = JavaStringFromStdString(jni, report->id);
1007 jstring j_type = JavaStringFromStdString(jni, report->type);
1008 jobjectArray j_values = ValuesToJava(jni, report->values);
fischman@webrtc.org41776152014-01-09 00:31:17 +00001009 jobject j_report = jni->NewObject(*j_stats_report_class_,
1010 j_stats_report_ctor_,
1011 j_id,
1012 j_type,
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001013 report->timestamp,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001014 j_values);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001015 jni->SetObjectArrayElement(reports_array, i++, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001016 }
1017 return reports_array;
1018 }
1019
1020 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1021 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001022 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001023 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001024 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025 const StatsReport::Value& value = values[i];
tommi@webrtc.orgc57310b2014-12-12 17:41:28 +00001026 // Should we use the '.name' enum value here instead of converting the
1027 // name to a string?
1028 jstring j_name = JavaStringFromStdString(jni, value.display_name());
fischman@webrtc.org41776152014-01-09 00:31:17 +00001029 jstring j_value = JavaStringFromStdString(jni, value.value);
1030 jobject j_element_value =
1031 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1032 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001033 }
1034 return j_values;
1035 }
1036
1037 JNIEnv* jni() {
1038 return AttachCurrentThreadIfNeeded();
1039 }
1040
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001041 const ScopedGlobalRef<jobject> j_observer_global_;
1042 const ScopedGlobalRef<jclass> j_observer_class_;
1043 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001044 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001045 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046 const jmethodID j_value_ctor_;
1047};
1048
1049// Adapter presenting a cricket::VideoRenderer as a
1050// webrtc::VideoRendererInterface.
1051class VideoRendererWrapper : public VideoRendererInterface {
1052 public:
1053 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1054 if (renderer)
1055 return new VideoRendererWrapper(renderer);
1056 return NULL;
1057 }
1058
1059 virtual ~VideoRendererWrapper() {}
1060
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001061 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001062 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001063 const bool kNotReserved = false; // What does this param mean??
1064 renderer_->SetSize(width, height, kNotReserved);
1065 }
1066
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001067 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001068 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001069 renderer_->RenderFrame(frame);
1070 }
1071
1072 private:
1073 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1074 : renderer_(renderer) {}
1075
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001076 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001077};
1078
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001079// Wrapper for texture object in TextureVideoFrame.
1080class NativeHandleImpl : public NativeHandle {
1081 public:
1082 NativeHandleImpl() :
1083 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1084 virtual ~NativeHandleImpl() {}
1085 virtual int32_t AddRef() {
1086 return ++ref_count_;
1087 }
1088 virtual int32_t Release() {
1089 return --ref_count_;
1090 }
1091 virtual void* GetHandle() {
1092 return texture_object_;
1093 }
1094 int GetTextureId() {
1095 return texture_id_;
1096 }
1097 void SetTextureObject(void *texture_object, int texture_id) {
1098 texture_object_ = reinterpret_cast<jobject>(texture_object);
1099 texture_id_ = texture_id;
1100 }
1101 int32_t ref_count() {
1102 return ref_count_;
1103 }
1104
1105 private:
1106 int32_t ref_count_;
1107 jobject texture_object_;
1108 int32_t texture_id_;
1109};
1110
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1112// instance.
1113class JavaVideoRendererWrapper : public VideoRendererInterface {
1114 public:
1115 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001116 : j_callbacks_(jni, j_callbacks),
1117 j_set_size_id_(GetMethodID(
1118 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1119 j_render_frame_id_(GetMethodID(
1120 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1121 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1122 j_frame_class_(jni,
1123 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001124 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001125 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001126 j_texture_frame_ctor_id_(GetMethodID(
1127 jni, *j_frame_class_, "<init>",
1128 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001129 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001130 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131 }
1132
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001133 virtual ~JavaVideoRendererWrapper() {}
1134
1135 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001136 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001138 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001139 }
1140
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001141 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001142 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001143 if (frame->GetNativeHandle() != NULL) {
1144 jobject j_frame = CricketToJavaTextureFrame(frame);
1145 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1146 CHECK_EXCEPTION(jni());
1147 } else {
1148 jobject j_frame = CricketToJavaI420Frame(frame);
1149 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1150 CHECK_EXCEPTION(jni());
1151 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 }
1153
1154 private:
1155 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001156 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001157 jintArray strides = jni()->NewIntArray(3);
1158 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001159 strides_array[0] = frame->GetYPitch();
1160 strides_array[1] = frame->GetUPitch();
1161 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001162 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1163 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1164 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001165 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001166 frame->GetYPitch() * frame->GetHeight());
1167 jobject u_buffer = jni()->NewDirectByteBuffer(
1168 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1169 jobject v_buffer = jni()->NewDirectByteBuffer(
1170 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1171 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1172 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1173 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001174 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001175 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001176 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177 }
1178
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001179 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1180 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1181 NativeHandleImpl* handle =
1182 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1183 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1184 int texture_id = handle->GetTextureId();
1185 return jni()->NewObject(
1186 *j_frame_class_, j_texture_frame_ctor_id_,
1187 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1188 }
1189
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 JNIEnv* jni() {
1191 return AttachCurrentThreadIfNeeded();
1192 }
1193
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001194 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 jmethodID j_set_size_id_;
1196 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001197 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001198 jmethodID j_i420_frame_ctor_id_;
1199 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001200 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001201};
1202
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001203#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001204// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1205// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1206// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001207
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001208//#define TRACK_BUFFER_TIMING
1209#define TAG "MediaCodecVideo"
1210#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001211#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1212#else
1213#define ALOGV(...)
1214#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001215#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1216#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001217
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001218// Color formats supported by encoder - should mirror supportedColorList
1219// from MediaCodecVideoEncoder.java
1220enum COLOR_FORMATTYPE {
1221 COLOR_FormatYUV420Planar = 0x13,
1222 COLOR_FormatYUV420SemiPlanar = 0x15,
1223 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1224 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1225 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1226 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1227 // but requires some (16, 32?) byte alignment.
1228 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1229};
1230
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001231// Arbitrary interval to poll the codec for new outputs.
1232enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001233// Media codec maximum output buffer ready timeout.
1234enum { kMediaCodecTimeoutMs = 500 };
1235// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1236enum { kMediaCodecStatisticsIntervalMs = 3000 };
1237
1238static int64_t GetCurrentTimeMs() {
1239 return TickTime::Now().Ticks() / 1000000LL;
1240}
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001241
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001242// Allow Invoke() calls from from current thread.
1243static void AllowBlockingCalls() {
1244 Thread* current_thread = Thread::Current();
1245 if (current_thread != NULL)
1246 current_thread->SetAllowBlockingCalls(true);
1247}
1248
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001249// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1250// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1251// HW-backed video encode. This C++ class is implemented as a very thin shim,
1252// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1253// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1254// thread, currently the libjingle Worker thread.
1255class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001256 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001257 public:
1258 virtual ~MediaCodecVideoEncoder();
1259 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1260
1261 // webrtc::VideoEncoder implementation. Everything trampolines to
1262 // |codec_thread_| for execution.
1263 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1264 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001265 size_t /* max_payload_size */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001266 virtual int32_t Encode(
1267 const webrtc::I420VideoFrame& input_image,
1268 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1269 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1270 virtual int32_t RegisterEncodeCompleteCallback(
1271 webrtc::EncodedImageCallback* callback) OVERRIDE;
1272 virtual int32_t Release() OVERRIDE;
1273 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001274 int64_t /* rtt */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001275 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1276
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001277 // rtc::MessageHandler implementation.
1278 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001279
1280 private:
1281 // CHECK-fail if not running on |codec_thread_|.
1282 void CheckOnCodecThread();
1283
1284 // Release() and InitEncode() in an attempt to restore the codec to an
1285 // operable state. Necessary after all manner of OMX-layer errors.
1286 void ResetCodec();
1287
1288 // Implementation of webrtc::VideoEncoder methods above, all running on the
1289 // codec thread exclusively.
1290 //
1291 // If width==0 then this is assumed to be a re-initialization and the
1292 // previously-current values are reused instead of the passed parameters
1293 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001294 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001295 int32_t EncodeOnCodecThread(
1296 const webrtc::I420VideoFrame& input_image,
1297 const std::vector<webrtc::VideoFrameType>* frame_types);
1298 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1299 webrtc::EncodedImageCallback* callback);
1300 int32_t ReleaseOnCodecThread();
1301 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1302
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001303 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1304 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1305 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1306 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1307 jlong GetOutputBufferInfoPresentationTimestampUs(
1308 JNIEnv* jni,
1309 jobject j_output_buffer_info);
1310
1311 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1312 // true on success.
1313 bool DeliverPendingOutputs(JNIEnv* jni);
1314
1315 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1316 // |codec_thread_| synchronously.
1317 webrtc::EncodedImageCallback* callback_;
1318
1319 // State that is constant for the lifetime of this object once the ctor
1320 // returns.
1321 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1322 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1323 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1324 jmethodID j_init_encode_method_;
1325 jmethodID j_dequeue_input_buffer_method_;
1326 jmethodID j_encode_method_;
1327 jmethodID j_release_method_;
1328 jmethodID j_set_rates_method_;
1329 jmethodID j_dequeue_output_buffer_method_;
1330 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001331 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001332 jfieldID j_info_index_field_;
1333 jfieldID j_info_buffer_field_;
1334 jfieldID j_info_is_key_frame_field_;
1335 jfieldID j_info_presentation_timestamp_us_field_;
1336
1337 // State that is valid only between InitEncode() and the next Release().
1338 // Touched only on codec_thread_ so no explicit synchronization necessary.
1339 int width_; // Frame width in pixels.
1340 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001341 bool inited_;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001342 uint16_t picture_id_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001343 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001344 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001345 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001346 int64_t current_timestamp_us_; // Current frame timestamps in us.
1347 int frames_received_; // Number of frames received by encoder.
1348 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001349 int frames_resolution_update_; // Number of frames with new codec resolution.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001350 int frames_in_queue_; // Number of frames in encoder queue.
1351 int64_t start_time_ms_; // Start time for statistics.
1352 int current_frames_; // Number of frames in the current statistics interval.
1353 int current_bytes_; // Encoded bytes in the current statistics interval.
1354 int current_encoding_time_ms_; // Overall encoding time in the current second
1355 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1356 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
1357 std::vector<int32_t> timestamps_; // Video frames timestamp queue.
1358 std::vector<int64_t> render_times_ms_; // Video frames render time queue.
1359 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1360 // encoder input.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001361 // Frame size in bytes fed to MediaCodec.
1362 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001363 // True only when between a callback_->Encoded() call return a positive value
1364 // and the next Encode() call being ignored.
1365 bool drop_next_input_frame_;
1366 // Global references; must be deleted in Release().
1367 std::vector<jobject> input_buffers_;
1368};
1369
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001370MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001371 // Call Release() to ensure no more callbacks to us after we are deleted.
1372 Release();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001373}
1374
1375MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001376 : callback_(NULL),
1377 inited_(false),
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001378 picture_id_(0),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001379 codec_thread_(new Thread()),
1380 j_media_codec_video_encoder_class_(
1381 jni,
1382 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1383 j_media_codec_video_encoder_(
1384 jni,
1385 jni->NewObject(*j_media_codec_video_encoder_class_,
1386 GetMethodID(jni,
1387 *j_media_codec_video_encoder_class_,
1388 "<init>",
1389 "()V"))) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001390 ScopedLocalRefFrame local_ref_frame(jni);
1391 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1392 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1393 // 2732 means that deadlocks abound. This class synchronously trampolines
1394 // to |codec_thread_|, so if anything else can be coming to _us_ from
1395 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1396 // in the bug, we have a problem. For now work around that with a dedicated
1397 // thread.
1398 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001399 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001400
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001401 jclass j_output_buffer_info_class =
1402 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1403 j_init_encode_method_ = GetMethodID(jni,
1404 *j_media_codec_video_encoder_class_,
1405 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001406 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001407 j_dequeue_input_buffer_method_ = GetMethodID(
1408 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1409 j_encode_method_ = GetMethodID(
1410 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1411 j_release_method_ =
1412 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1413 j_set_rates_method_ = GetMethodID(
1414 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1415 j_dequeue_output_buffer_method_ =
1416 GetMethodID(jni,
1417 *j_media_codec_video_encoder_class_,
1418 "dequeueOutputBuffer",
1419 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1420 j_release_output_buffer_method_ = GetMethodID(
1421 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1422
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001423 j_color_format_field_ =
1424 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001425 j_info_index_field_ =
1426 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1427 j_info_buffer_field_ = GetFieldID(
1428 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1429 j_info_is_key_frame_field_ =
1430 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1431 j_info_presentation_timestamp_us_field_ = GetFieldID(
1432 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001433 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001434 AllowBlockingCalls();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001435}
1436
1437int32_t MediaCodecVideoEncoder::InitEncode(
1438 const webrtc::VideoCodec* codec_settings,
1439 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001440 size_t /* max_payload_size */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001441 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001442 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001443
1444 return codec_thread_->Invoke<int32_t>(
1445 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1446 this,
1447 codec_settings->width,
1448 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001449 codec_settings->startBitrate,
1450 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001451}
1452
1453int32_t MediaCodecVideoEncoder::Encode(
1454 const webrtc::I420VideoFrame& frame,
1455 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1456 const std::vector<webrtc::VideoFrameType>* frame_types) {
1457 return codec_thread_->Invoke<int32_t>(Bind(
1458 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1459}
1460
1461int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1462 webrtc::EncodedImageCallback* callback) {
1463 return codec_thread_->Invoke<int32_t>(
1464 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1465 this,
1466 callback));
1467}
1468
1469int32_t MediaCodecVideoEncoder::Release() {
1470 return codec_thread_->Invoke<int32_t>(
1471 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1472}
1473
1474int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001475 int64_t /* rtt */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001476 return WEBRTC_VIDEO_CODEC_OK;
1477}
1478
1479int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1480 uint32_t frame_rate) {
1481 return codec_thread_->Invoke<int32_t>(
1482 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1483 this,
1484 new_bit_rate,
1485 frame_rate));
1486}
1487
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001488void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001489 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1490 ScopedLocalRefFrame local_ref_frame(jni);
1491
1492 // We only ever send one message to |this| directly (not through a Bind()'d
1493 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001494 CHECK(!msg->message_id) << "Unexpected message!";
1495 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001496 CheckOnCodecThread();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001497 if (!inited_) {
1498 return;
1499 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001500
1501 // It would be nice to recover from a failure here if one happened, but it's
1502 // unclear how to signal such a failure to the app, so instead we stay silent
1503 // about it and let the next app-called API method reveal the borkedness.
1504 DeliverPendingOutputs(jni);
1505 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1506}
1507
1508void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001509 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1510 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001511}
1512
1513void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001514 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001515 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1516 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001517 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1518 width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001519 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1520 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1521 // https://code.google.com/p/webrtc/issues/detail?id=2920
1522 }
1523}
1524
1525int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001526 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001527 CheckOnCodecThread();
1528 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1529 ScopedLocalRefFrame local_ref_frame(jni);
1530
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001531 ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1532 width, height, kbps, fps);
1533 if (kbps == 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001534 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001535 }
1536 if (fps == 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001537 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001538 }
1539
1540 width_ = width;
1541 height_ = height;
1542 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001543 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001544 yuv_size_ = width_ * height_ * 3 / 2;
1545 frames_received_ = 0;
1546 frames_dropped_ = 0;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001547 frames_resolution_update_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001548 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001549 current_timestamp_us_ = 0;
1550 start_time_ms_ = GetCurrentTimeMs();
1551 current_frames_ = 0;
1552 current_bytes_ = 0;
1553 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001554 last_input_timestamp_ms_ = -1;
1555 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001556 timestamps_.clear();
1557 render_times_ms_.clear();
1558 frame_rtc_times_ms_.clear();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001559 drop_next_input_frame_ = false;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001560 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001561 // We enforce no extra stride/padding in the format creation step.
1562 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1563 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1564 j_init_encode_method_,
1565 width_,
1566 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001567 kbps,
1568 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001569 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001570 if (IsNull(jni, input_buffers))
1571 return WEBRTC_VIDEO_CODEC_ERROR;
1572
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001573 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001574 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1575 j_color_format_field_)) {
1576 case COLOR_FormatYUV420Planar:
1577 encoder_fourcc_ = libyuv::FOURCC_YU12;
1578 break;
1579 case COLOR_FormatYUV420SemiPlanar:
1580 case COLOR_QCOM_FormatYUV420SemiPlanar:
1581 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1582 encoder_fourcc_ = libyuv::FOURCC_NV12;
1583 break;
1584 default:
1585 LOG(LS_ERROR) << "Wrong color format.";
1586 return WEBRTC_VIDEO_CODEC_ERROR;
1587 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001588 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001589 CHECK(input_buffers_.empty())
1590 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001591 input_buffers_.resize(num_input_buffers);
1592 for (size_t i = 0; i < num_input_buffers; ++i) {
1593 input_buffers_[i] =
1594 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001595 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001596 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001597 CHECK_EXCEPTION(jni);
1598 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001599 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001600 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001601
1602 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1603 return WEBRTC_VIDEO_CODEC_OK;
1604}
1605
1606int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1607 const webrtc::I420VideoFrame& frame,
1608 const std::vector<webrtc::VideoFrameType>* frame_types) {
1609 CheckOnCodecThread();
1610 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1611 ScopedLocalRefFrame local_ref_frame(jni);
1612
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001613 if (!inited_) {
1614 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1615 }
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001616 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001617 if (!DeliverPendingOutputs(jni)) {
1618 ResetCodec();
1619 // Continue as if everything's fine.
1620 }
1621
1622 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001623 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001624 drop_next_input_frame_ = false;
1625 return WEBRTC_VIDEO_CODEC_OK;
1626 }
1627
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001628 CHECK(frame_types->size() == 1) << "Unexpected stream count";
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001629 if (frame.width() != width_ || frame.height() != height_) {
1630 frames_resolution_update_++;
1631 ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1632 width_, height_, frame.width(), frame.height());
1633 if (frames_resolution_update_ > 3) {
1634 // Reset codec if we received more than 3 frames with new resolution.
1635 width_ = frame.width();
1636 height_ = frame.height();
1637 frames_resolution_update_ = 0;
1638 ResetCodec();
1639 }
1640 return WEBRTC_VIDEO_CODEC_OK;
1641 }
1642 frames_resolution_update_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001643
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001644 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1645
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001646 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001647 // or the encoder latency exceeds 70 ms and drop frame if so.
1648 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001649 int encoder_latency_ms = last_input_timestamp_ms_ -
1650 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001651 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001652 ALOGD("Drop frame - encoder is behind by %d ms. Q size: %d",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001653 encoder_latency_ms, frames_in_queue_);
1654 frames_dropped_++;
1655 return WEBRTC_VIDEO_CODEC_OK;
1656 }
1657 }
1658
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001659 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1660 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001661 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001662 if (j_input_buffer_index == -1) {
1663 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001664 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001665 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001666 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001667 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001668 if (j_input_buffer_index == -2) {
1669 ResetCodec();
1670 return WEBRTC_VIDEO_CODEC_ERROR;
1671 }
1672
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001673 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001674 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001675
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001676 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001677 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001678 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001679 CHECK_EXCEPTION(jni);
1680 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001681 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001682 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1683 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1684 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1685 yuv_buffer, width_,
1686 width_, height_,
1687 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001688 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001689 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001690 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001691
1692 // Save input image timestamps for later output
1693 timestamps_.push_back(frame.timestamp());
1694 render_times_ms_.push_back(frame.render_time_ms());
1695 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1696
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001697 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1698 j_encode_method_,
1699 key_frame,
1700 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001701 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001702 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001703 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001704 current_timestamp_us_ += 1000000 / last_set_fps_;
1705
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001706 if (!encode_status || !DeliverPendingOutputs(jni)) {
1707 ResetCodec();
1708 return WEBRTC_VIDEO_CODEC_ERROR;
1709 }
1710
1711 return WEBRTC_VIDEO_CODEC_OK;
1712}
1713
1714int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1715 webrtc::EncodedImageCallback* callback) {
1716 CheckOnCodecThread();
1717 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1718 ScopedLocalRefFrame local_ref_frame(jni);
1719 callback_ = callback;
1720 return WEBRTC_VIDEO_CODEC_OK;
1721}
1722
1723int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001724 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001725 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001726 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001727 CheckOnCodecThread();
1728 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001729 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1730 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001731 ScopedLocalRefFrame local_ref_frame(jni);
1732 for (size_t i = 0; i < input_buffers_.size(); ++i)
1733 jni->DeleteGlobalRef(input_buffers_[i]);
1734 input_buffers_.clear();
1735 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001736 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001737 rtc::MessageQueueManager::Clear(this);
1738 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001739 return WEBRTC_VIDEO_CODEC_OK;
1740}
1741
1742int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1743 uint32_t frame_rate) {
1744 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001745 if (last_set_bitrate_kbps_ == new_bit_rate &&
1746 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001747 return WEBRTC_VIDEO_CODEC_OK;
1748 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001749 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1750 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001751 if (new_bit_rate > 0) {
1752 last_set_bitrate_kbps_ = new_bit_rate;
1753 }
1754 if (frame_rate > 0) {
1755 last_set_fps_ = frame_rate;
1756 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001757 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1758 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001759 last_set_bitrate_kbps_,
1760 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001761 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001762 if (!ret) {
1763 ResetCodec();
1764 return WEBRTC_VIDEO_CODEC_ERROR;
1765 }
1766 return WEBRTC_VIDEO_CODEC_OK;
1767}
1768
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001769int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1770 JNIEnv* jni,
1771 jobject j_output_buffer_info) {
1772 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1773}
1774
1775jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1776 JNIEnv* jni,
1777 jobject j_output_buffer_info) {
1778 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1779}
1780
1781bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1782 JNIEnv* jni,
1783 jobject j_output_buffer_info) {
1784 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1785}
1786
1787jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1788 JNIEnv* jni,
1789 jobject j_output_buffer_info) {
1790 return GetLongField(
1791 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1792}
1793
1794bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1795 while (true) {
1796 jobject j_output_buffer_info = jni->CallObjectMethod(
1797 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001798 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001799 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001800 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001801 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001802
1803 int output_buffer_index =
1804 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1805 if (output_buffer_index == -1) {
1806 ResetCodec();
1807 return false;
1808 }
1809
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001810 // Get frame timestamps from a queue.
1811 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001812 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1813 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001814 int32_t timestamp = timestamps_.front();
1815 timestamps_.erase(timestamps_.begin());
1816 int64_t render_time_ms = render_times_ms_.front();
1817 render_times_ms_.erase(render_times_ms_.begin());
1818 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1819 frame_rtc_times_ms_.front();
1820 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001821 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001822
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001823 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001824 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001825 jobject j_output_buffer =
1826 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1827 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1828 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1829 uint8* payload = reinterpret_cast<uint8_t*>(
1830 jni->GetDirectBufferAddress(j_output_buffer));
1831 CHECK_EXCEPTION(jni);
1832
1833 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1834 " EncTime: %lld",
1835 output_buffer_index, payload_size, last_output_timestamp_ms_,
1836 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1837 frame_encoding_time_ms);
1838
1839 // Calculate and print encoding statistics - every 3 seconds.
1840 current_frames_++;
1841 current_bytes_ += payload_size;
1842 current_encoding_time_ms_ += frame_encoding_time_ms;
1843 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1844 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1845 current_frames_ > 0) {
1846 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1847 " encTime: %d for last %d ms",
1848 current_bytes_ * 8 / statistic_time_ms,
1849 last_set_bitrate_kbps_,
1850 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1851 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1852 start_time_ms_ = GetCurrentTimeMs();
1853 current_frames_ = 0;
1854 current_bytes_= 0;
1855 current_encoding_time_ms_ = 0;
1856 }
1857
1858 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001859 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001860 scoped_ptr<webrtc::EncodedImage> image(
1861 new webrtc::EncodedImage(payload, payload_size, payload_size));
1862 image->_encodedWidth = width_;
1863 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001864 image->_timeStamp = timestamp;
1865 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001866 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1867 image->_completeFrame = true;
1868
1869 webrtc::CodecSpecificInfo info;
1870 memset(&info, 0, sizeof(info));
1871 info.codecType = kVideoCodecVP8;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001872 info.codecSpecific.VP8.pictureId = picture_id_;
1873 info.codecSpecific.VP8.nonReference = false;
1874 info.codecSpecific.VP8.simulcastIdx = 0;
1875 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx;
1876 info.codecSpecific.VP8.layerSync = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001877 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1878 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001879 picture_id_ = (picture_id_ + 1) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001880
1881 // Generate a header describing a single fragment.
1882 webrtc::RTPFragmentationHeader header;
1883 memset(&header, 0, sizeof(header));
1884 header.VerifyAndAllocateFragmentationHeader(1);
1885 header.fragmentationOffset[0] = 0;
1886 header.fragmentationLength[0] = image->_length;
1887 header.fragmentationPlType[0] = 0;
1888 header.fragmentationTimeDiff[0] = 0;
1889
1890 callback_status = callback_->Encoded(*image, &info, &header);
1891 }
1892
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001893 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001894 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1895 j_release_output_buffer_method_,
1896 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001897 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001898 if (!success) {
1899 ResetCodec();
1900 return false;
1901 }
1902
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001903 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001904 drop_next_input_frame_ = true;
1905 // Theoretically could handle callback_status<0 here, but unclear what that
1906 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001907 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001908 }
1909
1910 return true;
1911}
1912
1913// Simplest-possible implementation of an encoder factory, churns out
1914// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1915class MediaCodecVideoEncoderFactory
1916 : public cricket::WebRtcVideoEncoderFactory {
1917 public:
1918 MediaCodecVideoEncoderFactory();
1919 virtual ~MediaCodecVideoEncoderFactory();
1920
1921 // WebRtcVideoEncoderFactory implementation.
1922 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1923 OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001924 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1925 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1926
1927 private:
1928 // Empty if platform support is lacking, const after ctor returns.
1929 std::vector<VideoCodec> supported_codecs_;
1930};
1931
1932MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1933 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1934 ScopedLocalRefFrame local_ref_frame(jni);
1935 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1936 bool is_platform_supported = jni->CallStaticBooleanMethod(
1937 j_encoder_class,
1938 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001939 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001940 if (!is_platform_supported)
1941 return;
1942
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001943 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1944 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1945 // reasonable defaults.
1946 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001947 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001948}
1949
1950MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1951
1952webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1953 webrtc::VideoCodecType type) {
1954 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1955 return NULL;
1956 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1957}
1958
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001959const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1960MediaCodecVideoEncoderFactory::codecs() const {
1961 return supported_codecs_;
1962}
1963
1964void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1965 webrtc::VideoEncoder* encoder) {
1966 delete encoder;
1967}
1968
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001969class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001970 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001971 public:
1972 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1973 virtual ~MediaCodecVideoDecoder();
1974
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001975 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1976
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001977 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1978 int32_t numberOfCores) OVERRIDE;
1979
1980 virtual int32_t
1981 Decode(const EncodedImage& inputImage, bool missingFrames,
1982 const RTPFragmentationHeader* fragmentation,
1983 const CodecSpecificInfo* codecSpecificInfo = NULL,
1984 int64_t renderTimeMs = -1) OVERRIDE;
1985
1986 virtual int32_t RegisterDecodeCompleteCallback(
1987 DecodedImageCallback* callback) OVERRIDE;
1988
1989 virtual int32_t Release() OVERRIDE;
1990
1991 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001992 // rtc::MessageHandler implementation.
1993 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001994
1995 private:
1996 // CHECK-fail if not running on |codec_thread_|.
1997 void CheckOnCodecThread();
1998
1999 int32_t InitDecodeOnCodecThread();
2000 int32_t ReleaseOnCodecThread();
2001 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002002 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
2003 // true on success.
2004 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
2005
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002006
2007 bool key_frame_required_;
2008 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002009 bool use_surface_;
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002010 int error_count_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002011 VideoCodec codec_;
2012 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002013 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002014 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002015 int frames_received_; // Number of frames received by decoder.
2016 int frames_decoded_; // Number of frames decoded by decoder
2017 int64_t start_time_ms_; // Start time for statistics.
2018 int current_frames_; // Number of frames in the current statistics interval.
2019 int current_bytes_; // Encoded bytes in the current statistics interval.
2020 int current_decoding_time_ms_; // Overall decoding time in the current second
2021 uint32_t max_pending_frames_; // Maximum number of pending input frames
2022 std::vector<int32_t> timestamps_;
2023 std::vector<int64_t> ntp_times_ms_;
2024 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
2025 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002026
2027 // State that is constant for the lifetime of this object once the ctor
2028 // returns.
2029 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
2030 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2031 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2032 jmethodID j_init_decode_method_;
2033 jmethodID j_release_method_;
2034 jmethodID j_dequeue_input_buffer_method_;
2035 jmethodID j_queue_input_buffer_method_;
2036 jmethodID j_dequeue_output_buffer_method_;
2037 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002038 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002039 jfieldID j_input_buffers_field_;
2040 jfieldID j_output_buffers_field_;
2041 jfieldID j_color_format_field_;
2042 jfieldID j_width_field_;
2043 jfieldID j_height_field_;
2044 jfieldID j_stride_field_;
2045 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002046 jfieldID j_surface_texture_field_;
2047 jfieldID j_textureID_field_;
2048 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2049 jfieldID j_info_index_field_;
2050 jfieldID j_info_offset_field_;
2051 jfieldID j_info_size_field_;
2052 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002053
2054 // Global references; must be deleted in Release().
2055 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002056 jobject surface_texture_;
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002057 jobject previous_surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002058
2059 // Render EGL context.
2060 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002061};
2062
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002063jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2064
2065int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2066 jobject render_egl_context) {
2067 if (render_egl_context_) {
2068 jni->DeleteGlobalRef(render_egl_context_);
2069 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002070 if (IsNull(jni, render_egl_context)) {
2071 render_egl_context_ = NULL;
2072 } else {
2073 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002074 CHECK_EXCEPTION(jni) << "error calling NewGlobalRef for EGL Context.";
2075 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
2076 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
2077 ALOGE("Wrong EGL Context.");
2078 jni->DeleteGlobalRef(render_egl_context_);
2079 render_egl_context_ = NULL;
2080 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002081 }
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002082 if (render_egl_context_ == NULL) {
2083 ALOGD("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
2084 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002085 return 0;
2086}
2087
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002088MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
2089 : key_frame_required_(true),
2090 inited_(false),
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002091 error_count_(0),
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002092 surface_texture_(NULL),
2093 previous_surface_texture_(NULL),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002094 codec_thread_(new Thread()),
2095 j_media_codec_video_decoder_class_(
2096 jni,
2097 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2098 j_media_codec_video_decoder_(
2099 jni,
2100 jni->NewObject(*j_media_codec_video_decoder_class_,
2101 GetMethodID(jni,
2102 *j_media_codec_video_decoder_class_,
2103 "<init>",
2104 "()V"))) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002105 ScopedLocalRefFrame local_ref_frame(jni);
2106 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002107 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002108
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002109 j_init_decode_method_ = GetMethodID(
2110 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002111 "(IIZZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002112 j_release_method_ =
2113 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2114 j_dequeue_input_buffer_method_ = GetMethodID(
2115 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2116 j_queue_input_buffer_method_ = GetMethodID(
2117 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2118 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002119 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2120 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002121 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002122 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002123
2124 j_input_buffers_field_ = GetFieldID(
2125 jni, *j_media_codec_video_decoder_class_,
2126 "inputBuffers", "[Ljava/nio/ByteBuffer;");
2127 j_output_buffers_field_ = GetFieldID(
2128 jni, *j_media_codec_video_decoder_class_,
2129 "outputBuffers", "[Ljava/nio/ByteBuffer;");
2130 j_color_format_field_ = GetFieldID(
2131 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2132 j_width_field_ = GetFieldID(
2133 jni, *j_media_codec_video_decoder_class_, "width", "I");
2134 j_height_field_ = GetFieldID(
2135 jni, *j_media_codec_video_decoder_class_, "height", "I");
2136 j_stride_field_ = GetFieldID(
2137 jni, *j_media_codec_video_decoder_class_, "stride", "I");
2138 j_slice_height_field_ = GetFieldID(
2139 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002140 j_textureID_field_ = GetFieldID(
2141 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2142 j_surface_texture_field_ = GetFieldID(
2143 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2144 "Landroid/graphics/SurfaceTexture;");
2145
2146 jclass j_decoder_output_buffer_info_class = FindClass(jni,
2147 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2148 j_info_index_field_ = GetFieldID(
2149 jni, j_decoder_output_buffer_info_class, "index", "I");
2150 j_info_offset_field_ = GetFieldID(
2151 jni, j_decoder_output_buffer_info_class, "offset", "I");
2152 j_info_size_field_ = GetFieldID(
2153 jni, j_decoder_output_buffer_info_class, "size", "I");
2154 j_info_presentation_timestamp_us_field_ = GetFieldID(
2155 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002156
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002157 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002158 use_surface_ = true;
2159 if (render_egl_context_ == NULL)
2160 use_surface_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002161 memset(&codec_, 0, sizeof(codec_));
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00002162 AllowBlockingCalls();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002163}
2164
2165MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002166 // Call Release() to ensure no more callbacks to us after we are deleted.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002167 Release();
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002168 // Delete global references.
2169 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2170 if (previous_surface_texture_ != NULL)
2171 jni->DeleteGlobalRef(previous_surface_texture_);
2172 if (surface_texture_ != NULL)
2173 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002174}
2175
2176int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2177 int32_t numberOfCores) {
2178 if (inst == NULL) {
2179 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2180 }
2181 int ret_val = Release();
2182 if (ret_val < 0) {
2183 return ret_val;
2184 }
2185 // Save VideoCodec instance for later.
2186 if (&codec_ != inst) {
2187 codec_ = *inst;
2188 }
2189 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2190
2191 // Always start with a complete key frame.
2192 key_frame_required_ = true;
2193 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002194 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002195
2196 // Call Java init.
2197 return codec_thread_->Invoke<int32_t>(
2198 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2199}
2200
2201int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2202 CheckOnCodecThread();
2203 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2204 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002205 ALOGD("InitDecodeOnCodecThread: %d x %d. Fps: %d. Errors: %d",
2206 codec_.width, codec_.height, codec_.maxFramerate, error_count_);
2207 bool use_sw_codec = false;
2208 if (error_count_ > 1) {
2209 // If more than one critical errors happen for HW codec, switch to SW codec.
2210 use_sw_codec = true;
2211 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002212
2213 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2214 j_init_decode_method_,
2215 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002216 codec_.height,
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002217 use_sw_codec,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002218 use_surface_,
2219 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002220 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002221 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002222 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002223 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002224 inited_ = true;
2225
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002226 max_pending_frames_ = 0;
2227 if (use_surface_) {
2228 max_pending_frames_ = 1;
2229 }
2230 start_time_ms_ = GetCurrentTimeMs();
2231 current_frames_ = 0;
2232 current_bytes_ = 0;
2233 current_decoding_time_ms_ = 0;
2234 timestamps_.clear();
2235 ntp_times_ms_.clear();
2236 frame_rtc_times_ms_.clear();
2237
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002238 jobjectArray input_buffers = (jobjectArray)GetObjectField(
2239 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2240 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002241 input_buffers_.resize(num_input_buffers);
2242 for (size_t i = 0; i < num_input_buffers; ++i) {
2243 input_buffers_[i] =
2244 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002245 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002246 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002247
2248 if (use_surface_) {
2249 jobject surface_texture = GetObjectField(
2250 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002251 if (previous_surface_texture_ != NULL) {
2252 jni->DeleteGlobalRef(previous_surface_texture_);
2253 }
2254 previous_surface_texture_ = surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002255 surface_texture_ = jni->NewGlobalRef(surface_texture);
2256 }
2257 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2258
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002259 return WEBRTC_VIDEO_CODEC_OK;
2260}
2261
2262int32_t MediaCodecVideoDecoder::Release() {
2263 return codec_thread_->Invoke<int32_t>(
2264 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2265}
2266
2267int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002268 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002269 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002270 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002271 CheckOnCodecThread();
2272 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2273 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2274 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002275 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002276 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002277 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002278 input_buffers_.clear();
2279 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002280 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002281 rtc::MessageQueueManager::Clear(this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002282 inited_ = false;
2283 return WEBRTC_VIDEO_CODEC_OK;
2284}
2285
2286
2287void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002288 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2289 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002290}
2291
2292int32_t MediaCodecVideoDecoder::Decode(
2293 const EncodedImage& inputImage,
2294 bool missingFrames,
2295 const RTPFragmentationHeader* fragmentation,
2296 const CodecSpecificInfo* codecSpecificInfo,
2297 int64_t renderTimeMs) {
2298 if (!inited_) {
2299 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2300 }
2301 if (callback_ == NULL) {
2302 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2303 }
2304 if (inputImage._buffer == NULL && inputImage._length > 0) {
2305 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2306 }
2307 // Check if encoded frame dimension has changed.
2308 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2309 (inputImage._encodedWidth != codec_.width ||
2310 inputImage._encodedHeight != codec_.height)) {
2311 codec_.width = inputImage._encodedWidth;
2312 codec_.height = inputImage._encodedHeight;
2313 InitDecode(&codec_, 1);
2314 }
2315
2316 // Always start with a complete key frame.
2317 if (key_frame_required_) {
2318 if (inputImage._frameType != webrtc::kKeyFrame) {
2319 return WEBRTC_VIDEO_CODEC_ERROR;
2320 }
2321 if (!inputImage._completeFrame) {
2322 return WEBRTC_VIDEO_CODEC_ERROR;
2323 }
2324 key_frame_required_ = false;
2325 }
2326 if (inputImage._length == 0) {
2327 return WEBRTC_VIDEO_CODEC_ERROR;
2328 }
2329
2330 return codec_thread_->Invoke<int32_t>(Bind(
2331 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2332}
2333
2334int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2335 const EncodedImage& inputImage) {
2336 static uint8_t yVal_ = 0x7f;
2337
2338 CheckOnCodecThread();
2339 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2340 ScopedLocalRefFrame local_ref_frame(jni);
2341
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002342 // Try to drain the decoder and wait until output is not too
2343 // much behind the input.
2344 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2345 ALOGV("Wait for output...");
2346 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002347 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002348 Reset();
2349 return WEBRTC_VIDEO_CODEC_ERROR;
2350 }
2351 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2352 ALOGE("Output buffer dequeue timeout");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002353 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002354 Reset();
2355 return WEBRTC_VIDEO_CODEC_ERROR;
2356 }
2357 }
2358
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002359 // Get input buffer.
2360 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2361 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002362 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002363 if (j_input_buffer_index < 0) {
2364 ALOGE("dequeueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002365 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002366 Reset();
2367 return WEBRTC_VIDEO_CODEC_ERROR;
2368 }
2369
2370 // Copy encoded data to Java ByteBuffer.
2371 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2372 uint8* buffer =
2373 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002374 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002375 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002376 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002377 if (buffer_capacity < inputImage._length) {
2378 ALOGE("Input frame size %d is bigger than buffer size %d.",
2379 inputImage._length, buffer_capacity);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002380 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002381 Reset();
2382 return WEBRTC_VIDEO_CODEC_ERROR;
2383 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002384 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002385 frames_received_, j_input_buffer_index, inputImage._length);
2386 memcpy(buffer, inputImage._buffer, inputImage._length);
2387
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002388 // Save input image timestamps for later output.
2389 frames_received_++;
2390 current_bytes_ += inputImage._length;
2391 timestamps_.push_back(inputImage._timeStamp);
2392 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2393 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2394
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002395 // Feed input to decoder.
2396 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2397 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2398 j_queue_input_buffer_method_,
2399 j_input_buffer_index,
2400 inputImage._length,
2401 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002402 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002403 if (!success) {
2404 ALOGE("queueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002405 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002406 Reset();
2407 return WEBRTC_VIDEO_CODEC_ERROR;
2408 }
2409
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002410 // Try to drain the decoder
2411 if (!DeliverPendingOutputs(jni, 0)) {
2412 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002413 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002414 Reset();
2415 return WEBRTC_VIDEO_CODEC_ERROR;
2416 }
2417
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002418 return WEBRTC_VIDEO_CODEC_OK;
2419}
2420
2421bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2422 JNIEnv* jni, int dequeue_timeout_us) {
2423 if (frames_received_ <= frames_decoded_) {
2424 // No need to query for output buffers - decoder is drained.
2425 return true;
2426 }
2427 // Get decoder output.
2428 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2429 *j_media_codec_video_decoder_,
2430 j_dequeue_output_buffer_method_,
2431 dequeue_timeout_us);
2432
2433 CHECK_EXCEPTION(jni);
2434 if (IsNull(jni, j_decoder_output_buffer_info)) {
2435 return true;
2436 }
2437
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002438 // Extract output buffer info from Java DecoderOutputBufferInfo.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002439 int output_buffer_index =
2440 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2441 if (output_buffer_index < 0) {
2442 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002443 return false;
2444 }
2445 int output_buffer_offset =
2446 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2447 int output_buffer_size =
2448 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2449 CHECK_EXCEPTION(jni);
2450
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002451 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002452 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2453 j_color_format_field_);
2454 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2455 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2456 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2457 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2458 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002459 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2460 j_textureID_field_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002461
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002462 // Extract data from Java ByteBuffer and create output yuv420 frame -
2463 // for non surface decoding only.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002464 if (!use_surface_) {
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002465 if (output_buffer_size < width * height * 3 / 2) {
2466 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002467 return false;
2468 }
2469 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2470 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2471 jobject output_buffer =
2472 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
2473 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
2474 output_buffer));
2475 CHECK_EXCEPTION(jni);
2476 payload += output_buffer_offset;
2477
2478 // Create yuv420 frame.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002479 if (color_format == COLOR_FormatYUV420Planar) {
2480 decoded_image_.CreateFrame(
2481 stride * slice_height, payload,
2482 (stride * slice_height) / 4, payload + (stride * slice_height),
2483 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2484 width, height,
2485 stride, stride / 2, stride / 2);
2486 } else {
2487 // All other supported formats are nv12.
2488 decoded_image_.CreateEmptyFrame(width, height, width,
2489 width / 2, width / 2);
2490 libyuv::NV12ToI420(
2491 payload, stride,
2492 payload + stride * slice_height, stride,
2493 decoded_image_.buffer(webrtc::kYPlane),
2494 decoded_image_.stride(webrtc::kYPlane),
2495 decoded_image_.buffer(webrtc::kUPlane),
2496 decoded_image_.stride(webrtc::kUPlane),
2497 decoded_image_.buffer(webrtc::kVPlane),
2498 decoded_image_.stride(webrtc::kVPlane),
2499 width, height);
2500 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002501 }
2502
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002503 // Get frame timestamps from a queue.
2504 int32_t timestamp = timestamps_.front();
2505 timestamps_.erase(timestamps_.begin());
2506 int64_t ntp_time_ms = ntp_times_ms_.front();
2507 ntp_times_ms_.erase(ntp_times_ms_.begin());
2508 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2509 frame_rtc_times_ms_.front();
2510 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2511
2512 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2513 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2514 color_format, output_buffer_size, frame_decoding_time_ms);
2515
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002516 // Return output buffer back to codec.
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002517 bool success = jni->CallBooleanMethod(
2518 *j_media_codec_video_decoder_,
2519 j_release_output_buffer_method_,
2520 output_buffer_index,
2521 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002522 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002523 if (!success) {
2524 ALOGE("releaseOutputBuffer error");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002525 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002526 }
2527
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002528 // Calculate and print decoding statistics - every 3 seconds.
2529 frames_decoded_++;
2530 current_frames_++;
2531 current_decoding_time_ms_ += frame_decoding_time_ms;
2532 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2533 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2534 current_frames_ > 0) {
2535 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2536 current_bytes_ * 8 / statistic_time_ms,
2537 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2538 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2539 start_time_ms_ = GetCurrentTimeMs();
2540 current_frames_ = 0;
2541 current_bytes_= 0;
2542 current_decoding_time_ms_ = 0;
2543 }
2544
2545 // Callback - output decoded frame.
2546 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2547 if (use_surface_) {
2548 native_handle_.SetTextureObject(surface_texture_, texture_id);
2549 TextureVideoFrame texture_image(
2550 &native_handle_, width, height, timestamp, 0);
2551 texture_image.set_ntp_time_ms(ntp_time_ms);
2552 callback_status = callback_->Decoded(texture_image);
2553 } else {
2554 decoded_image_.set_timestamp(timestamp);
2555 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2556 callback_status = callback_->Decoded(decoded_image_);
2557 }
2558 if (callback_status > 0) {
2559 ALOGE("callback error");
2560 }
2561
2562 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002563}
2564
2565int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2566 DecodedImageCallback* callback) {
2567 callback_ = callback;
2568 return WEBRTC_VIDEO_CODEC_OK;
2569}
2570
2571int32_t MediaCodecVideoDecoder::Reset() {
2572 ALOGD("DecoderReset");
2573 if (!inited_) {
2574 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2575 }
2576 return InitDecode(&codec_, 1);
2577}
2578
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002579void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002580 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2581 ScopedLocalRefFrame local_ref_frame(jni);
2582 if (!inited_) {
2583 return;
2584 }
2585 // We only ever send one message to |this| directly (not through a Bind()'d
2586 // functor), so expect no ID/data.
2587 CHECK(!msg->message_id) << "Unexpected message!";
2588 CHECK(!msg->pdata) << "Unexpected message!";
2589 CheckOnCodecThread();
2590
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002591 if (!DeliverPendingOutputs(jni, 0)) {
2592 error_count_++;
2593 Reset();
2594 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002595 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002596}
2597
2598class MediaCodecVideoDecoderFactory
2599 : public cricket::WebRtcVideoDecoderFactory {
2600 public:
2601 MediaCodecVideoDecoderFactory();
2602 virtual ~MediaCodecVideoDecoderFactory();
2603 // WebRtcVideoDecoderFactory implementation.
2604 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2605 webrtc::VideoCodecType type) OVERRIDE;
2606
2607 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2608
2609 private:
2610 bool is_platform_supported_;
2611};
2612
2613MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2614 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2615 ScopedLocalRefFrame local_ref_frame(jni);
2616 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2617 is_platform_supported_ = jni->CallStaticBooleanMethod(
2618 j_decoder_class,
2619 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002620 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002621}
2622
2623MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2624
2625webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2626 webrtc::VideoCodecType type) {
2627 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2628 return NULL;
2629 }
2630 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2631}
2632
2633
2634void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2635 webrtc::VideoDecoder* decoder) {
2636 delete decoder;
2637}
2638
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002639#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002640
2641} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002642
2643// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2644// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2645#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2646 Java_org_webrtc_##name
2647
2648extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002649 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002650 g_jvm = jvm;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002651 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002652
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002653 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002654
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002655 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002656
2657 JNIEnv* jni;
2658 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2659 return -1;
2660 g_class_reference_holder = new ClassReferenceHolder(jni);
2661
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002662 return JNI_VERSION_1_6;
2663}
2664
2665extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002666 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002667 delete g_class_reference_holder;
2668 g_class_reference_holder = NULL;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002669 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002670 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002671}
2672
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002673static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002674 jfieldID native_dc_id = GetFieldID(jni,
2675 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2676 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002677 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002678}
2679
2680JOW(jlong, DataChannel_registerObserverNative)(
2681 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002682 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002683 new DataChannelObserverWrapper(jni, j_observer));
2684 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002685 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002686}
2687
2688JOW(void, DataChannel_unregisterObserverNative)(
2689 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2690 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2691 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2692}
2693
2694JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2695 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2696}
2697
2698JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2699 return JavaEnumFromIndex(
2700 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2701}
2702
2703JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2704 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002705 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2706 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002707 return static_cast<jlong>(buffered_amount);
2708}
2709
2710JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2711 ExtractNativeDC(jni, j_dc)->Close();
2712}
2713
2714JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2715 jbyteArray data, jboolean binary) {
2716 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2717 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002718 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002719 binary));
2720 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2721 return ret;
2722}
2723
2724JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002725 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002726}
2727
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002728JOW(void, Logging_nativeEnableTracing)(
2729 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2730 jint nativeSeverity) {
2731 std::string path = JavaToStdString(jni, j_path);
2732 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002733 webrtc::Trace::set_level_filter(nativeLevels);
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002734#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002735 if (path != "logcat:") {
2736#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002737 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2738 << "SetTraceFile failed";
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002739#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002740 } else {
2741 // Intentionally leak this to avoid needing to reason about its lifecycle.
2742 // It keeps no state and functions only as a dispatch point.
2743 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2744 }
2745#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002746 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002747 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002748}
2749
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002751 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002752}
2753
2754JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2755 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2756 delete p;
2757}
2758
2759JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002760 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002761}
2762
2763JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2764 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2765}
2766
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002767JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002768 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2769}
2770
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002771JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2772 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2773}
2774
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002775JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002776 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777}
2778
2779JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2780 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002781 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002782 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002783}
2784
2785JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2786 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002787 return reinterpret_cast<MediaStreamInterface*>(pointer)
2788 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002789}
2790
2791JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2792 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002793 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002794 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002795}
2796
2797JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2798 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002799 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002800 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002801}
2802
2803JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2804 return JavaStringFromStdString(
2805 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2806}
2807
2808JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002809 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002810}
2811
2812JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2813 JNIEnv * jni, jclass, jobject j_observer) {
2814 return (jlong)new PCOJava(jni, j_observer);
2815}
2816
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002817#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002818JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002819 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002820 jboolean initialize_audio, jboolean initialize_video,
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002821 jboolean vp8_hw_acceleration, jobject render_egl_context) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002822 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002823 bool failure = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002824 vp8_hw_acceleration_enabled = vp8_hw_acceleration;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002825 if (!factory_static_initialized) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002826 if (initialize_video) {
2827 failure |= webrtc::SetCaptureAndroidVM(g_jvm, context);
2828 failure |= webrtc::SetRenderAndroidVM(g_jvm);
2829 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002830 if (initialize_audio)
2831 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2832 factory_static_initialized = true;
2833 }
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002834 if (initialize_video)
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002835 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2836 render_egl_context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002837 return !failure;
2838}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002839#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002840
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002841// Helper struct for working around the fact that CreatePeerConnectionFactory()
2842// comes in two flavors: either entirely automagical (constructing its own
2843// threads and deleting them on teardown, but no external codec factory support)
2844// or entirely manual (requires caller to delete threads after factory
2845// teardown). This struct takes ownership of its ctor's arguments to present a
2846// single thing for Java to hold and eventually free.
2847class OwnedFactoryAndThreads {
2848 public:
2849 OwnedFactoryAndThreads(Thread* worker_thread,
2850 Thread* signaling_thread,
2851 PeerConnectionFactoryInterface* factory)
2852 : worker_thread_(worker_thread),
2853 signaling_thread_(signaling_thread),
2854 factory_(factory) {}
2855
2856 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2857
2858 PeerConnectionFactoryInterface* factory() { return factory_; }
2859
2860 private:
2861 const scoped_ptr<Thread> worker_thread_;
2862 const scoped_ptr<Thread> signaling_thread_;
2863 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2864};
2865
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002866JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2867 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002868 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2869 // ThreadManager only WrapCurrentThread()s the thread where it is first
2870 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002871 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002872 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002873 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002874 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002875 Thread* worker_thread = new Thread();
2876 worker_thread->SetName("worker_thread", NULL);
2877 Thread* signaling_thread = new Thread();
2878 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002879 CHECK(worker_thread->Start() && signaling_thread->Start())
2880 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002881 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002882 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002883#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002884 if (vp8_hw_acceleration_enabled) {
2885 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
2886 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
2887 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002888#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002889 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002890 webrtc::CreatePeerConnectionFactory(worker_thread,
2891 signaling_thread,
2892 NULL,
2893 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002894 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002895 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2896 worker_thread, signaling_thread, factory.release());
2897 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898}
2899
2900JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002901 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002902 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002903}
2904
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002905static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2906 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2907}
2908
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002909JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2910 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002911 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002912 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002913 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002914 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2915 return (jlong)stream.release();
2916}
2917
2918JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2919 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2920 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002921 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002922 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002923 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002924 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002925 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002926 factory->CreateVideoSource(
2927 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2928 constraints.get()));
2929 return (jlong)source.release();
2930}
2931
2932JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2933 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2934 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002935 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002936 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002937 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002938 factory->CreateVideoTrack(
2939 JavaToStdString(jni, id),
2940 reinterpret_cast<VideoSourceInterface*>(native_source)));
2941 return (jlong)track.release();
2942}
2943
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002944JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2945 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2946 scoped_ptr<ConstraintsWrapper> constraints(
2947 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002948 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002949 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002950 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002951 factory->CreateAudioSource(constraints.get()));
2952 return (jlong)source.release();
2953}
2954
2955JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2956 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2957 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002958 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002959 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002960 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002961 JavaToStdString(jni, id),
2962 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963 return (jlong)track.release();
2964}
2965
2966static void JavaIceServersToJsepIceServers(
2967 JNIEnv* jni, jobject j_ice_servers,
2968 PeerConnectionInterface::IceServers* ice_servers) {
2969 jclass list_class = GetObjectClass(jni, j_ice_servers);
2970 jmethodID iterator_id = GetMethodID(
2971 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2972 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002973 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002974 jmethodID iterator_has_next = GetMethodID(
2975 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2976 jmethodID iterator_next = GetMethodID(
2977 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2978 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002979 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002980 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002981 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002982 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2983 jfieldID j_ice_server_uri_id =
2984 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2985 jfieldID j_ice_server_username_id =
2986 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2987 jfieldID j_ice_server_password_id =
2988 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2989 jstring uri = reinterpret_cast<jstring>(
2990 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2991 jstring username = reinterpret_cast<jstring>(
2992 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2993 jstring password = reinterpret_cast<jstring>(
2994 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2995 PeerConnectionInterface::IceServer server;
2996 server.uri = JavaToStdString(jni, uri);
2997 server.username = JavaToStdString(jni, username);
2998 server.password = JavaToStdString(jni, password);
2999 ice_servers->push_back(server);
3000 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003001 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003002}
3003
3004JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
3005 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
3006 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003007 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003008 reinterpret_cast<PeerConnectionFactoryInterface*>(
3009 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003010 PeerConnectionInterface::IceServers servers;
3011 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
3012 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
3013 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003014 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00003015 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003016 return (jlong)pc.release();
3017}
3018
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003019static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003020 JNIEnv* jni, jobject j_pc) {
3021 jfieldID native_pc_id = GetFieldID(jni,
3022 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
3023 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003024 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003025 reinterpret_cast<PeerConnectionInterface*>(j_p));
3026}
3027
3028JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
3029 const SessionDescriptionInterface* sdp =
3030 ExtractNativePC(jni, j_pc)->local_description();
3031 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3032}
3033
3034JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
3035 const SessionDescriptionInterface* sdp =
3036 ExtractNativePC(jni, j_pc)->remote_description();
3037 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3038}
3039
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003040JOW(jobject, PeerConnection_createDataChannel)(
3041 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
3042 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003043 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003044 ExtractNativePC(jni, j_pc)->CreateDataChannel(
3045 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00003046 // Mustn't pass channel.get() directly through NewObject to avoid reading its
3047 // vararg parameter as 64-bit and reading memory that doesn't belong to the
3048 // 32-bit parameter.
3049 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003050 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003051 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
3052 jmethodID j_data_channel_ctor = GetMethodID(
3053 jni, j_data_channel_class, "<init>", "(J)V");
3054 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00003055 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003056 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003057 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003058 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003059 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003060 return j_channel;
3061}
3062
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003063JOW(void, PeerConnection_createOffer)(
3064 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3065 ConstraintsWrapper* constraints =
3066 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003067 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3068 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003069 jni, j_observer, constraints));
3070 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3071}
3072
3073JOW(void, PeerConnection_createAnswer)(
3074 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3075 ConstraintsWrapper* constraints =
3076 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003077 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3078 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003079 jni, j_observer, constraints));
3080 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3081}
3082
3083// Helper to create a SessionDescriptionInterface from a SessionDescription.
3084static SessionDescriptionInterface* JavaSdpToNativeSdp(
3085 JNIEnv* jni, jobject j_sdp) {
3086 jfieldID j_type_id = GetFieldID(
3087 jni, GetObjectClass(jni, j_sdp), "type",
3088 "Lorg/webrtc/SessionDescription$Type;");
3089 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3090 jmethodID j_canonical_form_id = GetMethodID(
3091 jni, GetObjectClass(jni, j_type), "canonicalForm",
3092 "()Ljava/lang/String;");
3093 jstring j_type_string = (jstring)jni->CallObjectMethod(
3094 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003095 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003096 std::string std_type = JavaToStdString(jni, j_type_string);
3097
3098 jfieldID j_description_id = GetFieldID(
3099 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3100 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3101 std::string std_description = JavaToStdString(jni, j_description);
3102
3103 return webrtc::CreateSessionDescription(
3104 std_type, std_description, NULL);
3105}
3106
3107JOW(void, PeerConnection_setLocalDescription)(
3108 JNIEnv* jni, jobject j_pc,
3109 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003110 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3111 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003112 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3113 ExtractNativePC(jni, j_pc)->SetLocalDescription(
3114 observer, JavaSdpToNativeSdp(jni, j_sdp));
3115}
3116
3117JOW(void, PeerConnection_setRemoteDescription)(
3118 JNIEnv* jni, jobject j_pc,
3119 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003120 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3121 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003122 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3123 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3124 observer, JavaSdpToNativeSdp(jni, j_sdp));
3125}
3126
3127JOW(jboolean, PeerConnection_updateIce)(
3128 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3129 PeerConnectionInterface::IceServers ice_servers;
3130 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003131 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003132 new ConstraintsWrapper(jni, j_constraints));
3133 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3134}
3135
3136JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3137 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3138 jint j_sdp_mline_index, jstring j_candidate_sdp) {
3139 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3140 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003141 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003142 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3143 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3144}
3145
3146JOW(jboolean, PeerConnection_nativeAddLocalStream)(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003147 JNIEnv* jni, jobject j_pc, jlong native_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003148 return ExtractNativePC(jni, j_pc)->AddStream(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003149 reinterpret_cast<MediaStreamInterface*>(native_stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003150}
3151
3152JOW(void, PeerConnection_nativeRemoveLocalStream)(
3153 JNIEnv* jni, jobject j_pc, jlong native_stream) {
3154 ExtractNativePC(jni, j_pc)->RemoveStream(
3155 reinterpret_cast<MediaStreamInterface*>(native_stream));
3156}
3157
3158JOW(bool, PeerConnection_nativeGetStats)(
3159 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003160 rtc::scoped_refptr<StatsObserverWrapper> observer(
3161 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003162 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00003163 observer,
3164 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3165 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003166}
3167
3168JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3169 PeerConnectionInterface::SignalingState state =
3170 ExtractNativePC(jni, j_pc)->signaling_state();
3171 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3172}
3173
3174JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3175 PeerConnectionInterface::IceConnectionState state =
3176 ExtractNativePC(jni, j_pc)->ice_connection_state();
3177 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3178}
3179
3180JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
3181 PeerConnectionInterface::IceGatheringState state =
3182 ExtractNativePC(jni, j_pc)->ice_gathering_state();
3183 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
3184}
3185
3186JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3187 ExtractNativePC(jni, j_pc)->Close();
3188 return;
3189}
3190
3191JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003192 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003193 reinterpret_cast<MediaSourceInterface*>(j_p));
3194 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3195}
3196
3197JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
3198 JNIEnv* jni, jclass, jstring j_device_name) {
3199 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003200 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003201 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003202 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003203 cricket::Device device;
3204 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003205 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003206 return 0;
3207 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003208 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003209 device_manager->CreateVideoCapturer(device));
3210 return (jlong)capturer.release();
3211}
3212
3213JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3214 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003215 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3216 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003217 return (jlong)renderer.release();
3218}
3219
3220JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3221 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003222 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003223 new JavaVideoRendererWrapper(jni, j_callbacks));
3224 return (jlong)renderer.release();
3225}
3226
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003227JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3228 cricket::VideoCapturer* capturer =
3229 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003230 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003231 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3232 capturer->Stop();
3233 return jlongFromPointer(format.release());
3234}
3235
3236JOW(void, VideoSource_restart)(
3237 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003238 CHECK(j_p_source);
3239 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003240 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003241 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3242 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3243 StartCapturing(cricket::VideoFormat(*format));
3244}
3245
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00003246JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003247 JNIEnv* jni, jclass, jlong j_p) {
3248 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3249}
3250
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003251JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003252 return JavaStringFromStdString(
3253 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003254}
3255
3256JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003257 return JavaStringFromStdString(
3258 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003259}
3260
3261JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003262 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003263}
3264
3265JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003266 return JavaEnumFromIndex(
3267 jni,
3268 "MediaStreamTrack$State",
3269 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003270}
3271
3272JOW(jboolean, MediaStreamTrack_nativeSetState)(
3273 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003274 MediaStreamTrackInterface::TrackState new_state =
3275 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003276 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3277 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003278}
3279
3280JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3281 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003282 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3283 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003284}
3285
3286JOW(void, VideoTrack_nativeAddRenderer)(
3287 JNIEnv* jni, jclass,
3288 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003289 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003290 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3291}
3292
3293JOW(void, VideoTrack_nativeRemoveRenderer)(
3294 JNIEnv* jni, jclass,
3295 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003296 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003297 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3298}