blob: 43faa9ce7dad29073b808a77f58dcedcc589170b [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
fischman@webrtc.org33584f92013-07-25 16:43:30 +00003 * Copyright 2013, Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Hints for future visitors:
29// This entire file is an implementation detail of the org.webrtc Java package,
30// the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31// The layout of this file is roughly:
32// - various helper C++ functions & classes that wrap Java counterparts and
33// expose a C++ interface that can be passed to the C++ PeerConnection APIs
34// - implementations of methods declared "static" in the Java package (named
35// things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36// the JNI spec).
37//
38// Lifecycle notes: objects are owned where they will be called; in other words
39// FooObservers are owned by C++-land, and user-callable objects (e.g.
40// PeerConnection and VideoTrack) are owned by Java-land.
41// When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42// ref simulating the jlong held in Java-land, and then Release()s the ref in
43// the respective free call. Sometimes this AddRef is implicit in the
44// construction of a scoped_refptr<> which is then .release()d.
45// Any persistent (non-local) references from C++ to Java must be global or weak
46// (in which case they must be checked before use)!
47//
48// Exception notes: pretty much all JNI calls can throw Java exceptions, so each
49// call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50// call. In this file this is done in CHECK_EXCEPTION, making for much easier
51// debugging in case of failure (the alternative is to wait for control to
52// return to the Java frame that called code in this file, at which point it's
53// impossible to tell which JNI call broke).
54
55#include <jni.h>
56#undef JNIEXPORT
57#define JNIEXPORT __attribute__((visibility("default")))
58
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000059#include <asm/unistd.h>
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000060#include <sys/prctl.h>
61#include <sys/syscall.h>
fischman@webrtc.orgeb7def22013-12-09 21:34:30 +000062#include <unistd.h>
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000063#include <limits>
64#include <map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66#include "talk/app/webrtc/mediaconstraintsinterface.h"
67#include "talk/app/webrtc/peerconnectioninterface.h"
68#include "talk/app/webrtc/videosourceinterface.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069#include "talk/media/base/videocapturer.h"
70#include "talk/media/base/videorenderer.h"
71#include "talk/media/devices/videorendererfactory.h"
72#include "talk/media/webrtc/webrtcvideocapturer.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000073#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000074#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000075#include "third_party/icu/source/common/unicode/unistr.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000076#include "third_party/libyuv/include/libyuv/convert.h"
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +000077#include "third_party/libyuv/include/libyuv/convert_from.h"
78#include "third_party/libyuv/include/libyuv/video_common.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000079#include "webrtc/base/bind.h"
andresp@webrtc.org4d19e052014-09-09 11:45:44 +000080#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000081#include "webrtc/base/logging.h"
82#include "webrtc/base/messagequeue.h"
83#include "webrtc/base/ssladapter.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000084#include "webrtc/common_video/interface/texture_video_frame.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000085#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000086#include "webrtc/system_wrappers/interface/compile_assert.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;
134using webrtc::VideoRendererInterface;
135using webrtc::VideoSourceInterface;
136using webrtc::VideoTrackInterface;
137using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000138using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000140// Abort the process if |jni| has a Java exception pending.
141// This macros uses the comma operator to execute ExceptionDescribe
142// and ExceptionClear ignoring their return values and sending ""
143// to the error stream.
144#define CHECK_EXCEPTION(jni) \
145 CHECK(!jni->ExceptionCheck()) \
146 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000148// Helper that calls ptr->Release() and aborts the process with a useful
149// message if that didn't actually delete *ptr because of extra refcounts.
150#define CHECK_RELEASE(ptr) \
151 CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000152
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153namespace {
154
155static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
156
157static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000158// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
159// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
160// were attached by the JVM because of a Java->native call.
161static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000163#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
164// Set in PeerConnectionFactory_initializeAndroidGlobals().
165static bool factory_static_initialized = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +0000166static bool vp8_hw_acceleration_enabled = true;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000167#endif
168
169
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000170// Return thread ID as a string.
171static std::string GetThreadId() {
172 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000173 CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
174 sizeof(buf))
175 << "Thread id is bigger than uint64??";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000176 return std::string(buf);
177}
178
179// Return the current thread's name.
180static std::string GetThreadName() {
181 char name[17];
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000182 CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000183 name[16] = '\0';
184 return std::string(name);
185}
186
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000187// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
188static JNIEnv* GetEnv() {
189 void* env = NULL;
190 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
191 CHECK(((env != NULL) && (status == JNI_OK)) ||
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000192 ((env == NULL) && (status == JNI_EDETACHED)))
193 << "Unexpected GetEnv return: " << status << ":" << env;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000194 return reinterpret_cast<JNIEnv*>(env);
195}
196
197static void ThreadDestructor(void* prev_jni_ptr) {
198 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
199 // we were responsible for originally attaching the thread, so are responsible
200 // for detaching it now. However, because some JVM implementations (notably
201 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
202 // the JVMs accounting info for this thread may already be wiped out by the
203 // time this is called. Thus it may appear we are already detached even though
204 // it was our responsibility to detach! Oh well.
205 if (!GetEnv())
206 return;
207
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000208 CHECK(GetEnv() == prev_jni_ptr)
209 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210 jint status = g_jvm->DetachCurrentThread();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000211 CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
212 CHECK(!GetEnv()) << "Detaching was a successful no-op???";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000213}
214
215static void CreateJNIPtrKey() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000216 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
217 << "pthread_key_create";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218}
219
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000220// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000222 JNIEnv* jni = GetEnv();
223 if (jni)
224 return jni;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000225 CHECK(!pthread_getspecific(g_jni_ptr))
226 << "TLS has a JNIEnv* but not attached?";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000227
228 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
229 JavaVMAttachArgs args;
230 args.version = JNI_VERSION_1_6;
231 args.name = name;
232 args.group = NULL;
233 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000235 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000236#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000237 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000238#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000239 CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000240 free(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000241 CHECK(env) << "AttachCurrentThread handed back NULL!";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000242 jni = reinterpret_cast<JNIEnv*>(env);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000243 CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 return jni;
245}
246
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000247// Return a |jlong| that will correctly convert back to |ptr|. This is needed
248// because the alternative (of silently passing a 32-bit pointer to a vararg
249// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000250static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000251 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000252 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000253 // Going through intptr_t to be obvious about the definedness of the
254 // conversion from pointer to integral type. intptr_t to jlong is a standard
255 // widening by the COMPILE_ASSERT above.
256 jlong ret = reinterpret_cast<intptr_t>(ptr);
257 assert(reinterpret_cast<void*>(ret) == ptr);
258 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000259}
260
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261// Android's FindClass() is trickier than usual because the app-specific
262// ClassLoader is not consulted when there is no app-specific frame on the
263// stack. Consequently, we only look up classes once in JNI_OnLoad.
264// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
265class ClassReferenceHolder {
266 public:
267 explicit ClassReferenceHolder(JNIEnv* jni) {
268 LoadClass(jni, "java/nio/ByteBuffer");
269 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000270 LoadClass(jni, "org/webrtc/DataChannel");
271 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
272 LoadClass(jni, "org/webrtc/DataChannel$Init");
273 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 LoadClass(jni, "org/webrtc/IceCandidate");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000275#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
276 LoadClass(jni, "android/graphics/SurfaceTexture");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000277 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
278 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000279 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000280 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
glaznev@webrtc.orga8c0edd2014-10-20 19:08:05 +0000281 jclass j_decoder_class = GetClass("org/webrtc/MediaCodecVideoDecoder");
282 jmethodID j_is_egl14_supported_method = jni->GetStaticMethodID(
283 j_decoder_class, "isEGL14Supported", "()Z");
284 bool is_egl14_supported = jni->CallStaticBooleanMethod(
285 j_decoder_class, j_is_egl14_supported_method);
286 CHECK_EXCEPTION(jni);
287 if (is_egl14_supported) {
288 LoadClass(jni, "android/opengl/EGLContext");
289 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000290#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291 LoadClass(jni, "org/webrtc/MediaSource$State");
292 LoadClass(jni, "org/webrtc/MediaStream");
293 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
295 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000296 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000297 LoadClass(jni, "org/webrtc/SessionDescription");
298 LoadClass(jni, "org/webrtc/SessionDescription$Type");
299 LoadClass(jni, "org/webrtc/StatsReport");
300 LoadClass(jni, "org/webrtc/StatsReport$Value");
301 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
302 LoadClass(jni, "org/webrtc/VideoTrack");
303 }
304
305 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000306 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 }
308
309 void FreeReferences(JNIEnv* jni) {
310 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
311 it != classes_.end(); ++it) {
312 jni->DeleteGlobalRef(it->second);
313 }
314 classes_.clear();
315 }
316
317 jclass GetClass(const std::string& name) {
318 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000319 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320 return it->second;
321 }
322
323 private:
324 void LoadClass(JNIEnv* jni, const std::string& name) {
325 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000326 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
327 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000328 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000329 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
330 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000332 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333 }
334
335 std::map<std::string, jclass> classes_;
336};
337
338// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
339static ClassReferenceHolder* g_class_reference_holder = NULL;
340
341// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
342// object/class/method/field is non-null.
343jmethodID GetMethodID(
344 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
345 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000346 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
347 << signature;
348 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 return m;
350}
351
352jmethodID GetStaticMethodID(
353 JNIEnv* jni, jclass c, const char* name, const char* signature) {
354 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000355 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
356 << signature;
357 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000358 return m;
359}
360
361jfieldID GetFieldID(
362 JNIEnv* jni, jclass c, const char* name, const char* signature) {
363 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000364 CHECK_EXCEPTION(jni) << "error during GetFieldID";
365 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000366 return f;
367}
368
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000369// Returns a global reference guaranteed to be valid for the lifetime of the
370// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371jclass FindClass(JNIEnv* jni, const char* name) {
372 return g_class_reference_holder->GetClass(name);
373}
374
375jclass GetObjectClass(JNIEnv* jni, jobject object) {
376 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000377 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000378 CHECK(c) << "GetObjectClass returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000379 return c;
380}
381
382jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
383 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000384 CHECK_EXCEPTION(jni) << "error during GetObjectField";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000385 CHECK(o) << "GetObjectField returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386 return o;
387}
388
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000389jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
390 return static_cast<jstring>(GetObjectField(jni, object, id));
391}
392
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
394 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000395 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 return l;
397}
398
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000399jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
400 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000401 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000402 return i;
403}
404
405bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
406 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000407 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000408 return b;
409}
410
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411jobject NewGlobalRef(JNIEnv* jni, jobject o) {
412 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000413 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
414 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 return ret;
416}
417
418void DeleteGlobalRef(JNIEnv* jni, jobject o) {
419 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000420 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421}
422
423// Given a jweak reference, allocate a (strong) local reference scoped to the
424// lifetime of this object if the weak reference is still valid, or NULL
425// otherwise.
426class WeakRef {
427 public:
428 WeakRef(JNIEnv* jni, jweak ref)
429 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000430 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431 }
432 ~WeakRef() {
433 if (obj_) {
434 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000435 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 }
437 }
438 jobject obj() { return obj_; }
439
440 private:
441 JNIEnv* const jni_;
442 jobject const obj_;
443};
444
fischman@webrtc.org41776152014-01-09 00:31:17 +0000445// Scope Java local references to the lifetime of this object. Use in all C++
446// callbacks (i.e. entry points that don't originate in a Java callstack
447// through a "native" method call).
448class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000450 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000451 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000453 ~ScopedLocalRefFrame() {
454 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000456
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 private:
458 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000459};
460
461// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000462template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463class ScopedGlobalRef {
464 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000465 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000466 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000467 ~ScopedGlobalRef() {
468 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
469 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000470 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 return obj_;
472 }
473 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000474 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475};
476
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000477// Java references to "null" can only be distinguished as such in C++ by
478// creating a local reference, so this helper wraps that logic.
479static bool IsNull(JNIEnv* jni, jobject obj) {
480 ScopedLocalRefFrame local_ref_frame(jni);
481 return jni->NewLocalRef(obj) == NULL;
482}
483
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484// Return the (singleton) Java Enum object corresponding to |index|;
485// |state_class_fragment| is something like "MediaSource$State".
486jobject JavaEnumFromIndex(
487 JNIEnv* jni, const std::string& state_class_fragment, int index) {
488 std::string state_class_name = "org/webrtc/" + state_class_fragment;
489 jclass state_class = FindClass(jni, state_class_name.c_str());
490 jmethodID state_values_id = GetStaticMethodID(
491 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000492 jobjectArray state_values = static_cast<jobjectArray>(
493 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000494 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000495 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000496 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 return ret;
498}
499
500// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
501static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
502 UnicodeString ustr(UnicodeString::fromUTF8(native));
503 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000504 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 return jstr;
506}
507
508// Given a (UTF-16) jstring return a new UTF-8 native string.
509static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
510 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000511 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000513 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000515 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 std::string ret;
517 return ustr.toUTF8String(ret);
518}
519
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000520static DataChannelInit JavaDataChannelInitToNative(
521 JNIEnv* jni, jobject j_init) {
522 DataChannelInit init;
523
524 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
525 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
526 jfieldID max_retransmit_time_id =
527 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
528 jfieldID max_retransmits_id =
529 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
530 jfieldID protocol_id =
531 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
532 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
533 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
534
535 init.ordered = GetBooleanField(jni, j_init, ordered_id);
536 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
537 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
538 init.protocol = JavaToStdString(
539 jni, GetStringField(jni, j_init, protocol_id));
540 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
541 init.id = GetIntField(jni, j_init, id_id);
542
543 return init;
544}
545
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546class ConstraintsWrapper;
547
548// Adapter between the C++ PeerConnectionObserver interface and the Java
549// PeerConnection.Observer interface. Wraps an instance of the Java interface
550// and dispatches C++ callbacks to Java.
551class PCOJava : public PeerConnectionObserver {
552 public:
553 PCOJava(JNIEnv* jni, jobject j_observer)
554 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000555 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
556 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
557 j_media_stream_ctor_(GetMethodID(
558 jni, *j_media_stream_class_, "<init>", "(J)V")),
559 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000561 jni, *j_audio_track_class_, "<init>", "(J)V")),
562 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
563 j_video_track_ctor_(GetMethodID(
564 jni, *j_video_track_class_, "<init>", "(J)V")),
565 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
566 j_data_channel_ctor_(GetMethodID(
567 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 }
569
570 virtual ~PCOJava() {}
571
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000572 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000573 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000575 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
577 jmethodID ctor = GetMethodID(jni(), candidate_class,
578 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000579 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
580 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
581 jobject j_candidate = jni()->NewObject(
582 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000583 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000584 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000586 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000587 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 }
589
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000591 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000592 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000594 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000596 jobject new_state_enum =
597 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
598 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000599 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 }
601
602 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000603 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000604 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000606 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000608 jobject new_state_enum = JavaEnumFromIndex(
609 jni(), "PeerConnection$IceConnectionState", new_state);
610 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000611 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 }
613
614 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000615 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000616 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000618 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000620 jobject new_state_enum = JavaEnumFromIndex(
621 jni(), "PeerConnection$IceGatheringState", new_state);
622 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000623 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 }
625
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000626 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000627 ScopedLocalRefFrame local_ref_frame(jni());
628 jobject j_stream = jni()->NewObject(
629 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000630 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631
632 AudioTrackVector audio_tracks = stream->GetAudioTracks();
633 for (size_t i = 0; i < audio_tracks.size(); ++i) {
634 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000635 jstring id = JavaStringFromStdString(jni(), track->id());
636 jobject j_track = jni()->NewObject(
637 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000638 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000639 jfieldID audio_tracks_id = GetFieldID(jni(),
640 *j_media_stream_class_,
641 "audioTracks",
642 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000643 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000645 GetObjectClass(jni(), audio_tracks),
646 "add",
647 "(Ljava/lang/Object;)Z");
648 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000649 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
650 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 }
652
653 VideoTrackVector video_tracks = stream->GetVideoTracks();
654 for (size_t i = 0; i < video_tracks.size(); ++i) {
655 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000656 jstring id = JavaStringFromStdString(jni(), track->id());
657 jobject j_track = jni()->NewObject(
658 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000659 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000660 jfieldID video_tracks_id = GetFieldID(jni(),
661 *j_media_stream_class_,
662 "videoTracks",
663 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000664 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000666 GetObjectClass(jni(), video_tracks),
667 "add",
668 "(Ljava/lang/Object;)Z");
669 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000670 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
671 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000672 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000673 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000674 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000676 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
677 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000678 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000679 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 }
681
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000682 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000683 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000685 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686
687 WeakRef s(jni(), it->second);
688 streams_.erase(it);
689 if (!s.obj())
690 return;
691
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000692 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
693 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000695 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 }
697
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000698 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000699 ScopedLocalRefFrame local_ref_frame(jni());
700 jobject j_channel = jni()->NewObject(
701 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000702 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000703
704 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
705 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000706 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000707
708 // Channel is now owned by Java object, and will be freed from
709 // DataChannel.dispose(). Important that this be done _after_ the
710 // CallVoidMethod above as Java code might call back into native code and be
711 // surprised to see a refcount of 2.
712 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000713 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000714
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000715 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000716 }
717
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000718 virtual void OnRenegotiationNeeded() OVERRIDE {
719 ScopedLocalRefFrame local_ref_frame(jni());
720 jmethodID m =
721 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
722 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000723 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000724 }
725
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000727 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728 constraints_.reset(constraints);
729 }
730
731 const ConstraintsWrapper* constraints() { return constraints_.get(); }
732
733 private:
734 JNIEnv* jni() {
735 return AttachCurrentThreadIfNeeded();
736 }
737
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000738 const ScopedGlobalRef<jobject> j_observer_global_;
739 const ScopedGlobalRef<jclass> j_observer_class_;
740 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000742 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000744 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000746 const ScopedGlobalRef<jclass> j_data_channel_class_;
747 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
749 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000750 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751};
752
753// Wrapper for a Java MediaConstraints object. Copies all needed data so when
754// the constructor returns the Java object is no longer needed.
755class ConstraintsWrapper : public MediaConstraintsInterface {
756 public:
757 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
758 PopulateConstraintsFromJavaPairList(
759 jni, j_constraints, "mandatory", &mandatory_);
760 PopulateConstraintsFromJavaPairList(
761 jni, j_constraints, "optional", &optional_);
762 }
763
764 virtual ~ConstraintsWrapper() {}
765
766 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000767 virtual const Constraints& GetMandatory() const OVERRIDE {
768 return mandatory_;
769 }
770
771 virtual const Constraints& GetOptional() const OVERRIDE {
772 return optional_;
773 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774
775 private:
776 // Helper for translating a List<Pair<String, String>> to a Constraints.
777 static void PopulateConstraintsFromJavaPairList(
778 JNIEnv* jni, jobject j_constraints,
779 const char* field_name, Constraints* field) {
780 jfieldID j_id = GetFieldID(jni,
781 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
782 jobject j_list = GetObjectField(jni, j_constraints, j_id);
783 jmethodID j_iterator_id = GetMethodID(jni,
784 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
785 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000786 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 jmethodID j_has_next = GetMethodID(jni,
788 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
789 jmethodID j_next = GetMethodID(jni,
790 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
791 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000792 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000794 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 jmethodID get_key = GetMethodID(jni,
796 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
797 jstring j_key = reinterpret_cast<jstring>(
798 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000799 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 jmethodID get_value = GetMethodID(jni,
801 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
802 jstring j_value = reinterpret_cast<jstring>(
803 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000804 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 field->push_back(Constraint(JavaToStdString(jni, j_key),
806 JavaToStdString(jni, j_value)));
807 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000808 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 }
810
811 Constraints mandatory_;
812 Constraints optional_;
813};
814
815static jobject JavaSdpFromNativeSdp(
816 JNIEnv* jni, const SessionDescriptionInterface* desc) {
817 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000818 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000819 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820
821 jclass j_type_class = FindClass(
822 jni, "org/webrtc/SessionDescription$Type");
823 jmethodID j_type_from_canonical = GetStaticMethodID(
824 jni, j_type_class, "fromCanonicalForm",
825 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000826 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000828 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000829 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830
831 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
832 jmethodID j_sdp_ctor = GetMethodID(
833 jni, j_sdp_class, "<init>",
834 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
835 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000836 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000837 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 return j_sdp;
839}
840
841template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
842class SdpObserverWrapper : public T {
843 public:
844 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
845 ConstraintsWrapper* constraints)
846 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000847 j_observer_global_(jni, j_observer),
848 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 }
850
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000851 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000853 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000855 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000856 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
857 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000858 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 }
860
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000861 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000863 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000865 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000867 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
868 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000869 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 }
871
872 protected:
873 // Common implementation for failure of Set & Create types, distinguished by
874 // |op| being "Set" or "Create".
875 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000876 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
877 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000878 jstring j_error_string = JavaStringFromStdString(jni(), error);
879 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000880 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 }
882
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 JNIEnv* jni() {
884 return AttachCurrentThreadIfNeeded();
885 }
886
fischman@webrtc.org41776152014-01-09 00:31:17 +0000887 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000888 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000889 const ScopedGlobalRef<jobject> j_observer_global_;
890 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891};
892
893class CreateSdpObserverWrapper
894 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
895 public:
896 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
897 ConstraintsWrapper* constraints)
898 : SdpObserverWrapper(jni, j_observer, constraints) {}
899
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000900 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000901 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 SdpObserverWrapper::OnFailure(std::string("Create"), error);
903 }
904};
905
906class SetSdpObserverWrapper
907 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
908 public:
909 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
910 ConstraintsWrapper* constraints)
911 : SdpObserverWrapper(jni, j_observer, constraints) {}
912
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000913 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000914 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915 SdpObserverWrapper::OnFailure(std::string("Set"), error);
916 }
917};
918
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000919// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
920// and dispatching the callback from C++ back to Java.
921class DataChannelObserverWrapper : public DataChannelObserver {
922 public:
923 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
924 : j_observer_global_(jni, j_observer),
925 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000926 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000927 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
928 "onStateChange", "()V")),
929 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
930 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000931 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
932 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
933 }
934
935 virtual ~DataChannelObserverWrapper() {}
936
937 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000938 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000939 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000940 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000941 }
942
943 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000944 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000945 jobject byte_buffer =
946 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
947 buffer.data.length());
948 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
949 byte_buffer, buffer.binary);
950 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000951 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000952 }
953
954 private:
955 JNIEnv* jni() {
956 return AttachCurrentThreadIfNeeded();
957 }
958
959 const ScopedGlobalRef<jobject> j_observer_global_;
960 const ScopedGlobalRef<jclass> j_observer_class_;
961 const ScopedGlobalRef<jclass> j_buffer_class_;
962 const jmethodID j_on_state_change_mid_;
963 const jmethodID j_on_message_mid_;
964 const jmethodID j_buffer_ctor_;
965};
966
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000967// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
968// dispatching the callback from C++ back to Java.
969class StatsObserverWrapper : public StatsObserver {
970 public:
971 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000972 : j_observer_global_(jni, j_observer),
973 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
974 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000975 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000976 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000977 "(Ljava/lang/String;Ljava/lang/String;D"
978 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000979 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 jni, "org/webrtc/StatsReport$Value")),
981 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000982 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 "(Ljava/lang/String;Ljava/lang/String;)V")) {
984 }
985
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000986 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000988 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000989 ScopedLocalRefFrame local_ref_frame(jni());
990 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000991 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
992 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000993 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000994 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000995 }
996
997 private:
998 jobjectArray ReportsToJava(
999 JNIEnv* jni, const std::vector<StatsReport>& reports) {
1000 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001001 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001002 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001003 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001004 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001005 jstring j_id = JavaStringFromStdString(jni, report.id);
1006 jstring j_type = JavaStringFromStdString(jni, report.type);
1007 jobjectArray j_values = ValuesToJava(jni, report.values);
1008 jobject j_report = jni->NewObject(*j_stats_report_class_,
1009 j_stats_report_ctor_,
1010 j_id,
1011 j_type,
1012 report.timestamp,
1013 j_values);
1014 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001015 }
1016 return reports_array;
1017 }
1018
1019 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1020 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001021 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001023 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001025 jstring j_name = JavaStringFromStdString(jni, value.name);
1026 jstring j_value = JavaStringFromStdString(jni, value.value);
1027 jobject j_element_value =
1028 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1029 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001030 }
1031 return j_values;
1032 }
1033
1034 JNIEnv* jni() {
1035 return AttachCurrentThreadIfNeeded();
1036 }
1037
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001038 const ScopedGlobalRef<jobject> j_observer_global_;
1039 const ScopedGlobalRef<jclass> j_observer_class_;
1040 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001041 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001042 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001043 const jmethodID j_value_ctor_;
1044};
1045
1046// Adapter presenting a cricket::VideoRenderer as a
1047// webrtc::VideoRendererInterface.
1048class VideoRendererWrapper : public VideoRendererInterface {
1049 public:
1050 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1051 if (renderer)
1052 return new VideoRendererWrapper(renderer);
1053 return NULL;
1054 }
1055
1056 virtual ~VideoRendererWrapper() {}
1057
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001058 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001059 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060 const bool kNotReserved = false; // What does this param mean??
1061 renderer_->SetSize(width, height, kNotReserved);
1062 }
1063
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001064 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001065 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001066 renderer_->RenderFrame(frame);
1067 }
1068
1069 private:
1070 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1071 : renderer_(renderer) {}
1072
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001073 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001074};
1075
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001076// Wrapper for texture object in TextureVideoFrame.
1077class NativeHandleImpl : public NativeHandle {
1078 public:
1079 NativeHandleImpl() :
1080 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1081 virtual ~NativeHandleImpl() {}
1082 virtual int32_t AddRef() {
1083 return ++ref_count_;
1084 }
1085 virtual int32_t Release() {
1086 return --ref_count_;
1087 }
1088 virtual void* GetHandle() {
1089 return texture_object_;
1090 }
1091 int GetTextureId() {
1092 return texture_id_;
1093 }
1094 void SetTextureObject(void *texture_object, int texture_id) {
1095 texture_object_ = reinterpret_cast<jobject>(texture_object);
1096 texture_id_ = texture_id;
1097 }
1098 int32_t ref_count() {
1099 return ref_count_;
1100 }
1101
1102 private:
1103 int32_t ref_count_;
1104 jobject texture_object_;
1105 int32_t texture_id_;
1106};
1107
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1109// instance.
1110class JavaVideoRendererWrapper : public VideoRendererInterface {
1111 public:
1112 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001113 : j_callbacks_(jni, j_callbacks),
1114 j_set_size_id_(GetMethodID(
1115 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1116 j_render_frame_id_(GetMethodID(
1117 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1118 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1119 j_frame_class_(jni,
1120 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001121 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001122 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001123 j_texture_frame_ctor_id_(GetMethodID(
1124 jni, *j_frame_class_, "<init>",
1125 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001126 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001127 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001128 }
1129
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001130 virtual ~JavaVideoRendererWrapper() {}
1131
1132 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001133 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001135 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136 }
1137
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001138 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001139 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001140 if (frame->GetNativeHandle() != NULL) {
1141 jobject j_frame = CricketToJavaTextureFrame(frame);
1142 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1143 CHECK_EXCEPTION(jni());
1144 } else {
1145 jobject j_frame = CricketToJavaI420Frame(frame);
1146 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1147 CHECK_EXCEPTION(jni());
1148 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001149 }
1150
1151 private:
1152 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001153 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001154 jintArray strides = jni()->NewIntArray(3);
1155 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001156 strides_array[0] = frame->GetYPitch();
1157 strides_array[1] = frame->GetUPitch();
1158 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001159 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1160 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1161 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001162 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001163 frame->GetYPitch() * frame->GetHeight());
1164 jobject u_buffer = jni()->NewDirectByteBuffer(
1165 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1166 jobject v_buffer = jni()->NewDirectByteBuffer(
1167 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1168 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1169 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1170 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001171 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001172 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001173 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001174 }
1175
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001176 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1177 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1178 NativeHandleImpl* handle =
1179 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1180 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1181 int texture_id = handle->GetTextureId();
1182 return jni()->NewObject(
1183 *j_frame_class_, j_texture_frame_ctor_id_,
1184 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1185 }
1186
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001187 JNIEnv* jni() {
1188 return AttachCurrentThreadIfNeeded();
1189 }
1190
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001191 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001192 jmethodID j_set_size_id_;
1193 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001194 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001195 jmethodID j_i420_frame_ctor_id_;
1196 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001197 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001198};
1199
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001200#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001201// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1202// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1203// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001204
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001205//#define TRACK_BUFFER_TIMING
1206#define TAG "MediaCodecVideo"
1207#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001208#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1209#else
1210#define ALOGV(...)
1211#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001212#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1213#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001214
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001215// Color formats supported by encoder - should mirror supportedColorList
1216// from MediaCodecVideoEncoder.java
1217enum COLOR_FORMATTYPE {
1218 COLOR_FormatYUV420Planar = 0x13,
1219 COLOR_FormatYUV420SemiPlanar = 0x15,
1220 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1221 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1222 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1223 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1224 // but requires some (16, 32?) byte alignment.
1225 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1226};
1227
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001228// Arbitrary interval to poll the codec for new outputs.
1229enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001230// Media codec maximum output buffer ready timeout.
1231enum { kMediaCodecTimeoutMs = 500 };
1232// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1233enum { kMediaCodecStatisticsIntervalMs = 3000 };
1234
1235static int64_t GetCurrentTimeMs() {
1236 return TickTime::Now().Ticks() / 1000000LL;
1237}
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001238
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001239// Allow Invoke() calls from from current thread.
1240static void AllowBlockingCalls() {
1241 Thread* current_thread = Thread::Current();
1242 if (current_thread != NULL)
1243 current_thread->SetAllowBlockingCalls(true);
1244}
1245
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001246// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1247// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1248// HW-backed video encode. This C++ class is implemented as a very thin shim,
1249// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1250// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1251// thread, currently the libjingle Worker thread.
1252class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001253 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001254 public:
1255 virtual ~MediaCodecVideoEncoder();
1256 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1257
1258 // webrtc::VideoEncoder implementation. Everything trampolines to
1259 // |codec_thread_| for execution.
1260 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1261 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001262 size_t /* max_payload_size */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001263 virtual int32_t Encode(
1264 const webrtc::I420VideoFrame& input_image,
1265 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1266 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1267 virtual int32_t RegisterEncodeCompleteCallback(
1268 webrtc::EncodedImageCallback* callback) OVERRIDE;
1269 virtual int32_t Release() OVERRIDE;
1270 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1271 int /* rtt */) OVERRIDE;
1272 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1273
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001274 // rtc::MessageHandler implementation.
1275 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001276
1277 private:
1278 // CHECK-fail if not running on |codec_thread_|.
1279 void CheckOnCodecThread();
1280
1281 // Release() and InitEncode() in an attempt to restore the codec to an
1282 // operable state. Necessary after all manner of OMX-layer errors.
1283 void ResetCodec();
1284
1285 // Implementation of webrtc::VideoEncoder methods above, all running on the
1286 // codec thread exclusively.
1287 //
1288 // If width==0 then this is assumed to be a re-initialization and the
1289 // previously-current values are reused instead of the passed parameters
1290 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001291 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001292 int32_t EncodeOnCodecThread(
1293 const webrtc::I420VideoFrame& input_image,
1294 const std::vector<webrtc::VideoFrameType>* frame_types);
1295 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1296 webrtc::EncodedImageCallback* callback);
1297 int32_t ReleaseOnCodecThread();
1298 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1299
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001300 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1301 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1302 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1303 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1304 jlong GetOutputBufferInfoPresentationTimestampUs(
1305 JNIEnv* jni,
1306 jobject j_output_buffer_info);
1307
1308 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1309 // true on success.
1310 bool DeliverPendingOutputs(JNIEnv* jni);
1311
1312 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1313 // |codec_thread_| synchronously.
1314 webrtc::EncodedImageCallback* callback_;
1315
1316 // State that is constant for the lifetime of this object once the ctor
1317 // returns.
1318 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1319 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1320 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1321 jmethodID j_init_encode_method_;
1322 jmethodID j_dequeue_input_buffer_method_;
1323 jmethodID j_encode_method_;
1324 jmethodID j_release_method_;
1325 jmethodID j_set_rates_method_;
1326 jmethodID j_dequeue_output_buffer_method_;
1327 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001328 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001329 jfieldID j_info_index_field_;
1330 jfieldID j_info_buffer_field_;
1331 jfieldID j_info_is_key_frame_field_;
1332 jfieldID j_info_presentation_timestamp_us_field_;
1333
1334 // State that is valid only between InitEncode() and the next Release().
1335 // Touched only on codec_thread_ so no explicit synchronization necessary.
1336 int width_; // Frame width in pixels.
1337 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001338 bool inited_;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001339 uint16_t picture_id_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001340 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001341 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001342 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001343 int64_t current_timestamp_us_; // Current frame timestamps in us.
1344 int frames_received_; // Number of frames received by encoder.
1345 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001346 int frames_resolution_update_; // Number of frames with new codec resolution.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001347 int frames_in_queue_; // Number of frames in encoder queue.
1348 int64_t start_time_ms_; // Start time for statistics.
1349 int current_frames_; // Number of frames in the current statistics interval.
1350 int current_bytes_; // Encoded bytes in the current statistics interval.
1351 int current_encoding_time_ms_; // Overall encoding time in the current second
1352 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1353 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
1354 std::vector<int32_t> timestamps_; // Video frames timestamp queue.
1355 std::vector<int64_t> render_times_ms_; // Video frames render time queue.
1356 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1357 // encoder input.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001358 // Frame size in bytes fed to MediaCodec.
1359 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001360 // True only when between a callback_->Encoded() call return a positive value
1361 // and the next Encode() call being ignored.
1362 bool drop_next_input_frame_;
1363 // Global references; must be deleted in Release().
1364 std::vector<jobject> input_buffers_;
1365};
1366
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001367MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001368 // Call Release() to ensure no more callbacks to us after we are deleted.
1369 Release();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001370}
1371
1372MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001373 : callback_(NULL),
1374 inited_(false),
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001375 picture_id_(0),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001376 codec_thread_(new Thread()),
1377 j_media_codec_video_encoder_class_(
1378 jni,
1379 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1380 j_media_codec_video_encoder_(
1381 jni,
1382 jni->NewObject(*j_media_codec_video_encoder_class_,
1383 GetMethodID(jni,
1384 *j_media_codec_video_encoder_class_,
1385 "<init>",
1386 "()V"))) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001387 ScopedLocalRefFrame local_ref_frame(jni);
1388 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1389 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1390 // 2732 means that deadlocks abound. This class synchronously trampolines
1391 // to |codec_thread_|, so if anything else can be coming to _us_ from
1392 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1393 // in the bug, we have a problem. For now work around that with a dedicated
1394 // thread.
1395 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001396 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001397
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001398 jclass j_output_buffer_info_class =
1399 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1400 j_init_encode_method_ = GetMethodID(jni,
1401 *j_media_codec_video_encoder_class_,
1402 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001403 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001404 j_dequeue_input_buffer_method_ = GetMethodID(
1405 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1406 j_encode_method_ = GetMethodID(
1407 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1408 j_release_method_ =
1409 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1410 j_set_rates_method_ = GetMethodID(
1411 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1412 j_dequeue_output_buffer_method_ =
1413 GetMethodID(jni,
1414 *j_media_codec_video_encoder_class_,
1415 "dequeueOutputBuffer",
1416 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1417 j_release_output_buffer_method_ = GetMethodID(
1418 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1419
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001420 j_color_format_field_ =
1421 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001422 j_info_index_field_ =
1423 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1424 j_info_buffer_field_ = GetFieldID(
1425 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1426 j_info_is_key_frame_field_ =
1427 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1428 j_info_presentation_timestamp_us_field_ = GetFieldID(
1429 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001430 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001431 AllowBlockingCalls();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001432}
1433
1434int32_t MediaCodecVideoEncoder::InitEncode(
1435 const webrtc::VideoCodec* codec_settings,
1436 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001437 size_t /* max_payload_size */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001438 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001439 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001440
1441 return codec_thread_->Invoke<int32_t>(
1442 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1443 this,
1444 codec_settings->width,
1445 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001446 codec_settings->startBitrate,
1447 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001448}
1449
1450int32_t MediaCodecVideoEncoder::Encode(
1451 const webrtc::I420VideoFrame& frame,
1452 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1453 const std::vector<webrtc::VideoFrameType>* frame_types) {
1454 return codec_thread_->Invoke<int32_t>(Bind(
1455 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1456}
1457
1458int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1459 webrtc::EncodedImageCallback* callback) {
1460 return codec_thread_->Invoke<int32_t>(
1461 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1462 this,
1463 callback));
1464}
1465
1466int32_t MediaCodecVideoEncoder::Release() {
1467 return codec_thread_->Invoke<int32_t>(
1468 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1469}
1470
1471int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1472 int /* rtt */) {
1473 return WEBRTC_VIDEO_CODEC_OK;
1474}
1475
1476int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1477 uint32_t frame_rate) {
1478 return codec_thread_->Invoke<int32_t>(
1479 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1480 this,
1481 new_bit_rate,
1482 frame_rate));
1483}
1484
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001485void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001486 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1487 ScopedLocalRefFrame local_ref_frame(jni);
1488
1489 // We only ever send one message to |this| directly (not through a Bind()'d
1490 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001491 CHECK(!msg->message_id) << "Unexpected message!";
1492 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001493 CheckOnCodecThread();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001494 if (!inited_) {
1495 return;
1496 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001497
1498 // It would be nice to recover from a failure here if one happened, but it's
1499 // unclear how to signal such a failure to the app, so instead we stay silent
1500 // about it and let the next app-called API method reveal the borkedness.
1501 DeliverPendingOutputs(jni);
1502 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1503}
1504
1505void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001506 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1507 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001508}
1509
1510void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001511 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001512 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1513 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001514 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1515 width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001516 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1517 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1518 // https://code.google.com/p/webrtc/issues/detail?id=2920
1519 }
1520}
1521
1522int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001523 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001524 CheckOnCodecThread();
1525 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1526 ScopedLocalRefFrame local_ref_frame(jni);
1527
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001528 ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1529 width, height, kbps, fps);
1530 if (kbps == 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001531 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001532 }
1533 if (fps == 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001534 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001535 }
1536
1537 width_ = width;
1538 height_ = height;
1539 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001540 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001541 yuv_size_ = width_ * height_ * 3 / 2;
1542 frames_received_ = 0;
1543 frames_dropped_ = 0;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001544 frames_resolution_update_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001545 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001546 current_timestamp_us_ = 0;
1547 start_time_ms_ = GetCurrentTimeMs();
1548 current_frames_ = 0;
1549 current_bytes_ = 0;
1550 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001551 last_input_timestamp_ms_ = -1;
1552 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001553 timestamps_.clear();
1554 render_times_ms_.clear();
1555 frame_rtc_times_ms_.clear();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001556 drop_next_input_frame_ = false;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001557 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001558 // We enforce no extra stride/padding in the format creation step.
1559 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1560 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1561 j_init_encode_method_,
1562 width_,
1563 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001564 kbps,
1565 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001566 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001567 if (IsNull(jni, input_buffers))
1568 return WEBRTC_VIDEO_CODEC_ERROR;
1569
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001570 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001571 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1572 j_color_format_field_)) {
1573 case COLOR_FormatYUV420Planar:
1574 encoder_fourcc_ = libyuv::FOURCC_YU12;
1575 break;
1576 case COLOR_FormatYUV420SemiPlanar:
1577 case COLOR_QCOM_FormatYUV420SemiPlanar:
1578 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1579 encoder_fourcc_ = libyuv::FOURCC_NV12;
1580 break;
1581 default:
1582 LOG(LS_ERROR) << "Wrong color format.";
1583 return WEBRTC_VIDEO_CODEC_ERROR;
1584 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001585 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001586 CHECK(input_buffers_.empty())
1587 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001588 input_buffers_.resize(num_input_buffers);
1589 for (size_t i = 0; i < num_input_buffers; ++i) {
1590 input_buffers_[i] =
1591 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001592 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001593 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001594 CHECK_EXCEPTION(jni);
1595 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001596 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001597 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001598
1599 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1600 return WEBRTC_VIDEO_CODEC_OK;
1601}
1602
1603int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1604 const webrtc::I420VideoFrame& frame,
1605 const std::vector<webrtc::VideoFrameType>* frame_types) {
1606 CheckOnCodecThread();
1607 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1608 ScopedLocalRefFrame local_ref_frame(jni);
1609
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001610 if (!inited_) {
1611 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1612 }
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001613 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001614 if (!DeliverPendingOutputs(jni)) {
1615 ResetCodec();
1616 // Continue as if everything's fine.
1617 }
1618
1619 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001620 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001621 drop_next_input_frame_ = false;
1622 return WEBRTC_VIDEO_CODEC_OK;
1623 }
1624
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001625 CHECK(frame_types->size() == 1) << "Unexpected stream count";
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001626 if (frame.width() != width_ || frame.height() != height_) {
1627 frames_resolution_update_++;
1628 ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1629 width_, height_, frame.width(), frame.height());
1630 if (frames_resolution_update_ > 3) {
1631 // Reset codec if we received more than 3 frames with new resolution.
1632 width_ = frame.width();
1633 height_ = frame.height();
1634 frames_resolution_update_ = 0;
1635 ResetCodec();
1636 }
1637 return WEBRTC_VIDEO_CODEC_OK;
1638 }
1639 frames_resolution_update_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001640
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001641 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1642
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001643 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001644 // or the encoder latency exceeds 70 ms and drop frame if so.
1645 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001646 int encoder_latency_ms = last_input_timestamp_ms_ -
1647 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001648 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001649 ALOGD("Drop frame - encoder is behind by %d ms. Q size: %d",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001650 encoder_latency_ms, frames_in_queue_);
1651 frames_dropped_++;
1652 return WEBRTC_VIDEO_CODEC_OK;
1653 }
1654 }
1655
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001656 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1657 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001658 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001659 if (j_input_buffer_index == -1) {
1660 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001661 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001662 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001663 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001664 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001665 if (j_input_buffer_index == -2) {
1666 ResetCodec();
1667 return WEBRTC_VIDEO_CODEC_ERROR;
1668 }
1669
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001670 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001671 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001672
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001673 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001674 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001675 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001676 CHECK_EXCEPTION(jni);
1677 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001678 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001679 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1680 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1681 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1682 yuv_buffer, width_,
1683 width_, height_,
1684 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001685 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001686 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001687 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001688
1689 // Save input image timestamps for later output
1690 timestamps_.push_back(frame.timestamp());
1691 render_times_ms_.push_back(frame.render_time_ms());
1692 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1693
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001694 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1695 j_encode_method_,
1696 key_frame,
1697 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001698 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001699 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001700 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001701 current_timestamp_us_ += 1000000 / last_set_fps_;
1702
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001703 if (!encode_status || !DeliverPendingOutputs(jni)) {
1704 ResetCodec();
1705 return WEBRTC_VIDEO_CODEC_ERROR;
1706 }
1707
1708 return WEBRTC_VIDEO_CODEC_OK;
1709}
1710
1711int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1712 webrtc::EncodedImageCallback* callback) {
1713 CheckOnCodecThread();
1714 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1715 ScopedLocalRefFrame local_ref_frame(jni);
1716 callback_ = callback;
1717 return WEBRTC_VIDEO_CODEC_OK;
1718}
1719
1720int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001721 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001722 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001723 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001724 CheckOnCodecThread();
1725 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001726 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1727 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001728 ScopedLocalRefFrame local_ref_frame(jni);
1729 for (size_t i = 0; i < input_buffers_.size(); ++i)
1730 jni->DeleteGlobalRef(input_buffers_[i]);
1731 input_buffers_.clear();
1732 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001733 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001734 rtc::MessageQueueManager::Clear(this);
1735 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001736 return WEBRTC_VIDEO_CODEC_OK;
1737}
1738
1739int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1740 uint32_t frame_rate) {
1741 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001742 if (last_set_bitrate_kbps_ == new_bit_rate &&
1743 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001744 return WEBRTC_VIDEO_CODEC_OK;
1745 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001746 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1747 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001748 if (new_bit_rate > 0) {
1749 last_set_bitrate_kbps_ = new_bit_rate;
1750 }
1751 if (frame_rate > 0) {
1752 last_set_fps_ = frame_rate;
1753 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001754 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1755 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001756 last_set_bitrate_kbps_,
1757 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001758 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001759 if (!ret) {
1760 ResetCodec();
1761 return WEBRTC_VIDEO_CODEC_ERROR;
1762 }
1763 return WEBRTC_VIDEO_CODEC_OK;
1764}
1765
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001766int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1767 JNIEnv* jni,
1768 jobject j_output_buffer_info) {
1769 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1770}
1771
1772jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1773 JNIEnv* jni,
1774 jobject j_output_buffer_info) {
1775 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1776}
1777
1778bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1779 JNIEnv* jni,
1780 jobject j_output_buffer_info) {
1781 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1782}
1783
1784jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1785 JNIEnv* jni,
1786 jobject j_output_buffer_info) {
1787 return GetLongField(
1788 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1789}
1790
1791bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1792 while (true) {
1793 jobject j_output_buffer_info = jni->CallObjectMethod(
1794 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001795 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001796 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001797 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001798 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001799
1800 int output_buffer_index =
1801 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1802 if (output_buffer_index == -1) {
1803 ResetCodec();
1804 return false;
1805 }
1806
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001807 // Get frame timestamps from a queue.
1808 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001809 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1810 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001811 int32_t timestamp = timestamps_.front();
1812 timestamps_.erase(timestamps_.begin());
1813 int64_t render_time_ms = render_times_ms_.front();
1814 render_times_ms_.erase(render_times_ms_.begin());
1815 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1816 frame_rtc_times_ms_.front();
1817 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001818 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001819
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001820 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001821 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001822 jobject j_output_buffer =
1823 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1824 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1825 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1826 uint8* payload = reinterpret_cast<uint8_t*>(
1827 jni->GetDirectBufferAddress(j_output_buffer));
1828 CHECK_EXCEPTION(jni);
1829
1830 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1831 " EncTime: %lld",
1832 output_buffer_index, payload_size, last_output_timestamp_ms_,
1833 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1834 frame_encoding_time_ms);
1835
1836 // Calculate and print encoding statistics - every 3 seconds.
1837 current_frames_++;
1838 current_bytes_ += payload_size;
1839 current_encoding_time_ms_ += frame_encoding_time_ms;
1840 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1841 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1842 current_frames_ > 0) {
1843 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1844 " encTime: %d for last %d ms",
1845 current_bytes_ * 8 / statistic_time_ms,
1846 last_set_bitrate_kbps_,
1847 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1848 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1849 start_time_ms_ = GetCurrentTimeMs();
1850 current_frames_ = 0;
1851 current_bytes_= 0;
1852 current_encoding_time_ms_ = 0;
1853 }
1854
1855 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001856 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001857 scoped_ptr<webrtc::EncodedImage> image(
1858 new webrtc::EncodedImage(payload, payload_size, payload_size));
1859 image->_encodedWidth = width_;
1860 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001861 image->_timeStamp = timestamp;
1862 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001863 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1864 image->_completeFrame = true;
1865
1866 webrtc::CodecSpecificInfo info;
1867 memset(&info, 0, sizeof(info));
1868 info.codecType = kVideoCodecVP8;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001869 info.codecSpecific.VP8.pictureId = picture_id_;
1870 info.codecSpecific.VP8.nonReference = false;
1871 info.codecSpecific.VP8.simulcastIdx = 0;
1872 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx;
1873 info.codecSpecific.VP8.layerSync = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001874 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1875 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001876 picture_id_ = (picture_id_ + 1) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001877
1878 // Generate a header describing a single fragment.
1879 webrtc::RTPFragmentationHeader header;
1880 memset(&header, 0, sizeof(header));
1881 header.VerifyAndAllocateFragmentationHeader(1);
1882 header.fragmentationOffset[0] = 0;
1883 header.fragmentationLength[0] = image->_length;
1884 header.fragmentationPlType[0] = 0;
1885 header.fragmentationTimeDiff[0] = 0;
1886
1887 callback_status = callback_->Encoded(*image, &info, &header);
1888 }
1889
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001890 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001891 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1892 j_release_output_buffer_method_,
1893 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001894 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001895 if (!success) {
1896 ResetCodec();
1897 return false;
1898 }
1899
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001900 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001901 drop_next_input_frame_ = true;
1902 // Theoretically could handle callback_status<0 here, but unclear what that
1903 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001904 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001905 }
1906
1907 return true;
1908}
1909
1910// Simplest-possible implementation of an encoder factory, churns out
1911// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1912class MediaCodecVideoEncoderFactory
1913 : public cricket::WebRtcVideoEncoderFactory {
1914 public:
1915 MediaCodecVideoEncoderFactory();
1916 virtual ~MediaCodecVideoEncoderFactory();
1917
1918 // WebRtcVideoEncoderFactory implementation.
1919 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1920 OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001921 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1922 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1923
1924 private:
1925 // Empty if platform support is lacking, const after ctor returns.
1926 std::vector<VideoCodec> supported_codecs_;
1927};
1928
1929MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1930 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1931 ScopedLocalRefFrame local_ref_frame(jni);
1932 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1933 bool is_platform_supported = jni->CallStaticBooleanMethod(
1934 j_encoder_class,
1935 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001936 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001937 if (!is_platform_supported)
1938 return;
1939
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001940 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1941 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1942 // reasonable defaults.
1943 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001944 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001945}
1946
1947MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1948
1949webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1950 webrtc::VideoCodecType type) {
1951 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1952 return NULL;
1953 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1954}
1955
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001956const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1957MediaCodecVideoEncoderFactory::codecs() const {
1958 return supported_codecs_;
1959}
1960
1961void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1962 webrtc::VideoEncoder* encoder) {
1963 delete encoder;
1964}
1965
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001966class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001967 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001968 public:
1969 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1970 virtual ~MediaCodecVideoDecoder();
1971
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001972 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1973
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001974 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1975 int32_t numberOfCores) OVERRIDE;
1976
1977 virtual int32_t
1978 Decode(const EncodedImage& inputImage, bool missingFrames,
1979 const RTPFragmentationHeader* fragmentation,
1980 const CodecSpecificInfo* codecSpecificInfo = NULL,
1981 int64_t renderTimeMs = -1) OVERRIDE;
1982
1983 virtual int32_t RegisterDecodeCompleteCallback(
1984 DecodedImageCallback* callback) OVERRIDE;
1985
1986 virtual int32_t Release() OVERRIDE;
1987
1988 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001989 // rtc::MessageHandler implementation.
1990 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001991
1992 private:
1993 // CHECK-fail if not running on |codec_thread_|.
1994 void CheckOnCodecThread();
1995
1996 int32_t InitDecodeOnCodecThread();
1997 int32_t ReleaseOnCodecThread();
1998 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001999 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
2000 // true on success.
2001 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
2002
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002003
2004 bool key_frame_required_;
2005 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002006 bool use_surface_;
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002007 int error_count_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002008 VideoCodec codec_;
2009 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002010 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002011 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002012 int frames_received_; // Number of frames received by decoder.
2013 int frames_decoded_; // Number of frames decoded by decoder
2014 int64_t start_time_ms_; // Start time for statistics.
2015 int current_frames_; // Number of frames in the current statistics interval.
2016 int current_bytes_; // Encoded bytes in the current statistics interval.
2017 int current_decoding_time_ms_; // Overall decoding time in the current second
2018 uint32_t max_pending_frames_; // Maximum number of pending input frames
2019 std::vector<int32_t> timestamps_;
2020 std::vector<int64_t> ntp_times_ms_;
2021 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
2022 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002023
2024 // State that is constant for the lifetime of this object once the ctor
2025 // returns.
2026 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
2027 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2028 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2029 jmethodID j_init_decode_method_;
2030 jmethodID j_release_method_;
2031 jmethodID j_dequeue_input_buffer_method_;
2032 jmethodID j_queue_input_buffer_method_;
2033 jmethodID j_dequeue_output_buffer_method_;
2034 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002035 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002036 jfieldID j_input_buffers_field_;
2037 jfieldID j_output_buffers_field_;
2038 jfieldID j_color_format_field_;
2039 jfieldID j_width_field_;
2040 jfieldID j_height_field_;
2041 jfieldID j_stride_field_;
2042 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002043 jfieldID j_surface_texture_field_;
2044 jfieldID j_textureID_field_;
2045 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2046 jfieldID j_info_index_field_;
2047 jfieldID j_info_offset_field_;
2048 jfieldID j_info_size_field_;
2049 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002050
2051 // Global references; must be deleted in Release().
2052 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002053 jobject surface_texture_;
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002054 jobject previous_surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002055
2056 // Render EGL context.
2057 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002058};
2059
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002060jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2061
2062int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2063 jobject render_egl_context) {
2064 if (render_egl_context_) {
2065 jni->DeleteGlobalRef(render_egl_context_);
2066 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002067 if (IsNull(jni, render_egl_context)) {
2068 render_egl_context_ = NULL;
2069 } else {
2070 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002071 CHECK_EXCEPTION(jni) << "error calling NewGlobalRef for EGL Context.";
2072 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
2073 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
2074 ALOGE("Wrong EGL Context.");
2075 jni->DeleteGlobalRef(render_egl_context_);
2076 render_egl_context_ = NULL;
2077 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002078 }
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002079 if (render_egl_context_ == NULL) {
2080 ALOGD("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
2081 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002082 return 0;
2083}
2084
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002085MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
2086 : key_frame_required_(true),
2087 inited_(false),
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002088 error_count_(0),
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002089 surface_texture_(NULL),
2090 previous_surface_texture_(NULL),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002091 codec_thread_(new Thread()),
2092 j_media_codec_video_decoder_class_(
2093 jni,
2094 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2095 j_media_codec_video_decoder_(
2096 jni,
2097 jni->NewObject(*j_media_codec_video_decoder_class_,
2098 GetMethodID(jni,
2099 *j_media_codec_video_decoder_class_,
2100 "<init>",
2101 "()V"))) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002102 ScopedLocalRefFrame local_ref_frame(jni);
2103 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002104 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002105
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002106 j_init_decode_method_ = GetMethodID(
2107 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002108 "(IIZZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002109 j_release_method_ =
2110 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2111 j_dequeue_input_buffer_method_ = GetMethodID(
2112 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2113 j_queue_input_buffer_method_ = GetMethodID(
2114 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2115 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002116 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2117 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002118 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002119 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002120
2121 j_input_buffers_field_ = GetFieldID(
2122 jni, *j_media_codec_video_decoder_class_,
2123 "inputBuffers", "[Ljava/nio/ByteBuffer;");
2124 j_output_buffers_field_ = GetFieldID(
2125 jni, *j_media_codec_video_decoder_class_,
2126 "outputBuffers", "[Ljava/nio/ByteBuffer;");
2127 j_color_format_field_ = GetFieldID(
2128 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2129 j_width_field_ = GetFieldID(
2130 jni, *j_media_codec_video_decoder_class_, "width", "I");
2131 j_height_field_ = GetFieldID(
2132 jni, *j_media_codec_video_decoder_class_, "height", "I");
2133 j_stride_field_ = GetFieldID(
2134 jni, *j_media_codec_video_decoder_class_, "stride", "I");
2135 j_slice_height_field_ = GetFieldID(
2136 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002137 j_textureID_field_ = GetFieldID(
2138 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2139 j_surface_texture_field_ = GetFieldID(
2140 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2141 "Landroid/graphics/SurfaceTexture;");
2142
2143 jclass j_decoder_output_buffer_info_class = FindClass(jni,
2144 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2145 j_info_index_field_ = GetFieldID(
2146 jni, j_decoder_output_buffer_info_class, "index", "I");
2147 j_info_offset_field_ = GetFieldID(
2148 jni, j_decoder_output_buffer_info_class, "offset", "I");
2149 j_info_size_field_ = GetFieldID(
2150 jni, j_decoder_output_buffer_info_class, "size", "I");
2151 j_info_presentation_timestamp_us_field_ = GetFieldID(
2152 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002153
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002154 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002155 use_surface_ = true;
2156 if (render_egl_context_ == NULL)
2157 use_surface_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002158 memset(&codec_, 0, sizeof(codec_));
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00002159 AllowBlockingCalls();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002160}
2161
2162MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002163 // Call Release() to ensure no more callbacks to us after we are deleted.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002164 Release();
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002165 // Delete global references.
2166 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2167 if (previous_surface_texture_ != NULL)
2168 jni->DeleteGlobalRef(previous_surface_texture_);
2169 if (surface_texture_ != NULL)
2170 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002171}
2172
2173int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2174 int32_t numberOfCores) {
2175 if (inst == NULL) {
2176 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2177 }
2178 int ret_val = Release();
2179 if (ret_val < 0) {
2180 return ret_val;
2181 }
2182 // Save VideoCodec instance for later.
2183 if (&codec_ != inst) {
2184 codec_ = *inst;
2185 }
2186 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2187
2188 // Always start with a complete key frame.
2189 key_frame_required_ = true;
2190 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002191 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002192
2193 // Call Java init.
2194 return codec_thread_->Invoke<int32_t>(
2195 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2196}
2197
2198int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2199 CheckOnCodecThread();
2200 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2201 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002202 ALOGD("InitDecodeOnCodecThread: %d x %d. Fps: %d. Errors: %d",
2203 codec_.width, codec_.height, codec_.maxFramerate, error_count_);
2204 bool use_sw_codec = false;
2205 if (error_count_ > 1) {
2206 // If more than one critical errors happen for HW codec, switch to SW codec.
2207 use_sw_codec = true;
2208 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002209
2210 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2211 j_init_decode_method_,
2212 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002213 codec_.height,
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002214 use_sw_codec,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002215 use_surface_,
2216 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002217 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002218 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002219 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002220 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002221 inited_ = true;
2222
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002223 max_pending_frames_ = 0;
2224 if (use_surface_) {
2225 max_pending_frames_ = 1;
2226 }
2227 start_time_ms_ = GetCurrentTimeMs();
2228 current_frames_ = 0;
2229 current_bytes_ = 0;
2230 current_decoding_time_ms_ = 0;
2231 timestamps_.clear();
2232 ntp_times_ms_.clear();
2233 frame_rtc_times_ms_.clear();
2234
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002235 jobjectArray input_buffers = (jobjectArray)GetObjectField(
2236 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2237 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002238 input_buffers_.resize(num_input_buffers);
2239 for (size_t i = 0; i < num_input_buffers; ++i) {
2240 input_buffers_[i] =
2241 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002242 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002243 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002244
2245 if (use_surface_) {
2246 jobject surface_texture = GetObjectField(
2247 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002248 if (previous_surface_texture_ != NULL) {
2249 jni->DeleteGlobalRef(previous_surface_texture_);
2250 }
2251 previous_surface_texture_ = surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002252 surface_texture_ = jni->NewGlobalRef(surface_texture);
2253 }
2254 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2255
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002256 return WEBRTC_VIDEO_CODEC_OK;
2257}
2258
2259int32_t MediaCodecVideoDecoder::Release() {
2260 return codec_thread_->Invoke<int32_t>(
2261 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2262}
2263
2264int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002265 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002266 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002267 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002268 CheckOnCodecThread();
2269 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2270 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2271 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002272 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002273 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002274 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002275 input_buffers_.clear();
2276 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002277 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002278 rtc::MessageQueueManager::Clear(this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002279 inited_ = false;
2280 return WEBRTC_VIDEO_CODEC_OK;
2281}
2282
2283
2284void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002285 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2286 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002287}
2288
2289int32_t MediaCodecVideoDecoder::Decode(
2290 const EncodedImage& inputImage,
2291 bool missingFrames,
2292 const RTPFragmentationHeader* fragmentation,
2293 const CodecSpecificInfo* codecSpecificInfo,
2294 int64_t renderTimeMs) {
2295 if (!inited_) {
2296 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2297 }
2298 if (callback_ == NULL) {
2299 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2300 }
2301 if (inputImage._buffer == NULL && inputImage._length > 0) {
2302 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2303 }
2304 // Check if encoded frame dimension has changed.
2305 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2306 (inputImage._encodedWidth != codec_.width ||
2307 inputImage._encodedHeight != codec_.height)) {
2308 codec_.width = inputImage._encodedWidth;
2309 codec_.height = inputImage._encodedHeight;
2310 InitDecode(&codec_, 1);
2311 }
2312
2313 // Always start with a complete key frame.
2314 if (key_frame_required_) {
2315 if (inputImage._frameType != webrtc::kKeyFrame) {
2316 return WEBRTC_VIDEO_CODEC_ERROR;
2317 }
2318 if (!inputImage._completeFrame) {
2319 return WEBRTC_VIDEO_CODEC_ERROR;
2320 }
2321 key_frame_required_ = false;
2322 }
2323 if (inputImage._length == 0) {
2324 return WEBRTC_VIDEO_CODEC_ERROR;
2325 }
2326
2327 return codec_thread_->Invoke<int32_t>(Bind(
2328 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2329}
2330
2331int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2332 const EncodedImage& inputImage) {
2333 static uint8_t yVal_ = 0x7f;
2334
2335 CheckOnCodecThread();
2336 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2337 ScopedLocalRefFrame local_ref_frame(jni);
2338
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002339 // Try to drain the decoder and wait until output is not too
2340 // much behind the input.
2341 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2342 ALOGV("Wait for output...");
2343 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002344 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002345 Reset();
2346 return WEBRTC_VIDEO_CODEC_ERROR;
2347 }
2348 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2349 ALOGE("Output buffer dequeue timeout");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002350 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002351 Reset();
2352 return WEBRTC_VIDEO_CODEC_ERROR;
2353 }
2354 }
2355
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002356 // Get input buffer.
2357 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2358 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002359 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002360 if (j_input_buffer_index < 0) {
2361 ALOGE("dequeueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002362 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002363 Reset();
2364 return WEBRTC_VIDEO_CODEC_ERROR;
2365 }
2366
2367 // Copy encoded data to Java ByteBuffer.
2368 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2369 uint8* buffer =
2370 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002371 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002372 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002373 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002374 if (buffer_capacity < inputImage._length) {
2375 ALOGE("Input frame size %d is bigger than buffer size %d.",
2376 inputImage._length, buffer_capacity);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002377 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002378 Reset();
2379 return WEBRTC_VIDEO_CODEC_ERROR;
2380 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002381 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002382 frames_received_, j_input_buffer_index, inputImage._length);
2383 memcpy(buffer, inputImage._buffer, inputImage._length);
2384
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002385 // Save input image timestamps for later output.
2386 frames_received_++;
2387 current_bytes_ += inputImage._length;
2388 timestamps_.push_back(inputImage._timeStamp);
2389 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2390 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2391
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002392 // Feed input to decoder.
2393 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2394 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2395 j_queue_input_buffer_method_,
2396 j_input_buffer_index,
2397 inputImage._length,
2398 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002399 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002400 if (!success) {
2401 ALOGE("queueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002402 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002403 Reset();
2404 return WEBRTC_VIDEO_CODEC_ERROR;
2405 }
2406
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002407 // Try to drain the decoder
2408 if (!DeliverPendingOutputs(jni, 0)) {
2409 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002410 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002411 Reset();
2412 return WEBRTC_VIDEO_CODEC_ERROR;
2413 }
2414
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002415 return WEBRTC_VIDEO_CODEC_OK;
2416}
2417
2418bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2419 JNIEnv* jni, int dequeue_timeout_us) {
2420 if (frames_received_ <= frames_decoded_) {
2421 // No need to query for output buffers - decoder is drained.
2422 return true;
2423 }
2424 // Get decoder output.
2425 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2426 *j_media_codec_video_decoder_,
2427 j_dequeue_output_buffer_method_,
2428 dequeue_timeout_us);
2429
2430 CHECK_EXCEPTION(jni);
2431 if (IsNull(jni, j_decoder_output_buffer_info)) {
2432 return true;
2433 }
2434
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002435 // Extract output buffer info from Java DecoderOutputBufferInfo.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002436 int output_buffer_index =
2437 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2438 if (output_buffer_index < 0) {
2439 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002440 return false;
2441 }
2442 int output_buffer_offset =
2443 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2444 int output_buffer_size =
2445 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2446 CHECK_EXCEPTION(jni);
2447
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002448 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002449 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2450 j_color_format_field_);
2451 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2452 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2453 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2454 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2455 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002456 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2457 j_textureID_field_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002458
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002459 // Extract data from Java ByteBuffer and create output yuv420 frame -
2460 // for non surface decoding only.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002461 if (!use_surface_) {
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002462 if (output_buffer_size < width * height * 3 / 2) {
2463 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002464 return false;
2465 }
2466 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2467 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2468 jobject output_buffer =
2469 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
2470 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
2471 output_buffer));
2472 CHECK_EXCEPTION(jni);
2473 payload += output_buffer_offset;
2474
2475 // Create yuv420 frame.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002476 if (color_format == COLOR_FormatYUV420Planar) {
2477 decoded_image_.CreateFrame(
2478 stride * slice_height, payload,
2479 (stride * slice_height) / 4, payload + (stride * slice_height),
2480 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2481 width, height,
2482 stride, stride / 2, stride / 2);
2483 } else {
2484 // All other supported formats are nv12.
2485 decoded_image_.CreateEmptyFrame(width, height, width,
2486 width / 2, width / 2);
2487 libyuv::NV12ToI420(
2488 payload, stride,
2489 payload + stride * slice_height, stride,
2490 decoded_image_.buffer(webrtc::kYPlane),
2491 decoded_image_.stride(webrtc::kYPlane),
2492 decoded_image_.buffer(webrtc::kUPlane),
2493 decoded_image_.stride(webrtc::kUPlane),
2494 decoded_image_.buffer(webrtc::kVPlane),
2495 decoded_image_.stride(webrtc::kVPlane),
2496 width, height);
2497 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002498 }
2499
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002500 // Get frame timestamps from a queue.
2501 int32_t timestamp = timestamps_.front();
2502 timestamps_.erase(timestamps_.begin());
2503 int64_t ntp_time_ms = ntp_times_ms_.front();
2504 ntp_times_ms_.erase(ntp_times_ms_.begin());
2505 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2506 frame_rtc_times_ms_.front();
2507 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2508
2509 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2510 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2511 color_format, output_buffer_size, frame_decoding_time_ms);
2512
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002513 // Return output buffer back to codec.
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002514 bool success = jni->CallBooleanMethod(
2515 *j_media_codec_video_decoder_,
2516 j_release_output_buffer_method_,
2517 output_buffer_index,
2518 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002519 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002520 if (!success) {
2521 ALOGE("releaseOutputBuffer error");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002522 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002523 }
2524
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002525 // Calculate and print decoding statistics - every 3 seconds.
2526 frames_decoded_++;
2527 current_frames_++;
2528 current_decoding_time_ms_ += frame_decoding_time_ms;
2529 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2530 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2531 current_frames_ > 0) {
2532 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2533 current_bytes_ * 8 / statistic_time_ms,
2534 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2535 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2536 start_time_ms_ = GetCurrentTimeMs();
2537 current_frames_ = 0;
2538 current_bytes_= 0;
2539 current_decoding_time_ms_ = 0;
2540 }
2541
2542 // Callback - output decoded frame.
2543 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2544 if (use_surface_) {
2545 native_handle_.SetTextureObject(surface_texture_, texture_id);
2546 TextureVideoFrame texture_image(
2547 &native_handle_, width, height, timestamp, 0);
2548 texture_image.set_ntp_time_ms(ntp_time_ms);
2549 callback_status = callback_->Decoded(texture_image);
2550 } else {
2551 decoded_image_.set_timestamp(timestamp);
2552 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2553 callback_status = callback_->Decoded(decoded_image_);
2554 }
2555 if (callback_status > 0) {
2556 ALOGE("callback error");
2557 }
2558
2559 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002560}
2561
2562int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2563 DecodedImageCallback* callback) {
2564 callback_ = callback;
2565 return WEBRTC_VIDEO_CODEC_OK;
2566}
2567
2568int32_t MediaCodecVideoDecoder::Reset() {
2569 ALOGD("DecoderReset");
2570 if (!inited_) {
2571 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2572 }
2573 return InitDecode(&codec_, 1);
2574}
2575
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002576void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002577 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2578 ScopedLocalRefFrame local_ref_frame(jni);
2579 if (!inited_) {
2580 return;
2581 }
2582 // We only ever send one message to |this| directly (not through a Bind()'d
2583 // functor), so expect no ID/data.
2584 CHECK(!msg->message_id) << "Unexpected message!";
2585 CHECK(!msg->pdata) << "Unexpected message!";
2586 CheckOnCodecThread();
2587
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002588 if (!DeliverPendingOutputs(jni, 0)) {
2589 error_count_++;
2590 Reset();
2591 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002592 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002593}
2594
2595class MediaCodecVideoDecoderFactory
2596 : public cricket::WebRtcVideoDecoderFactory {
2597 public:
2598 MediaCodecVideoDecoderFactory();
2599 virtual ~MediaCodecVideoDecoderFactory();
2600 // WebRtcVideoDecoderFactory implementation.
2601 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2602 webrtc::VideoCodecType type) OVERRIDE;
2603
2604 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2605
2606 private:
2607 bool is_platform_supported_;
2608};
2609
2610MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2611 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2612 ScopedLocalRefFrame local_ref_frame(jni);
2613 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2614 is_platform_supported_ = jni->CallStaticBooleanMethod(
2615 j_decoder_class,
2616 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002617 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002618}
2619
2620MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2621
2622webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2623 webrtc::VideoCodecType type) {
2624 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2625 return NULL;
2626 }
2627 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2628}
2629
2630
2631void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2632 webrtc::VideoDecoder* decoder) {
2633 delete decoder;
2634}
2635
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002636#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002637
2638} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002639
2640// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2641// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2642#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2643 Java_org_webrtc_##name
2644
2645extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002646 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002647 g_jvm = jvm;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002648 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002649
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002650 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002651
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002652 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002653
2654 JNIEnv* jni;
2655 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2656 return -1;
2657 g_class_reference_holder = new ClassReferenceHolder(jni);
2658
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002659 return JNI_VERSION_1_6;
2660}
2661
2662extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002663 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002664 delete g_class_reference_holder;
2665 g_class_reference_holder = NULL;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002666 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002667 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002668}
2669
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002670static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002671 jfieldID native_dc_id = GetFieldID(jni,
2672 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2673 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002674 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002675}
2676
2677JOW(jlong, DataChannel_registerObserverNative)(
2678 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002679 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002680 new DataChannelObserverWrapper(jni, j_observer));
2681 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002682 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002683}
2684
2685JOW(void, DataChannel_unregisterObserverNative)(
2686 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2687 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2688 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2689}
2690
2691JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2692 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2693}
2694
2695JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2696 return JavaEnumFromIndex(
2697 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2698}
2699
2700JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2701 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002702 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2703 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002704 return static_cast<jlong>(buffered_amount);
2705}
2706
2707JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2708 ExtractNativeDC(jni, j_dc)->Close();
2709}
2710
2711JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2712 jbyteArray data, jboolean binary) {
2713 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2714 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002715 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002716 binary));
2717 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2718 return ret;
2719}
2720
2721JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002722 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002723}
2724
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002725JOW(void, Logging_nativeEnableTracing)(
2726 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2727 jint nativeSeverity) {
2728 std::string path = JavaToStdString(jni, j_path);
2729 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002730 webrtc::Trace::set_level_filter(nativeLevels);
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002731#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002732 if (path != "logcat:") {
2733#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002734 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2735 << "SetTraceFile failed";
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002736#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002737 } else {
2738 // Intentionally leak this to avoid needing to reason about its lifecycle.
2739 // It keeps no state and functions only as a dispatch point.
2740 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2741 }
2742#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002743 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002744 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002745}
2746
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002747JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002748 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002749}
2750
2751JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2752 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2753 delete p;
2754}
2755
2756JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002757 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002758}
2759
2760JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2761 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2762}
2763
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002764JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2766}
2767
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002768JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2769 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2770}
2771
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002773 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002774}
2775
2776JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2777 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002778 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002779 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002780}
2781
2782JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2783 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002784 return reinterpret_cast<MediaStreamInterface*>(pointer)
2785 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786}
2787
2788JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2789 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002790 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002791 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002792}
2793
2794JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2795 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002796 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002797 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002798}
2799
2800JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2801 return JavaStringFromStdString(
2802 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2803}
2804
2805JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002806 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002807}
2808
2809JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2810 JNIEnv * jni, jclass, jobject j_observer) {
2811 return (jlong)new PCOJava(jni, j_observer);
2812}
2813
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002814#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002815JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002816 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002817 jboolean initialize_audio, jboolean initialize_video,
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002818 jboolean vp8_hw_acceleration, jobject render_egl_context) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002819 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002820 bool failure = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002821 vp8_hw_acceleration_enabled = vp8_hw_acceleration;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002822 if (!factory_static_initialized) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002823 if (initialize_video) {
2824 failure |= webrtc::SetCaptureAndroidVM(g_jvm, context);
2825 failure |= webrtc::SetRenderAndroidVM(g_jvm);
2826 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002827 if (initialize_audio)
2828 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2829 factory_static_initialized = true;
2830 }
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002831 if (initialize_video)
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002832 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2833 render_egl_context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002834 return !failure;
2835}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002836#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002837
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002838// Helper struct for working around the fact that CreatePeerConnectionFactory()
2839// comes in two flavors: either entirely automagical (constructing its own
2840// threads and deleting them on teardown, but no external codec factory support)
2841// or entirely manual (requires caller to delete threads after factory
2842// teardown). This struct takes ownership of its ctor's arguments to present a
2843// single thing for Java to hold and eventually free.
2844class OwnedFactoryAndThreads {
2845 public:
2846 OwnedFactoryAndThreads(Thread* worker_thread,
2847 Thread* signaling_thread,
2848 PeerConnectionFactoryInterface* factory)
2849 : worker_thread_(worker_thread),
2850 signaling_thread_(signaling_thread),
2851 factory_(factory) {}
2852
2853 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2854
2855 PeerConnectionFactoryInterface* factory() { return factory_; }
2856
2857 private:
2858 const scoped_ptr<Thread> worker_thread_;
2859 const scoped_ptr<Thread> signaling_thread_;
2860 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2861};
2862
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002863JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2864 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002865 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2866 // ThreadManager only WrapCurrentThread()s the thread where it is first
2867 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002868 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002869 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002870 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002871 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002872 Thread* worker_thread = new Thread();
2873 worker_thread->SetName("worker_thread", NULL);
2874 Thread* signaling_thread = new Thread();
2875 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002876 CHECK(worker_thread->Start() && signaling_thread->Start())
2877 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002878 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002879 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002880#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002881 if (vp8_hw_acceleration_enabled) {
2882 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
2883 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
2884 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002885#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002886 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002887 webrtc::CreatePeerConnectionFactory(worker_thread,
2888 signaling_thread,
2889 NULL,
2890 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002891 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002892 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2893 worker_thread, signaling_thread, factory.release());
2894 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002895}
2896
2897JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002898 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002899 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002900}
2901
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002902static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2903 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2904}
2905
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002906JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2907 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002908 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002909 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002910 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002911 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2912 return (jlong)stream.release();
2913}
2914
2915JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2916 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2917 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002918 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002919 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002920 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002921 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002922 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002923 factory->CreateVideoSource(
2924 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2925 constraints.get()));
2926 return (jlong)source.release();
2927}
2928
2929JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2930 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2931 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002932 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002933 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002934 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002935 factory->CreateVideoTrack(
2936 JavaToStdString(jni, id),
2937 reinterpret_cast<VideoSourceInterface*>(native_source)));
2938 return (jlong)track.release();
2939}
2940
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002941JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2942 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2943 scoped_ptr<ConstraintsWrapper> constraints(
2944 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002945 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002946 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002947 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002948 factory->CreateAudioSource(constraints.get()));
2949 return (jlong)source.release();
2950}
2951
2952JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2953 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2954 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002955 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002956 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002957 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002958 JavaToStdString(jni, id),
2959 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002960 return (jlong)track.release();
2961}
2962
2963static void JavaIceServersToJsepIceServers(
2964 JNIEnv* jni, jobject j_ice_servers,
2965 PeerConnectionInterface::IceServers* ice_servers) {
2966 jclass list_class = GetObjectClass(jni, j_ice_servers);
2967 jmethodID iterator_id = GetMethodID(
2968 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2969 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002970 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002971 jmethodID iterator_has_next = GetMethodID(
2972 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2973 jmethodID iterator_next = GetMethodID(
2974 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2975 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002976 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002978 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002979 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2980 jfieldID j_ice_server_uri_id =
2981 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2982 jfieldID j_ice_server_username_id =
2983 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2984 jfieldID j_ice_server_password_id =
2985 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2986 jstring uri = reinterpret_cast<jstring>(
2987 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2988 jstring username = reinterpret_cast<jstring>(
2989 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2990 jstring password = reinterpret_cast<jstring>(
2991 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2992 PeerConnectionInterface::IceServer server;
2993 server.uri = JavaToStdString(jni, uri);
2994 server.username = JavaToStdString(jni, username);
2995 server.password = JavaToStdString(jni, password);
2996 ice_servers->push_back(server);
2997 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002998 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002999}
3000
3001JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
3002 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
3003 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003004 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003005 reinterpret_cast<PeerConnectionFactoryInterface*>(
3006 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003007 PeerConnectionInterface::IceServers servers;
3008 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
3009 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
3010 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003011 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00003012 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003013 return (jlong)pc.release();
3014}
3015
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003016static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003017 JNIEnv* jni, jobject j_pc) {
3018 jfieldID native_pc_id = GetFieldID(jni,
3019 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
3020 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003021 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003022 reinterpret_cast<PeerConnectionInterface*>(j_p));
3023}
3024
3025JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
3026 const SessionDescriptionInterface* sdp =
3027 ExtractNativePC(jni, j_pc)->local_description();
3028 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3029}
3030
3031JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
3032 const SessionDescriptionInterface* sdp =
3033 ExtractNativePC(jni, j_pc)->remote_description();
3034 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3035}
3036
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003037JOW(jobject, PeerConnection_createDataChannel)(
3038 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
3039 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003040 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003041 ExtractNativePC(jni, j_pc)->CreateDataChannel(
3042 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00003043 // Mustn't pass channel.get() directly through NewObject to avoid reading its
3044 // vararg parameter as 64-bit and reading memory that doesn't belong to the
3045 // 32-bit parameter.
3046 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003047 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003048 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
3049 jmethodID j_data_channel_ctor = GetMethodID(
3050 jni, j_data_channel_class, "<init>", "(J)V");
3051 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00003052 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003053 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003054 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003055 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003056 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003057 return j_channel;
3058}
3059
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003060JOW(void, PeerConnection_createOffer)(
3061 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3062 ConstraintsWrapper* constraints =
3063 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003064 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3065 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003066 jni, j_observer, constraints));
3067 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3068}
3069
3070JOW(void, PeerConnection_createAnswer)(
3071 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3072 ConstraintsWrapper* constraints =
3073 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003074 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3075 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003076 jni, j_observer, constraints));
3077 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3078}
3079
3080// Helper to create a SessionDescriptionInterface from a SessionDescription.
3081static SessionDescriptionInterface* JavaSdpToNativeSdp(
3082 JNIEnv* jni, jobject j_sdp) {
3083 jfieldID j_type_id = GetFieldID(
3084 jni, GetObjectClass(jni, j_sdp), "type",
3085 "Lorg/webrtc/SessionDescription$Type;");
3086 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3087 jmethodID j_canonical_form_id = GetMethodID(
3088 jni, GetObjectClass(jni, j_type), "canonicalForm",
3089 "()Ljava/lang/String;");
3090 jstring j_type_string = (jstring)jni->CallObjectMethod(
3091 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003092 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003093 std::string std_type = JavaToStdString(jni, j_type_string);
3094
3095 jfieldID j_description_id = GetFieldID(
3096 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3097 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3098 std::string std_description = JavaToStdString(jni, j_description);
3099
3100 return webrtc::CreateSessionDescription(
3101 std_type, std_description, NULL);
3102}
3103
3104JOW(void, PeerConnection_setLocalDescription)(
3105 JNIEnv* jni, jobject j_pc,
3106 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003107 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3108 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003109 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3110 ExtractNativePC(jni, j_pc)->SetLocalDescription(
3111 observer, JavaSdpToNativeSdp(jni, j_sdp));
3112}
3113
3114JOW(void, PeerConnection_setRemoteDescription)(
3115 JNIEnv* jni, jobject j_pc,
3116 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003117 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3118 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003119 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3120 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3121 observer, JavaSdpToNativeSdp(jni, j_sdp));
3122}
3123
3124JOW(jboolean, PeerConnection_updateIce)(
3125 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3126 PeerConnectionInterface::IceServers ice_servers;
3127 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003128 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003129 new ConstraintsWrapper(jni, j_constraints));
3130 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3131}
3132
3133JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3134 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3135 jint j_sdp_mline_index, jstring j_candidate_sdp) {
3136 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3137 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003138 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003139 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3140 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3141}
3142
3143JOW(jboolean, PeerConnection_nativeAddLocalStream)(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003144 JNIEnv* jni, jobject j_pc, jlong native_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003145 return ExtractNativePC(jni, j_pc)->AddStream(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003146 reinterpret_cast<MediaStreamInterface*>(native_stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003147}
3148
3149JOW(void, PeerConnection_nativeRemoveLocalStream)(
3150 JNIEnv* jni, jobject j_pc, jlong native_stream) {
3151 ExtractNativePC(jni, j_pc)->RemoveStream(
3152 reinterpret_cast<MediaStreamInterface*>(native_stream));
3153}
3154
3155JOW(bool, PeerConnection_nativeGetStats)(
3156 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003157 rtc::scoped_refptr<StatsObserverWrapper> observer(
3158 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003159 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00003160 observer,
3161 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3162 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003163}
3164
3165JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3166 PeerConnectionInterface::SignalingState state =
3167 ExtractNativePC(jni, j_pc)->signaling_state();
3168 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3169}
3170
3171JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3172 PeerConnectionInterface::IceConnectionState state =
3173 ExtractNativePC(jni, j_pc)->ice_connection_state();
3174 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3175}
3176
3177JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
3178 PeerConnectionInterface::IceGatheringState state =
3179 ExtractNativePC(jni, j_pc)->ice_gathering_state();
3180 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
3181}
3182
3183JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3184 ExtractNativePC(jni, j_pc)->Close();
3185 return;
3186}
3187
3188JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003189 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003190 reinterpret_cast<MediaSourceInterface*>(j_p));
3191 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3192}
3193
3194JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
3195 JNIEnv* jni, jclass, jstring j_device_name) {
3196 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003197 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003198 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003199 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003200 cricket::Device device;
3201 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003202 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003203 return 0;
3204 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003205 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003206 device_manager->CreateVideoCapturer(device));
3207 return (jlong)capturer.release();
3208}
3209
3210JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3211 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003212 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3213 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003214 return (jlong)renderer.release();
3215}
3216
3217JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3218 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003219 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003220 new JavaVideoRendererWrapper(jni, j_callbacks));
3221 return (jlong)renderer.release();
3222}
3223
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003224JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3225 cricket::VideoCapturer* capturer =
3226 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003227 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003228 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3229 capturer->Stop();
3230 return jlongFromPointer(format.release());
3231}
3232
3233JOW(void, VideoSource_restart)(
3234 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003235 CHECK(j_p_source);
3236 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003237 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003238 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3239 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3240 StartCapturing(cricket::VideoFormat(*format));
3241}
3242
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00003243JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003244 JNIEnv* jni, jclass, jlong j_p) {
3245 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3246}
3247
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003248JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003249 return JavaStringFromStdString(
3250 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003251}
3252
3253JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003254 return JavaStringFromStdString(
3255 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003256}
3257
3258JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003259 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003260}
3261
3262JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003263 return JavaEnumFromIndex(
3264 jni,
3265 "MediaStreamTrack$State",
3266 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003267}
3268
3269JOW(jboolean, MediaStreamTrack_nativeSetState)(
3270 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003271 MediaStreamTrackInterface::TrackState new_state =
3272 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003273 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3274 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003275}
3276
3277JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3278 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003279 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3280 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003281}
3282
3283JOW(void, VideoTrack_nativeAddRenderer)(
3284 JNIEnv* jni, jclass,
3285 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003286 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003287 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3288}
3289
3290JOW(void, VideoTrack_nativeRemoveRenderer)(
3291 JNIEnv* jni, jclass,
3292 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003293 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003294 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3295}