blob: 8eb5ff042626e0b69a78618e21989b67f4801c52 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +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.org44ae4c82015-02-09 23:25:58 +000084#include "webrtc/base/stringutils.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000085#include "webrtc/common_video/interface/texture_video_frame.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000086#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +000087#include "webrtc/system_wrappers/interface/field_trial_default.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000088#include "webrtc/system_wrappers/interface/trace.h"
89#include "webrtc/video_engine/include/vie_base.h"
90#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091
glaznev@webrtc.org99678452014-09-15 17:52:42 +000092#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
93#include <android/log.h>
andresp@webrtc.org85ef7702014-09-17 11:44:51 +000094#include "webrtc/modules/video_capture/video_capture_internal.h"
95#include "webrtc/modules/video_render/video_render_internal.h"
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000096#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000097#include "webrtc/system_wrappers/interface/tick_util.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000098using webrtc::CodecSpecificInfo;
99using webrtc::DecodedImageCallback;
100using webrtc::EncodedImage;
101using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000102using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000103using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000104using webrtc::TextureVideoFrame;
105using webrtc::TickTime;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000106using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000107#endif
108
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109using icu::UnicodeString;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000110using rtc::Bind;
111using rtc::Thread;
112using rtc::ThreadManager;
113using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114using webrtc::AudioSourceInterface;
115using webrtc::AudioTrackInterface;
116using webrtc::AudioTrackVector;
117using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000118using webrtc::DataBuffer;
119using webrtc::DataChannelInit;
120using webrtc::DataChannelInterface;
121using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122using webrtc::IceCandidateInterface;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000123using webrtc::NativeHandle;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124using webrtc::MediaConstraintsInterface;
125using webrtc::MediaSourceInterface;
126using webrtc::MediaStreamInterface;
127using webrtc::MediaStreamTrackInterface;
128using webrtc::PeerConnectionFactoryInterface;
129using webrtc::PeerConnectionInterface;
130using webrtc::PeerConnectionObserver;
131using webrtc::SessionDescriptionInterface;
132using webrtc::SetSessionDescriptionObserver;
133using webrtc::StatsObserver;
134using webrtc::StatsReport;
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000135using webrtc::StatsReports;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136using webrtc::VideoRendererInterface;
137using webrtc::VideoSourceInterface;
138using webrtc::VideoTrackInterface;
139using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000140using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000141
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000142// Abort the process if |jni| has a Java exception pending.
143// This macros uses the comma operator to execute ExceptionDescribe
144// and ExceptionClear ignoring their return values and sending ""
145// to the error stream.
146#define CHECK_EXCEPTION(jni) \
147 CHECK(!jni->ExceptionCheck()) \
148 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000149
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000150// Helper that calls ptr->Release() and aborts the process with a useful
151// message if that didn't actually delete *ptr because of extra refcounts.
152#define CHECK_RELEASE(ptr) \
153 CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000154
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155namespace {
156
157static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
158
159static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000160// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
161// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
162// were attached by the JVM because of a Java->native call.
163static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +0000165// Field trials initialization string
166static char *field_trials_init_string = NULL;
167
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000168#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
169// Set in PeerConnectionFactory_initializeAndroidGlobals().
170static bool factory_static_initialized = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +0000171static bool vp8_hw_acceleration_enabled = true;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000172#endif
173
174
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000175// Return thread ID as a string.
176static std::string GetThreadId() {
177 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000178 CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
179 sizeof(buf))
180 << "Thread id is bigger than uint64??";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000181 return std::string(buf);
182}
183
184// Return the current thread's name.
185static std::string GetThreadName() {
186 char name[17];
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000187 CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000188 name[16] = '\0';
189 return std::string(name);
190}
191
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000192// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
193static JNIEnv* GetEnv() {
194 void* env = NULL;
195 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
196 CHECK(((env != NULL) && (status == JNI_OK)) ||
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000197 ((env == NULL) && (status == JNI_EDETACHED)))
198 << "Unexpected GetEnv return: " << status << ":" << env;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000199 return reinterpret_cast<JNIEnv*>(env);
200}
201
202static void ThreadDestructor(void* prev_jni_ptr) {
203 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
204 // we were responsible for originally attaching the thread, so are responsible
205 // for detaching it now. However, because some JVM implementations (notably
206 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
207 // the JVMs accounting info for this thread may already be wiped out by the
208 // time this is called. Thus it may appear we are already detached even though
209 // it was our responsibility to detach! Oh well.
210 if (!GetEnv())
211 return;
212
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000213 CHECK(GetEnv() == prev_jni_ptr)
214 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215 jint status = g_jvm->DetachCurrentThread();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000216 CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
217 CHECK(!GetEnv()) << "Detaching was a successful no-op???";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218}
219
220static void CreateJNIPtrKey() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000221 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
222 << "pthread_key_create";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000223}
224
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000225// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000227 JNIEnv* jni = GetEnv();
228 if (jni)
229 return jni;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000230 CHECK(!pthread_getspecific(g_jni_ptr))
231 << "TLS has a JNIEnv* but not attached?";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000232
233 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
234 JavaVMAttachArgs args;
235 args.version = JNI_VERSION_1_6;
236 args.name = name;
237 args.group = NULL;
238 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000239#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000240 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000241#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000242 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000244 CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000245 free(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000246 CHECK(env) << "AttachCurrentThread handed back NULL!";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000247 jni = reinterpret_cast<JNIEnv*>(env);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000248 CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000249 return jni;
250}
251
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000252// Return a |jlong| that will correctly convert back to |ptr|. This is needed
253// because the alternative (of silently passing a 32-bit pointer to a vararg
254// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000255static jlong jlongFromPointer(void* ptr) {
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +0000256 static_assert(sizeof(intptr_t) <= sizeof(jlong),
257 "Time to rethink the use of jlongs");
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000258 // Going through intptr_t to be obvious about the definedness of the
259 // conversion from pointer to integral type. intptr_t to jlong is a standard
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +0000260 // widening by the static_assert above.
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000261 jlong ret = reinterpret_cast<intptr_t>(ptr);
262 assert(reinterpret_cast<void*>(ret) == ptr);
263 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000264}
265
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266// Android's FindClass() is trickier than usual because the app-specific
267// ClassLoader is not consulted when there is no app-specific frame on the
268// stack. Consequently, we only look up classes once in JNI_OnLoad.
269// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
270class ClassReferenceHolder {
271 public:
272 explicit ClassReferenceHolder(JNIEnv* jni) {
273 LoadClass(jni, "java/nio/ByteBuffer");
274 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000275 LoadClass(jni, "org/webrtc/DataChannel");
276 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
277 LoadClass(jni, "org/webrtc/DataChannel$Init");
278 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000279 LoadClass(jni, "org/webrtc/IceCandidate");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000280#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
281 LoadClass(jni, "android/graphics/SurfaceTexture");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000282 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
283 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000284 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000285 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
glaznev@webrtc.orga8c0edd2014-10-20 19:08:05 +0000286 jclass j_decoder_class = GetClass("org/webrtc/MediaCodecVideoDecoder");
287 jmethodID j_is_egl14_supported_method = jni->GetStaticMethodID(
288 j_decoder_class, "isEGL14Supported", "()Z");
289 bool is_egl14_supported = jni->CallStaticBooleanMethod(
290 j_decoder_class, j_is_egl14_supported_method);
291 CHECK_EXCEPTION(jni);
292 if (is_egl14_supported) {
293 LoadClass(jni, "android/opengl/EGLContext");
294 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000295#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 LoadClass(jni, "org/webrtc/MediaSource$State");
297 LoadClass(jni, "org/webrtc/MediaStream");
298 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
300 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000301 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000302 LoadClass(jni, "org/webrtc/SessionDescription");
303 LoadClass(jni, "org/webrtc/SessionDescription$Type");
304 LoadClass(jni, "org/webrtc/StatsReport");
305 LoadClass(jni, "org/webrtc/StatsReport$Value");
306 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
307 LoadClass(jni, "org/webrtc/VideoTrack");
308 }
309
310 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000311 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000312 }
313
314 void FreeReferences(JNIEnv* jni) {
315 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
316 it != classes_.end(); ++it) {
317 jni->DeleteGlobalRef(it->second);
318 }
319 classes_.clear();
320 }
321
322 jclass GetClass(const std::string& name) {
323 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000324 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000325 return it->second;
326 }
327
328 private:
329 void LoadClass(JNIEnv* jni, const std::string& name) {
330 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000331 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
332 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000334 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
335 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000337 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338 }
339
340 std::map<std::string, jclass> classes_;
341};
342
343// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
344static ClassReferenceHolder* g_class_reference_holder = NULL;
345
346// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
347// object/class/method/field is non-null.
348jmethodID GetMethodID(
349 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
350 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000351 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
352 << signature;
353 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000354 return m;
355}
356
357jmethodID GetStaticMethodID(
358 JNIEnv* jni, jclass c, const char* name, const char* signature) {
359 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000360 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
361 << signature;
362 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000363 return m;
364}
365
366jfieldID GetFieldID(
367 JNIEnv* jni, jclass c, const char* name, const char* signature) {
368 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000369 CHECK_EXCEPTION(jni) << "error during GetFieldID";
370 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371 return f;
372}
373
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000374// Returns a global reference guaranteed to be valid for the lifetime of the
375// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000376jclass FindClass(JNIEnv* jni, const char* name) {
377 return g_class_reference_holder->GetClass(name);
378}
379
380jclass GetObjectClass(JNIEnv* jni, jobject object) {
381 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000382 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000383 CHECK(c) << "GetObjectClass returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384 return c;
385}
386
387jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
388 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000389 CHECK_EXCEPTION(jni) << "error during GetObjectField";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000390 CHECK(o) << "GetObjectField returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391 return o;
392}
393
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000394jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
395 return static_cast<jstring>(GetObjectField(jni, object, id));
396}
397
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000398jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
399 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000400 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401 return l;
402}
403
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000404jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
405 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000406 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000407 return i;
408}
409
410bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
411 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000412 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000413 return b;
414}
415
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416jobject NewGlobalRef(JNIEnv* jni, jobject o) {
417 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000418 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
419 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 return ret;
421}
422
423void DeleteGlobalRef(JNIEnv* jni, jobject o) {
424 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000425 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000426}
427
428// Given a jweak reference, allocate a (strong) local reference scoped to the
429// lifetime of this object if the weak reference is still valid, or NULL
430// otherwise.
431class WeakRef {
432 public:
433 WeakRef(JNIEnv* jni, jweak ref)
434 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000435 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 }
437 ~WeakRef() {
438 if (obj_) {
439 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000440 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441 }
442 }
443 jobject obj() { return obj_; }
444
445 private:
446 JNIEnv* const jni_;
447 jobject const obj_;
448};
449
fischman@webrtc.org41776152014-01-09 00:31:17 +0000450// Scope Java local references to the lifetime of this object. Use in all C++
451// callbacks (i.e. entry points that don't originate in a Java callstack
452// through a "native" method call).
453class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000455 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000456 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000458 ~ScopedLocalRefFrame() {
459 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000461
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462 private:
463 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464};
465
466// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000467template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000468class ScopedGlobalRef {
469 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000470 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000471 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000472 ~ScopedGlobalRef() {
473 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
474 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000475 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000476 return obj_;
477 }
478 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000479 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000480};
481
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000482// Java references to "null" can only be distinguished as such in C++ by
483// creating a local reference, so this helper wraps that logic.
484static bool IsNull(JNIEnv* jni, jobject obj) {
485 ScopedLocalRefFrame local_ref_frame(jni);
486 return jni->NewLocalRef(obj) == NULL;
487}
488
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000489// Return the (singleton) Java Enum object corresponding to |index|;
490// |state_class_fragment| is something like "MediaSource$State".
491jobject JavaEnumFromIndex(
492 JNIEnv* jni, const std::string& state_class_fragment, int index) {
493 std::string state_class_name = "org/webrtc/" + state_class_fragment;
494 jclass state_class = FindClass(jni, state_class_name.c_str());
495 jmethodID state_values_id = GetStaticMethodID(
496 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000497 jobjectArray state_values = static_cast<jobjectArray>(
498 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000499 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000500 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000501 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 return ret;
503}
504
505// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
506static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
507 UnicodeString ustr(UnicodeString::fromUTF8(native));
508 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000509 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 return jstr;
511}
512
513// Given a (UTF-16) jstring return a new UTF-8 native string.
514static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
515 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000516 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000518 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000520 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 std::string ret;
522 return ustr.toUTF8String(ret);
523}
524
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000525static DataChannelInit JavaDataChannelInitToNative(
526 JNIEnv* jni, jobject j_init) {
527 DataChannelInit init;
528
529 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
530 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
531 jfieldID max_retransmit_time_id =
532 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
533 jfieldID max_retransmits_id =
534 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
535 jfieldID protocol_id =
536 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
537 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
538 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
539
540 init.ordered = GetBooleanField(jni, j_init, ordered_id);
541 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
542 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
543 init.protocol = JavaToStdString(
544 jni, GetStringField(jni, j_init, protocol_id));
545 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
546 init.id = GetIntField(jni, j_init, id_id);
547
548 return init;
549}
550
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551class ConstraintsWrapper;
552
553// Adapter between the C++ PeerConnectionObserver interface and the Java
554// PeerConnection.Observer interface. Wraps an instance of the Java interface
555// and dispatches C++ callbacks to Java.
556class PCOJava : public PeerConnectionObserver {
557 public:
558 PCOJava(JNIEnv* jni, jobject j_observer)
559 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000560 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
561 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
562 j_media_stream_ctor_(GetMethodID(
563 jni, *j_media_stream_class_, "<init>", "(J)V")),
564 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000566 jni, *j_audio_track_class_, "<init>", "(J)V")),
567 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
568 j_video_track_ctor_(GetMethodID(
569 jni, *j_video_track_class_, "<init>", "(J)V")),
570 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
571 j_data_channel_ctor_(GetMethodID(
572 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 }
574
575 virtual ~PCOJava() {}
576
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000577 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000578 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000580 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
582 jmethodID ctor = GetMethodID(jni(), candidate_class,
583 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000584 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
585 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
586 jobject j_candidate = jni()->NewObject(
587 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000588 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000589 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000591 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000592 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 }
594
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000596 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000597 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000599 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000601 jobject new_state_enum =
602 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
603 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000604 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 }
606
607 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000608 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000609 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000611 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000613 jobject new_state_enum = JavaEnumFromIndex(
614 jni(), "PeerConnection$IceConnectionState", new_state);
615 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000616 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 }
618
619 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000620 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000621 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000623 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000625 jobject new_state_enum = JavaEnumFromIndex(
626 jni(), "PeerConnection$IceGatheringState", new_state);
627 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000628 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629 }
630
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000631 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000632 ScopedLocalRefFrame local_ref_frame(jni());
633 jobject j_stream = jni()->NewObject(
634 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000635 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636
637 AudioTrackVector audio_tracks = stream->GetAudioTracks();
638 for (size_t i = 0; i < audio_tracks.size(); ++i) {
639 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000640 jstring id = JavaStringFromStdString(jni(), track->id());
641 jobject j_track = jni()->NewObject(
642 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000643 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000644 jfieldID audio_tracks_id = GetFieldID(jni(),
645 *j_media_stream_class_,
646 "audioTracks",
647 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000648 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000650 GetObjectClass(jni(), audio_tracks),
651 "add",
652 "(Ljava/lang/Object;)Z");
653 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000654 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
655 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 }
657
658 VideoTrackVector video_tracks = stream->GetVideoTracks();
659 for (size_t i = 0; i < video_tracks.size(); ++i) {
660 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000661 jstring id = JavaStringFromStdString(jni(), track->id());
662 jobject j_track = jni()->NewObject(
663 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000664 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000665 jfieldID video_tracks_id = GetFieldID(jni(),
666 *j_media_stream_class_,
667 "videoTracks",
668 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000669 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000671 GetObjectClass(jni(), video_tracks),
672 "add",
673 "(Ljava/lang/Object;)Z");
674 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000675 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
676 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000678 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000679 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000681 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
682 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000683 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000684 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 }
686
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000687 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000688 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000690 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691
692 WeakRef s(jni(), it->second);
693 streams_.erase(it);
694 if (!s.obj())
695 return;
696
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000697 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
698 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000700 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701 }
702
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000703 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000704 ScopedLocalRefFrame local_ref_frame(jni());
705 jobject j_channel = jni()->NewObject(
706 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000707 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000708
709 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
710 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000711 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000712
713 // Channel is now owned by Java object, and will be freed from
714 // DataChannel.dispose(). Important that this be done _after_ the
715 // CallVoidMethod above as Java code might call back into native code and be
716 // surprised to see a refcount of 2.
717 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000718 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000719
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000720 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000721 }
722
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000723 virtual void OnRenegotiationNeeded() OVERRIDE {
724 ScopedLocalRefFrame local_ref_frame(jni());
725 jmethodID m =
726 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
727 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000728 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000729 }
730
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000732 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 constraints_.reset(constraints);
734 }
735
736 const ConstraintsWrapper* constraints() { return constraints_.get(); }
737
738 private:
739 JNIEnv* jni() {
740 return AttachCurrentThreadIfNeeded();
741 }
742
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000743 const ScopedGlobalRef<jobject> j_observer_global_;
744 const ScopedGlobalRef<jclass> j_observer_class_;
745 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000747 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000749 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000750 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000751 const ScopedGlobalRef<jclass> j_data_channel_class_;
752 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
754 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000755 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756};
757
758// Wrapper for a Java MediaConstraints object. Copies all needed data so when
759// the constructor returns the Java object is no longer needed.
760class ConstraintsWrapper : public MediaConstraintsInterface {
761 public:
762 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
763 PopulateConstraintsFromJavaPairList(
764 jni, j_constraints, "mandatory", &mandatory_);
765 PopulateConstraintsFromJavaPairList(
766 jni, j_constraints, "optional", &optional_);
767 }
768
769 virtual ~ConstraintsWrapper() {}
770
771 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000772 virtual const Constraints& GetMandatory() const OVERRIDE {
773 return mandatory_;
774 }
775
776 virtual const Constraints& GetOptional() const OVERRIDE {
777 return optional_;
778 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779
780 private:
781 // Helper for translating a List<Pair<String, String>> to a Constraints.
782 static void PopulateConstraintsFromJavaPairList(
783 JNIEnv* jni, jobject j_constraints,
784 const char* field_name, Constraints* field) {
785 jfieldID j_id = GetFieldID(jni,
786 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
787 jobject j_list = GetObjectField(jni, j_constraints, j_id);
788 jmethodID j_iterator_id = GetMethodID(jni,
789 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
790 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000791 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 jmethodID j_has_next = GetMethodID(jni,
793 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
794 jmethodID j_next = GetMethodID(jni,
795 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
796 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000797 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
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_key = GetMethodID(jni,
801 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
802 jstring j_key = reinterpret_cast<jstring>(
803 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000804 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 jmethodID get_value = GetMethodID(jni,
806 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
807 jstring j_value = reinterpret_cast<jstring>(
808 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000809 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810 field->push_back(Constraint(JavaToStdString(jni, j_key),
811 JavaToStdString(jni, j_value)));
812 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000813 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 }
815
816 Constraints mandatory_;
817 Constraints optional_;
818};
819
820static jobject JavaSdpFromNativeSdp(
821 JNIEnv* jni, const SessionDescriptionInterface* desc) {
822 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000823 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000824 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825
826 jclass j_type_class = FindClass(
827 jni, "org/webrtc/SessionDescription$Type");
828 jmethodID j_type_from_canonical = GetStaticMethodID(
829 jni, j_type_class, "fromCanonicalForm",
830 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000831 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000833 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000834 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835
836 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
837 jmethodID j_sdp_ctor = GetMethodID(
838 jni, j_sdp_class, "<init>",
839 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
840 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000841 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000842 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 return j_sdp;
844}
845
846template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
847class SdpObserverWrapper : public T {
848 public:
849 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
850 ConstraintsWrapper* constraints)
851 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000852 j_observer_global_(jni, j_observer),
853 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 }
855
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000856 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000858 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000860 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000861 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
862 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000863 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 }
865
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000866 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000868 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000869 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000870 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000872 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
873 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000874 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000875 }
876
877 protected:
878 // Common implementation for failure of Set & Create types, distinguished by
879 // |op| being "Set" or "Create".
880 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000881 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
882 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000883 jstring j_error_string = JavaStringFromStdString(jni(), error);
884 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000885 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886 }
887
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888 JNIEnv* jni() {
889 return AttachCurrentThreadIfNeeded();
890 }
891
fischman@webrtc.org41776152014-01-09 00:31:17 +0000892 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000893 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000894 const ScopedGlobalRef<jobject> j_observer_global_;
895 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000896};
897
898class CreateSdpObserverWrapper
899 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
900 public:
901 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
902 ConstraintsWrapper* constraints)
903 : SdpObserverWrapper(jni, j_observer, constraints) {}
904
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000905 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000906 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907 SdpObserverWrapper::OnFailure(std::string("Create"), error);
908 }
909};
910
911class SetSdpObserverWrapper
912 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
913 public:
914 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
915 ConstraintsWrapper* constraints)
916 : SdpObserverWrapper(jni, j_observer, constraints) {}
917
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000918 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000919 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000920 SdpObserverWrapper::OnFailure(std::string("Set"), error);
921 }
922};
923
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000924// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
925// and dispatching the callback from C++ back to Java.
926class DataChannelObserverWrapper : public DataChannelObserver {
927 public:
928 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
929 : j_observer_global_(jni, j_observer),
930 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000931 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000932 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
933 "onStateChange", "()V")),
934 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
935 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000936 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
937 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
938 }
939
940 virtual ~DataChannelObserverWrapper() {}
941
942 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000943 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000944 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000945 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000946 }
947
948 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000949 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000950 jobject byte_buffer =
951 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
952 buffer.data.length());
953 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
954 byte_buffer, buffer.binary);
955 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000956 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000957 }
958
959 private:
960 JNIEnv* jni() {
961 return AttachCurrentThreadIfNeeded();
962 }
963
964 const ScopedGlobalRef<jobject> j_observer_global_;
965 const ScopedGlobalRef<jclass> j_observer_class_;
966 const ScopedGlobalRef<jclass> j_buffer_class_;
967 const jmethodID j_on_state_change_mid_;
968 const jmethodID j_on_message_mid_;
969 const jmethodID j_buffer_ctor_;
970};
971
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000972// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
973// dispatching the callback from C++ back to Java.
974class StatsObserverWrapper : public StatsObserver {
975 public:
976 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000977 : j_observer_global_(jni, j_observer),
978 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
979 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000981 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000982 "(Ljava/lang/String;Ljava/lang/String;D"
983 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000984 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985 jni, "org/webrtc/StatsReport$Value")),
986 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000987 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 "(Ljava/lang/String;Ljava/lang/String;)V")) {
989 }
990
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000991 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000992
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000993 virtual void OnComplete(const StatsReports& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000994 ScopedLocalRefFrame local_ref_frame(jni());
995 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000996 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
997 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000998 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000999 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 }
1001
1002 private:
1003 jobjectArray ReportsToJava(
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001004 JNIEnv* jni, const StatsReports& reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001006 reports.size(), *j_stats_report_class_, NULL);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001007 int i = 0;
1008 for (const auto* report : reports) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001009 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001010 jstring j_id = JavaStringFromStdString(jni, report->id().ToString());
1011 jstring j_type = JavaStringFromStdString(jni, report->TypeToString());
1012 jobjectArray j_values = ValuesToJava(jni, report->values());
fischman@webrtc.org41776152014-01-09 00:31:17 +00001013 jobject j_report = jni->NewObject(*j_stats_report_class_,
1014 j_stats_report_ctor_,
1015 j_id,
1016 j_type,
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001017 report->timestamp(),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001018 j_values);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001019 jni->SetObjectArrayElement(reports_array, i++, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020 }
1021 return reports_array;
1022 }
1023
1024 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1025 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001026 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001027 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001028 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001029 const auto& value = values[i];
tommi@webrtc.orgc57310b2014-12-12 17:41:28 +00001030 // Should we use the '.name' enum value here instead of converting the
1031 // name to a string?
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001032 jstring j_name = JavaStringFromStdString(jni, value->display_name());
1033 jstring j_value = JavaStringFromStdString(jni, value->value);
fischman@webrtc.org41776152014-01-09 00:31:17 +00001034 jobject j_element_value =
1035 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1036 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 }
1038 return j_values;
1039 }
1040
1041 JNIEnv* jni() {
1042 return AttachCurrentThreadIfNeeded();
1043 }
1044
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001045 const ScopedGlobalRef<jobject> j_observer_global_;
1046 const ScopedGlobalRef<jclass> j_observer_class_;
1047 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001048 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001049 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001050 const jmethodID j_value_ctor_;
1051};
1052
1053// Adapter presenting a cricket::VideoRenderer as a
1054// webrtc::VideoRendererInterface.
1055class VideoRendererWrapper : public VideoRendererInterface {
1056 public:
1057 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1058 if (renderer)
1059 return new VideoRendererWrapper(renderer);
1060 return NULL;
1061 }
1062
1063 virtual ~VideoRendererWrapper() {}
1064
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001065 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001066 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001067 const bool kNotReserved = false; // What does this param mean??
1068 renderer_->SetSize(width, height, kNotReserved);
1069 }
1070
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001071 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001072 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001073 renderer_->RenderFrame(frame);
1074 }
1075
1076 private:
1077 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1078 : renderer_(renderer) {}
1079
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001080 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081};
1082
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001083// Wrapper for texture object in TextureVideoFrame.
1084class NativeHandleImpl : public NativeHandle {
1085 public:
1086 NativeHandleImpl() :
1087 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1088 virtual ~NativeHandleImpl() {}
1089 virtual int32_t AddRef() {
1090 return ++ref_count_;
1091 }
1092 virtual int32_t Release() {
1093 return --ref_count_;
1094 }
1095 virtual void* GetHandle() {
1096 return texture_object_;
1097 }
1098 int GetTextureId() {
1099 return texture_id_;
1100 }
1101 void SetTextureObject(void *texture_object, int texture_id) {
1102 texture_object_ = reinterpret_cast<jobject>(texture_object);
1103 texture_id_ = texture_id;
1104 }
1105 int32_t ref_count() {
1106 return ref_count_;
1107 }
1108
1109 private:
1110 int32_t ref_count_;
1111 jobject texture_object_;
1112 int32_t texture_id_;
1113};
1114
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001115// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1116// instance.
1117class JavaVideoRendererWrapper : public VideoRendererInterface {
1118 public:
1119 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001120 : j_callbacks_(jni, j_callbacks),
1121 j_set_size_id_(GetMethodID(
1122 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1123 j_render_frame_id_(GetMethodID(
1124 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1125 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1126 j_frame_class_(jni,
1127 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001128 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001129 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001130 j_texture_frame_ctor_id_(GetMethodID(
1131 jni, *j_frame_class_, "<init>",
1132 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001133 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001134 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001135 }
1136
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001137 virtual ~JavaVideoRendererWrapper() {}
1138
1139 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001140 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001141 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001142 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001143 }
1144
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001145 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001146 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001147 if (frame->GetNativeHandle() != NULL) {
1148 jobject j_frame = CricketToJavaTextureFrame(frame);
1149 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1150 CHECK_EXCEPTION(jni());
1151 } else {
1152 jobject j_frame = CricketToJavaI420Frame(frame);
1153 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1154 CHECK_EXCEPTION(jni());
1155 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001156 }
1157
1158 private:
1159 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001160 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001161 jintArray strides = jni()->NewIntArray(3);
1162 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001163 strides_array[0] = frame->GetYPitch();
1164 strides_array[1] = frame->GetUPitch();
1165 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001166 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1167 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1168 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001170 frame->GetYPitch() * frame->GetHeight());
1171 jobject u_buffer = jni()->NewDirectByteBuffer(
1172 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1173 jobject v_buffer = jni()->NewDirectByteBuffer(
1174 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1175 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1176 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1177 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001179 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001180 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 }
1182
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001183 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1184 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1185 NativeHandleImpl* handle =
1186 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1187 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1188 int texture_id = handle->GetTextureId();
1189 return jni()->NewObject(
1190 *j_frame_class_, j_texture_frame_ctor_id_,
1191 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1192 }
1193
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194 JNIEnv* jni() {
1195 return AttachCurrentThreadIfNeeded();
1196 }
1197
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001198 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001199 jmethodID j_set_size_id_;
1200 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001201 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001202 jmethodID j_i420_frame_ctor_id_;
1203 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001204 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001205};
1206
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001207#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001208// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1209// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1210// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001211
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001212//#define TRACK_BUFFER_TIMING
1213#define TAG "MediaCodecVideo"
1214#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001215#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1216#else
1217#define ALOGV(...)
1218#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001219#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1220#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001221
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001222// Color formats supported by encoder - should mirror supportedColorList
1223// from MediaCodecVideoEncoder.java
1224enum COLOR_FORMATTYPE {
1225 COLOR_FormatYUV420Planar = 0x13,
1226 COLOR_FormatYUV420SemiPlanar = 0x15,
1227 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1228 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1229 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1230 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1231 // but requires some (16, 32?) byte alignment.
1232 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1233};
1234
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001235// Arbitrary interval to poll the codec for new outputs.
1236enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001237// Media codec maximum output buffer ready timeout.
1238enum { kMediaCodecTimeoutMs = 500 };
1239// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1240enum { kMediaCodecStatisticsIntervalMs = 3000 };
1241
1242static int64_t GetCurrentTimeMs() {
1243 return TickTime::Now().Ticks() / 1000000LL;
1244}
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001245
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001246// Allow Invoke() calls from from current thread.
1247static void AllowBlockingCalls() {
1248 Thread* current_thread = Thread::Current();
1249 if (current_thread != NULL)
1250 current_thread->SetAllowBlockingCalls(true);
1251}
1252
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001253// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1254// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1255// HW-backed video encode. This C++ class is implemented as a very thin shim,
1256// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1257// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1258// thread, currently the libjingle Worker thread.
1259class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001260 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001261 public:
1262 virtual ~MediaCodecVideoEncoder();
1263 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1264
1265 // webrtc::VideoEncoder implementation. Everything trampolines to
1266 // |codec_thread_| for execution.
1267 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1268 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001269 size_t /* max_payload_size */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001270 virtual int32_t Encode(
1271 const webrtc::I420VideoFrame& input_image,
1272 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1273 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1274 virtual int32_t RegisterEncodeCompleteCallback(
1275 webrtc::EncodedImageCallback* callback) OVERRIDE;
1276 virtual int32_t Release() OVERRIDE;
1277 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001278 int64_t /* rtt */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001279 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1280
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001281 // rtc::MessageHandler implementation.
1282 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001283
1284 private:
1285 // CHECK-fail if not running on |codec_thread_|.
1286 void CheckOnCodecThread();
1287
1288 // Release() and InitEncode() in an attempt to restore the codec to an
1289 // operable state. Necessary after all manner of OMX-layer errors.
1290 void ResetCodec();
1291
1292 // Implementation of webrtc::VideoEncoder methods above, all running on the
1293 // codec thread exclusively.
1294 //
1295 // If width==0 then this is assumed to be a re-initialization and the
1296 // previously-current values are reused instead of the passed parameters
1297 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001298 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001299 int32_t EncodeOnCodecThread(
1300 const webrtc::I420VideoFrame& input_image,
1301 const std::vector<webrtc::VideoFrameType>* frame_types);
1302 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1303 webrtc::EncodedImageCallback* callback);
1304 int32_t ReleaseOnCodecThread();
1305 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1306
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001307 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1308 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1309 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1310 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1311 jlong GetOutputBufferInfoPresentationTimestampUs(
1312 JNIEnv* jni,
1313 jobject j_output_buffer_info);
1314
1315 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1316 // true on success.
1317 bool DeliverPendingOutputs(JNIEnv* jni);
1318
1319 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1320 // |codec_thread_| synchronously.
1321 webrtc::EncodedImageCallback* callback_;
1322
1323 // State that is constant for the lifetime of this object once the ctor
1324 // returns.
1325 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1326 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1327 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1328 jmethodID j_init_encode_method_;
1329 jmethodID j_dequeue_input_buffer_method_;
1330 jmethodID j_encode_method_;
1331 jmethodID j_release_method_;
1332 jmethodID j_set_rates_method_;
1333 jmethodID j_dequeue_output_buffer_method_;
1334 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001335 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001336 jfieldID j_info_index_field_;
1337 jfieldID j_info_buffer_field_;
1338 jfieldID j_info_is_key_frame_field_;
1339 jfieldID j_info_presentation_timestamp_us_field_;
1340
1341 // State that is valid only between InitEncode() and the next Release().
1342 // Touched only on codec_thread_ so no explicit synchronization necessary.
1343 int width_; // Frame width in pixels.
1344 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001345 bool inited_;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001346 uint16_t picture_id_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001347 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001348 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001349 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001350 int64_t current_timestamp_us_; // Current frame timestamps in us.
1351 int frames_received_; // Number of frames received by encoder.
1352 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001353 int frames_resolution_update_; // Number of frames with new codec resolution.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001354 int frames_in_queue_; // Number of frames in encoder queue.
1355 int64_t start_time_ms_; // Start time for statistics.
1356 int current_frames_; // Number of frames in the current statistics interval.
1357 int current_bytes_; // Encoded bytes in the current statistics interval.
1358 int current_encoding_time_ms_; // Overall encoding time in the current second
1359 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1360 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
1361 std::vector<int32_t> timestamps_; // Video frames timestamp queue.
1362 std::vector<int64_t> render_times_ms_; // Video frames render time queue.
1363 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1364 // encoder input.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001365 // Frame size in bytes fed to MediaCodec.
1366 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001367 // True only when between a callback_->Encoded() call return a positive value
1368 // and the next Encode() call being ignored.
1369 bool drop_next_input_frame_;
1370 // Global references; must be deleted in Release().
1371 std::vector<jobject> input_buffers_;
1372};
1373
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001374MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001375 // Call Release() to ensure no more callbacks to us after we are deleted.
1376 Release();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001377}
1378
1379MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001380 : callback_(NULL),
1381 inited_(false),
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001382 picture_id_(0),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001383 codec_thread_(new Thread()),
1384 j_media_codec_video_encoder_class_(
1385 jni,
1386 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1387 j_media_codec_video_encoder_(
1388 jni,
1389 jni->NewObject(*j_media_codec_video_encoder_class_,
1390 GetMethodID(jni,
1391 *j_media_codec_video_encoder_class_,
1392 "<init>",
1393 "()V"))) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001394 ScopedLocalRefFrame local_ref_frame(jni);
1395 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1396 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1397 // 2732 means that deadlocks abound. This class synchronously trampolines
1398 // to |codec_thread_|, so if anything else can be coming to _us_ from
1399 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1400 // in the bug, we have a problem. For now work around that with a dedicated
1401 // thread.
1402 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001403 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001404
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001405 jclass j_output_buffer_info_class =
1406 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1407 j_init_encode_method_ = GetMethodID(jni,
1408 *j_media_codec_video_encoder_class_,
1409 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001410 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001411 j_dequeue_input_buffer_method_ = GetMethodID(
1412 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1413 j_encode_method_ = GetMethodID(
1414 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1415 j_release_method_ =
1416 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1417 j_set_rates_method_ = GetMethodID(
1418 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1419 j_dequeue_output_buffer_method_ =
1420 GetMethodID(jni,
1421 *j_media_codec_video_encoder_class_,
1422 "dequeueOutputBuffer",
1423 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1424 j_release_output_buffer_method_ = GetMethodID(
1425 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1426
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001427 j_color_format_field_ =
1428 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001429 j_info_index_field_ =
1430 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1431 j_info_buffer_field_ = GetFieldID(
1432 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1433 j_info_is_key_frame_field_ =
1434 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1435 j_info_presentation_timestamp_us_field_ = GetFieldID(
1436 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001437 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001438 AllowBlockingCalls();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001439}
1440
1441int32_t MediaCodecVideoEncoder::InitEncode(
1442 const webrtc::VideoCodec* codec_settings,
1443 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001444 size_t /* max_payload_size */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001445 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001446 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001447
1448 return codec_thread_->Invoke<int32_t>(
1449 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1450 this,
1451 codec_settings->width,
1452 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001453 codec_settings->startBitrate,
1454 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001455}
1456
1457int32_t MediaCodecVideoEncoder::Encode(
1458 const webrtc::I420VideoFrame& frame,
1459 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1460 const std::vector<webrtc::VideoFrameType>* frame_types) {
1461 return codec_thread_->Invoke<int32_t>(Bind(
1462 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1463}
1464
1465int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1466 webrtc::EncodedImageCallback* callback) {
1467 return codec_thread_->Invoke<int32_t>(
1468 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1469 this,
1470 callback));
1471}
1472
1473int32_t MediaCodecVideoEncoder::Release() {
1474 return codec_thread_->Invoke<int32_t>(
1475 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1476}
1477
1478int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001479 int64_t /* rtt */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001480 return WEBRTC_VIDEO_CODEC_OK;
1481}
1482
1483int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1484 uint32_t frame_rate) {
1485 return codec_thread_->Invoke<int32_t>(
1486 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1487 this,
1488 new_bit_rate,
1489 frame_rate));
1490}
1491
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001492void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001493 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1494 ScopedLocalRefFrame local_ref_frame(jni);
1495
1496 // We only ever send one message to |this| directly (not through a Bind()'d
1497 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001498 CHECK(!msg->message_id) << "Unexpected message!";
1499 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001500 CheckOnCodecThread();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001501 if (!inited_) {
1502 return;
1503 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001504
1505 // It would be nice to recover from a failure here if one happened, but it's
1506 // unclear how to signal such a failure to the app, so instead we stay silent
1507 // about it and let the next app-called API method reveal the borkedness.
1508 DeliverPendingOutputs(jni);
1509 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1510}
1511
1512void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001513 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1514 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001515}
1516
1517void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001518 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001519 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1520 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001521 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1522 width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001523 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1524 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1525 // https://code.google.com/p/webrtc/issues/detail?id=2920
1526 }
1527}
1528
1529int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001530 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001531 CheckOnCodecThread();
1532 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1533 ScopedLocalRefFrame local_ref_frame(jni);
1534
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001535 ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1536 width, height, kbps, fps);
1537 if (kbps == 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001538 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001539 }
1540 if (fps == 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001541 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001542 }
1543
1544 width_ = width;
1545 height_ = height;
1546 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001547 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001548 yuv_size_ = width_ * height_ * 3 / 2;
1549 frames_received_ = 0;
1550 frames_dropped_ = 0;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001551 frames_resolution_update_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001552 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001553 current_timestamp_us_ = 0;
1554 start_time_ms_ = GetCurrentTimeMs();
1555 current_frames_ = 0;
1556 current_bytes_ = 0;
1557 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001558 last_input_timestamp_ms_ = -1;
1559 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001560 timestamps_.clear();
1561 render_times_ms_.clear();
1562 frame_rtc_times_ms_.clear();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001563 drop_next_input_frame_ = false;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001564 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001565 // We enforce no extra stride/padding in the format creation step.
1566 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1567 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1568 j_init_encode_method_,
1569 width_,
1570 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001571 kbps,
1572 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001573 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001574 if (IsNull(jni, input_buffers))
1575 return WEBRTC_VIDEO_CODEC_ERROR;
1576
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001577 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001578 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1579 j_color_format_field_)) {
1580 case COLOR_FormatYUV420Planar:
1581 encoder_fourcc_ = libyuv::FOURCC_YU12;
1582 break;
1583 case COLOR_FormatYUV420SemiPlanar:
1584 case COLOR_QCOM_FormatYUV420SemiPlanar:
1585 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1586 encoder_fourcc_ = libyuv::FOURCC_NV12;
1587 break;
1588 default:
1589 LOG(LS_ERROR) << "Wrong color format.";
1590 return WEBRTC_VIDEO_CODEC_ERROR;
1591 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001592 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001593 CHECK(input_buffers_.empty())
1594 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001595 input_buffers_.resize(num_input_buffers);
1596 for (size_t i = 0; i < num_input_buffers; ++i) {
1597 input_buffers_[i] =
1598 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001599 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001600 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001601 CHECK_EXCEPTION(jni);
1602 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001603 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001604 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001605
1606 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1607 return WEBRTC_VIDEO_CODEC_OK;
1608}
1609
1610int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1611 const webrtc::I420VideoFrame& frame,
1612 const std::vector<webrtc::VideoFrameType>* frame_types) {
1613 CheckOnCodecThread();
1614 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1615 ScopedLocalRefFrame local_ref_frame(jni);
1616
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001617 if (!inited_) {
1618 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1619 }
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001620 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001621 if (!DeliverPendingOutputs(jni)) {
1622 ResetCodec();
1623 // Continue as if everything's fine.
1624 }
1625
1626 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001627 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001628 drop_next_input_frame_ = false;
1629 return WEBRTC_VIDEO_CODEC_OK;
1630 }
1631
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001632 CHECK(frame_types->size() == 1) << "Unexpected stream count";
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001633 if (frame.width() != width_ || frame.height() != height_) {
1634 frames_resolution_update_++;
1635 ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1636 width_, height_, frame.width(), frame.height());
1637 if (frames_resolution_update_ > 3) {
1638 // Reset codec if we received more than 3 frames with new resolution.
1639 width_ = frame.width();
1640 height_ = frame.height();
1641 frames_resolution_update_ = 0;
1642 ResetCodec();
1643 }
1644 return WEBRTC_VIDEO_CODEC_OK;
1645 }
1646 frames_resolution_update_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001647
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001648 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1649
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001650 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001651 // or the encoder latency exceeds 70 ms and drop frame if so.
1652 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001653 int encoder_latency_ms = last_input_timestamp_ms_ -
1654 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001655 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001656 ALOGD("Drop frame - encoder is behind by %d ms. Q size: %d",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001657 encoder_latency_ms, frames_in_queue_);
1658 frames_dropped_++;
1659 return WEBRTC_VIDEO_CODEC_OK;
1660 }
1661 }
1662
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001663 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1664 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001665 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001666 if (j_input_buffer_index == -1) {
1667 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001668 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001669 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001670 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001671 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001672 if (j_input_buffer_index == -2) {
1673 ResetCodec();
1674 return WEBRTC_VIDEO_CODEC_ERROR;
1675 }
1676
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001677 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001678 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001679
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001680 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001681 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001682 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001683 CHECK_EXCEPTION(jni);
1684 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001685 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001686 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1687 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1688 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1689 yuv_buffer, width_,
1690 width_, height_,
1691 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001692 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001693 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001694 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001695
1696 // Save input image timestamps for later output
1697 timestamps_.push_back(frame.timestamp());
1698 render_times_ms_.push_back(frame.render_time_ms());
1699 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1700
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001701 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1702 j_encode_method_,
1703 key_frame,
1704 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001705 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001706 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001707 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001708 current_timestamp_us_ += 1000000 / last_set_fps_;
1709
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001710 if (!encode_status || !DeliverPendingOutputs(jni)) {
1711 ResetCodec();
1712 return WEBRTC_VIDEO_CODEC_ERROR;
1713 }
1714
1715 return WEBRTC_VIDEO_CODEC_OK;
1716}
1717
1718int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1719 webrtc::EncodedImageCallback* callback) {
1720 CheckOnCodecThread();
1721 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1722 ScopedLocalRefFrame local_ref_frame(jni);
1723 callback_ = callback;
1724 return WEBRTC_VIDEO_CODEC_OK;
1725}
1726
1727int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001728 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001729 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001730 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001731 CheckOnCodecThread();
1732 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001733 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1734 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001735 ScopedLocalRefFrame local_ref_frame(jni);
1736 for (size_t i = 0; i < input_buffers_.size(); ++i)
1737 jni->DeleteGlobalRef(input_buffers_[i]);
1738 input_buffers_.clear();
1739 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001740 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001741 rtc::MessageQueueManager::Clear(this);
1742 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001743 return WEBRTC_VIDEO_CODEC_OK;
1744}
1745
1746int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1747 uint32_t frame_rate) {
1748 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001749 if (last_set_bitrate_kbps_ == new_bit_rate &&
1750 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001751 return WEBRTC_VIDEO_CODEC_OK;
1752 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001753 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1754 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001755 if (new_bit_rate > 0) {
1756 last_set_bitrate_kbps_ = new_bit_rate;
1757 }
1758 if (frame_rate > 0) {
1759 last_set_fps_ = frame_rate;
1760 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001761 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1762 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001763 last_set_bitrate_kbps_,
1764 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001765 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001766 if (!ret) {
1767 ResetCodec();
1768 return WEBRTC_VIDEO_CODEC_ERROR;
1769 }
1770 return WEBRTC_VIDEO_CODEC_OK;
1771}
1772
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001773int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1774 JNIEnv* jni,
1775 jobject j_output_buffer_info) {
1776 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1777}
1778
1779jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1780 JNIEnv* jni,
1781 jobject j_output_buffer_info) {
1782 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1783}
1784
1785bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1786 JNIEnv* jni,
1787 jobject j_output_buffer_info) {
1788 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1789}
1790
1791jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1792 JNIEnv* jni,
1793 jobject j_output_buffer_info) {
1794 return GetLongField(
1795 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1796}
1797
1798bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1799 while (true) {
1800 jobject j_output_buffer_info = jni->CallObjectMethod(
1801 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001802 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001803 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001804 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001805 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001806
1807 int output_buffer_index =
1808 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1809 if (output_buffer_index == -1) {
1810 ResetCodec();
1811 return false;
1812 }
1813
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001814 // Get frame timestamps from a queue.
1815 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001816 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1817 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001818 int32_t timestamp = timestamps_.front();
1819 timestamps_.erase(timestamps_.begin());
1820 int64_t render_time_ms = render_times_ms_.front();
1821 render_times_ms_.erase(render_times_ms_.begin());
1822 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1823 frame_rtc_times_ms_.front();
1824 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001825 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001826
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001827 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001828 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001829 jobject j_output_buffer =
1830 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1831 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1832 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1833 uint8* payload = reinterpret_cast<uint8_t*>(
1834 jni->GetDirectBufferAddress(j_output_buffer));
1835 CHECK_EXCEPTION(jni);
1836
1837 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1838 " EncTime: %lld",
1839 output_buffer_index, payload_size, last_output_timestamp_ms_,
1840 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1841 frame_encoding_time_ms);
1842
1843 // Calculate and print encoding statistics - every 3 seconds.
1844 current_frames_++;
1845 current_bytes_ += payload_size;
1846 current_encoding_time_ms_ += frame_encoding_time_ms;
1847 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1848 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1849 current_frames_ > 0) {
1850 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1851 " encTime: %d for last %d ms",
1852 current_bytes_ * 8 / statistic_time_ms,
1853 last_set_bitrate_kbps_,
1854 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1855 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1856 start_time_ms_ = GetCurrentTimeMs();
1857 current_frames_ = 0;
1858 current_bytes_= 0;
1859 current_encoding_time_ms_ = 0;
1860 }
1861
1862 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001863 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001864 scoped_ptr<webrtc::EncodedImage> image(
1865 new webrtc::EncodedImage(payload, payload_size, payload_size));
1866 image->_encodedWidth = width_;
1867 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001868 image->_timeStamp = timestamp;
1869 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001870 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1871 image->_completeFrame = true;
1872
1873 webrtc::CodecSpecificInfo info;
1874 memset(&info, 0, sizeof(info));
1875 info.codecType = kVideoCodecVP8;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001876 info.codecSpecific.VP8.pictureId = picture_id_;
1877 info.codecSpecific.VP8.nonReference = false;
1878 info.codecSpecific.VP8.simulcastIdx = 0;
1879 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx;
1880 info.codecSpecific.VP8.layerSync = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001881 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1882 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001883 picture_id_ = (picture_id_ + 1) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001884
1885 // Generate a header describing a single fragment.
1886 webrtc::RTPFragmentationHeader header;
1887 memset(&header, 0, sizeof(header));
1888 header.VerifyAndAllocateFragmentationHeader(1);
1889 header.fragmentationOffset[0] = 0;
1890 header.fragmentationLength[0] = image->_length;
1891 header.fragmentationPlType[0] = 0;
1892 header.fragmentationTimeDiff[0] = 0;
1893
1894 callback_status = callback_->Encoded(*image, &info, &header);
1895 }
1896
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001897 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001898 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1899 j_release_output_buffer_method_,
1900 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001901 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001902 if (!success) {
1903 ResetCodec();
1904 return false;
1905 }
1906
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001907 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001908 drop_next_input_frame_ = true;
1909 // Theoretically could handle callback_status<0 here, but unclear what that
1910 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001911 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001912 }
1913
1914 return true;
1915}
1916
1917// Simplest-possible implementation of an encoder factory, churns out
1918// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1919class MediaCodecVideoEncoderFactory
1920 : public cricket::WebRtcVideoEncoderFactory {
1921 public:
1922 MediaCodecVideoEncoderFactory();
1923 virtual ~MediaCodecVideoEncoderFactory();
1924
1925 // WebRtcVideoEncoderFactory implementation.
1926 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1927 OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001928 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1929 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1930
1931 private:
1932 // Empty if platform support is lacking, const after ctor returns.
1933 std::vector<VideoCodec> supported_codecs_;
1934};
1935
1936MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1937 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1938 ScopedLocalRefFrame local_ref_frame(jni);
1939 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1940 bool is_platform_supported = jni->CallStaticBooleanMethod(
1941 j_encoder_class,
1942 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001943 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001944 if (!is_platform_supported)
1945 return;
1946
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001947 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1948 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1949 // reasonable defaults.
1950 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001951 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001952}
1953
1954MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1955
1956webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1957 webrtc::VideoCodecType type) {
1958 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1959 return NULL;
1960 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1961}
1962
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001963const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1964MediaCodecVideoEncoderFactory::codecs() const {
1965 return supported_codecs_;
1966}
1967
1968void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1969 webrtc::VideoEncoder* encoder) {
1970 delete encoder;
1971}
1972
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001973class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001974 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001975 public:
1976 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1977 virtual ~MediaCodecVideoDecoder();
1978
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001979 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1980
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001981 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1982 int32_t numberOfCores) OVERRIDE;
1983
1984 virtual int32_t
1985 Decode(const EncodedImage& inputImage, bool missingFrames,
1986 const RTPFragmentationHeader* fragmentation,
1987 const CodecSpecificInfo* codecSpecificInfo = NULL,
1988 int64_t renderTimeMs = -1) OVERRIDE;
1989
1990 virtual int32_t RegisterDecodeCompleteCallback(
1991 DecodedImageCallback* callback) OVERRIDE;
1992
1993 virtual int32_t Release() OVERRIDE;
1994
1995 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001996 // rtc::MessageHandler implementation.
1997 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001998
1999 private:
2000 // CHECK-fail if not running on |codec_thread_|.
2001 void CheckOnCodecThread();
2002
2003 int32_t InitDecodeOnCodecThread();
2004 int32_t ReleaseOnCodecThread();
2005 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002006 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
2007 // true on success.
2008 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
2009
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002010
2011 bool key_frame_required_;
2012 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002013 bool use_surface_;
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002014 int error_count_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002015 VideoCodec codec_;
2016 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002017 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002018 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002019 int frames_received_; // Number of frames received by decoder.
2020 int frames_decoded_; // Number of frames decoded by decoder
2021 int64_t start_time_ms_; // Start time for statistics.
2022 int current_frames_; // Number of frames in the current statistics interval.
2023 int current_bytes_; // Encoded bytes in the current statistics interval.
2024 int current_decoding_time_ms_; // Overall decoding time in the current second
2025 uint32_t max_pending_frames_; // Maximum number of pending input frames
2026 std::vector<int32_t> timestamps_;
2027 std::vector<int64_t> ntp_times_ms_;
2028 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
2029 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002030
2031 // State that is constant for the lifetime of this object once the ctor
2032 // returns.
2033 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
2034 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2035 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2036 jmethodID j_init_decode_method_;
2037 jmethodID j_release_method_;
2038 jmethodID j_dequeue_input_buffer_method_;
2039 jmethodID j_queue_input_buffer_method_;
2040 jmethodID j_dequeue_output_buffer_method_;
2041 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002042 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002043 jfieldID j_input_buffers_field_;
2044 jfieldID j_output_buffers_field_;
2045 jfieldID j_color_format_field_;
2046 jfieldID j_width_field_;
2047 jfieldID j_height_field_;
2048 jfieldID j_stride_field_;
2049 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002050 jfieldID j_surface_texture_field_;
2051 jfieldID j_textureID_field_;
2052 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2053 jfieldID j_info_index_field_;
2054 jfieldID j_info_offset_field_;
2055 jfieldID j_info_size_field_;
2056 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002057
2058 // Global references; must be deleted in Release().
2059 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002060 jobject surface_texture_;
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002061 jobject previous_surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002062
2063 // Render EGL context.
2064 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002065};
2066
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002067jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2068
2069int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2070 jobject render_egl_context) {
2071 if (render_egl_context_) {
2072 jni->DeleteGlobalRef(render_egl_context_);
2073 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002074 if (IsNull(jni, render_egl_context)) {
2075 render_egl_context_ = NULL;
2076 } else {
2077 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002078 CHECK_EXCEPTION(jni) << "error calling NewGlobalRef for EGL Context.";
2079 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
2080 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
2081 ALOGE("Wrong EGL Context.");
2082 jni->DeleteGlobalRef(render_egl_context_);
2083 render_egl_context_ = NULL;
2084 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002085 }
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002086 if (render_egl_context_ == NULL) {
2087 ALOGD("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
2088 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002089 return 0;
2090}
2091
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002092MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
2093 : key_frame_required_(true),
2094 inited_(false),
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002095 error_count_(0),
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002096 surface_texture_(NULL),
2097 previous_surface_texture_(NULL),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002098 codec_thread_(new Thread()),
2099 j_media_codec_video_decoder_class_(
2100 jni,
2101 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2102 j_media_codec_video_decoder_(
2103 jni,
2104 jni->NewObject(*j_media_codec_video_decoder_class_,
2105 GetMethodID(jni,
2106 *j_media_codec_video_decoder_class_,
2107 "<init>",
2108 "()V"))) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002109 ScopedLocalRefFrame local_ref_frame(jni);
2110 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002111 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002112
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002113 j_init_decode_method_ = GetMethodID(
2114 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002115 "(IIZZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002116 j_release_method_ =
2117 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2118 j_dequeue_input_buffer_method_ = GetMethodID(
2119 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2120 j_queue_input_buffer_method_ = GetMethodID(
2121 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2122 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002123 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2124 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002125 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002126 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002127
2128 j_input_buffers_field_ = GetFieldID(
2129 jni, *j_media_codec_video_decoder_class_,
2130 "inputBuffers", "[Ljava/nio/ByteBuffer;");
2131 j_output_buffers_field_ = GetFieldID(
2132 jni, *j_media_codec_video_decoder_class_,
2133 "outputBuffers", "[Ljava/nio/ByteBuffer;");
2134 j_color_format_field_ = GetFieldID(
2135 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2136 j_width_field_ = GetFieldID(
2137 jni, *j_media_codec_video_decoder_class_, "width", "I");
2138 j_height_field_ = GetFieldID(
2139 jni, *j_media_codec_video_decoder_class_, "height", "I");
2140 j_stride_field_ = GetFieldID(
2141 jni, *j_media_codec_video_decoder_class_, "stride", "I");
2142 j_slice_height_field_ = GetFieldID(
2143 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002144 j_textureID_field_ = GetFieldID(
2145 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2146 j_surface_texture_field_ = GetFieldID(
2147 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2148 "Landroid/graphics/SurfaceTexture;");
2149
2150 jclass j_decoder_output_buffer_info_class = FindClass(jni,
2151 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2152 j_info_index_field_ = GetFieldID(
2153 jni, j_decoder_output_buffer_info_class, "index", "I");
2154 j_info_offset_field_ = GetFieldID(
2155 jni, j_decoder_output_buffer_info_class, "offset", "I");
2156 j_info_size_field_ = GetFieldID(
2157 jni, j_decoder_output_buffer_info_class, "size", "I");
2158 j_info_presentation_timestamp_us_field_ = GetFieldID(
2159 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002160
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002161 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002162 use_surface_ = true;
2163 if (render_egl_context_ == NULL)
2164 use_surface_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002165 memset(&codec_, 0, sizeof(codec_));
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00002166 AllowBlockingCalls();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002167}
2168
2169MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002170 // Call Release() to ensure no more callbacks to us after we are deleted.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002171 Release();
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002172 // Delete global references.
2173 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2174 if (previous_surface_texture_ != NULL)
2175 jni->DeleteGlobalRef(previous_surface_texture_);
2176 if (surface_texture_ != NULL)
2177 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002178}
2179
2180int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2181 int32_t numberOfCores) {
2182 if (inst == NULL) {
2183 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2184 }
2185 int ret_val = Release();
2186 if (ret_val < 0) {
2187 return ret_val;
2188 }
2189 // Save VideoCodec instance for later.
2190 if (&codec_ != inst) {
2191 codec_ = *inst;
2192 }
2193 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2194
2195 // Always start with a complete key frame.
2196 key_frame_required_ = true;
2197 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002198 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002199
2200 // Call Java init.
2201 return codec_thread_->Invoke<int32_t>(
2202 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2203}
2204
2205int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2206 CheckOnCodecThread();
2207 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2208 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002209 ALOGD("InitDecodeOnCodecThread: %d x %d. Fps: %d. Errors: %d",
2210 codec_.width, codec_.height, codec_.maxFramerate, error_count_);
2211 bool use_sw_codec = false;
2212 if (error_count_ > 1) {
2213 // If more than one critical errors happen for HW codec, switch to SW codec.
2214 use_sw_codec = true;
2215 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002216
2217 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2218 j_init_decode_method_,
2219 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002220 codec_.height,
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002221 use_sw_codec,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002222 use_surface_,
2223 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002224 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002225 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002226 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002227 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002228 inited_ = true;
2229
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002230 max_pending_frames_ = 0;
2231 if (use_surface_) {
2232 max_pending_frames_ = 1;
2233 }
2234 start_time_ms_ = GetCurrentTimeMs();
2235 current_frames_ = 0;
2236 current_bytes_ = 0;
2237 current_decoding_time_ms_ = 0;
2238 timestamps_.clear();
2239 ntp_times_ms_.clear();
2240 frame_rtc_times_ms_.clear();
2241
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002242 jobjectArray input_buffers = (jobjectArray)GetObjectField(
2243 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2244 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002245 input_buffers_.resize(num_input_buffers);
2246 for (size_t i = 0; i < num_input_buffers; ++i) {
2247 input_buffers_[i] =
2248 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002249 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002250 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002251
2252 if (use_surface_) {
2253 jobject surface_texture = GetObjectField(
2254 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002255 if (previous_surface_texture_ != NULL) {
2256 jni->DeleteGlobalRef(previous_surface_texture_);
2257 }
2258 previous_surface_texture_ = surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002259 surface_texture_ = jni->NewGlobalRef(surface_texture);
2260 }
2261 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2262
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002263 return WEBRTC_VIDEO_CODEC_OK;
2264}
2265
2266int32_t MediaCodecVideoDecoder::Release() {
2267 return codec_thread_->Invoke<int32_t>(
2268 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2269}
2270
2271int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002272 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002273 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002274 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002275 CheckOnCodecThread();
2276 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2277 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2278 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002279 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002280 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002281 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002282 input_buffers_.clear();
2283 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002284 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002285 rtc::MessageQueueManager::Clear(this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002286 inited_ = false;
2287 return WEBRTC_VIDEO_CODEC_OK;
2288}
2289
2290
2291void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002292 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2293 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002294}
2295
2296int32_t MediaCodecVideoDecoder::Decode(
2297 const EncodedImage& inputImage,
2298 bool missingFrames,
2299 const RTPFragmentationHeader* fragmentation,
2300 const CodecSpecificInfo* codecSpecificInfo,
2301 int64_t renderTimeMs) {
2302 if (!inited_) {
2303 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2304 }
2305 if (callback_ == NULL) {
2306 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2307 }
2308 if (inputImage._buffer == NULL && inputImage._length > 0) {
2309 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2310 }
2311 // Check if encoded frame dimension has changed.
2312 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2313 (inputImage._encodedWidth != codec_.width ||
2314 inputImage._encodedHeight != codec_.height)) {
2315 codec_.width = inputImage._encodedWidth;
2316 codec_.height = inputImage._encodedHeight;
2317 InitDecode(&codec_, 1);
2318 }
2319
2320 // Always start with a complete key frame.
2321 if (key_frame_required_) {
2322 if (inputImage._frameType != webrtc::kKeyFrame) {
2323 return WEBRTC_VIDEO_CODEC_ERROR;
2324 }
2325 if (!inputImage._completeFrame) {
2326 return WEBRTC_VIDEO_CODEC_ERROR;
2327 }
2328 key_frame_required_ = false;
2329 }
2330 if (inputImage._length == 0) {
2331 return WEBRTC_VIDEO_CODEC_ERROR;
2332 }
2333
2334 return codec_thread_->Invoke<int32_t>(Bind(
2335 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2336}
2337
2338int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2339 const EncodedImage& inputImage) {
2340 static uint8_t yVal_ = 0x7f;
2341
2342 CheckOnCodecThread();
2343 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2344 ScopedLocalRefFrame local_ref_frame(jni);
2345
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002346 // Try to drain the decoder and wait until output is not too
2347 // much behind the input.
2348 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2349 ALOGV("Wait for output...");
2350 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002351 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002352 Reset();
2353 return WEBRTC_VIDEO_CODEC_ERROR;
2354 }
2355 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2356 ALOGE("Output buffer dequeue timeout");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002357 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002358 Reset();
2359 return WEBRTC_VIDEO_CODEC_ERROR;
2360 }
2361 }
2362
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002363 // Get input buffer.
2364 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2365 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002366 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002367 if (j_input_buffer_index < 0) {
2368 ALOGE("dequeueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002369 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002370 Reset();
2371 return WEBRTC_VIDEO_CODEC_ERROR;
2372 }
2373
2374 // Copy encoded data to Java ByteBuffer.
2375 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2376 uint8* buffer =
2377 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002378 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002379 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002380 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002381 if (buffer_capacity < inputImage._length) {
2382 ALOGE("Input frame size %d is bigger than buffer size %d.",
2383 inputImage._length, buffer_capacity);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002384 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002385 Reset();
2386 return WEBRTC_VIDEO_CODEC_ERROR;
2387 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002388 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002389 frames_received_, j_input_buffer_index, inputImage._length);
2390 memcpy(buffer, inputImage._buffer, inputImage._length);
2391
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002392 // Save input image timestamps for later output.
2393 frames_received_++;
2394 current_bytes_ += inputImage._length;
2395 timestamps_.push_back(inputImage._timeStamp);
2396 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2397 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2398
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002399 // Feed input to decoder.
2400 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2401 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2402 j_queue_input_buffer_method_,
2403 j_input_buffer_index,
2404 inputImage._length,
2405 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002406 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002407 if (!success) {
2408 ALOGE("queueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002409 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002410 Reset();
2411 return WEBRTC_VIDEO_CODEC_ERROR;
2412 }
2413
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002414 // Try to drain the decoder
2415 if (!DeliverPendingOutputs(jni, 0)) {
2416 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002417 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002418 Reset();
2419 return WEBRTC_VIDEO_CODEC_ERROR;
2420 }
2421
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002422 return WEBRTC_VIDEO_CODEC_OK;
2423}
2424
2425bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2426 JNIEnv* jni, int dequeue_timeout_us) {
2427 if (frames_received_ <= frames_decoded_) {
2428 // No need to query for output buffers - decoder is drained.
2429 return true;
2430 }
2431 // Get decoder output.
2432 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2433 *j_media_codec_video_decoder_,
2434 j_dequeue_output_buffer_method_,
2435 dequeue_timeout_us);
2436
2437 CHECK_EXCEPTION(jni);
2438 if (IsNull(jni, j_decoder_output_buffer_info)) {
2439 return true;
2440 }
2441
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002442 // Extract output buffer info from Java DecoderOutputBufferInfo.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002443 int output_buffer_index =
2444 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2445 if (output_buffer_index < 0) {
2446 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002447 return false;
2448 }
2449 int output_buffer_offset =
2450 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2451 int output_buffer_size =
2452 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2453 CHECK_EXCEPTION(jni);
2454
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002455 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002456 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2457 j_color_format_field_);
2458 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2459 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2460 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2461 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2462 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002463 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2464 j_textureID_field_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002465
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002466 // Extract data from Java ByteBuffer and create output yuv420 frame -
2467 // for non surface decoding only.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002468 if (!use_surface_) {
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002469 if (output_buffer_size < width * height * 3 / 2) {
2470 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002471 return false;
2472 }
2473 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2474 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2475 jobject output_buffer =
2476 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
2477 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
2478 output_buffer));
2479 CHECK_EXCEPTION(jni);
2480 payload += output_buffer_offset;
2481
2482 // Create yuv420 frame.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002483 if (color_format == COLOR_FormatYUV420Planar) {
2484 decoded_image_.CreateFrame(
2485 stride * slice_height, payload,
2486 (stride * slice_height) / 4, payload + (stride * slice_height),
2487 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2488 width, height,
2489 stride, stride / 2, stride / 2);
2490 } else {
2491 // All other supported formats are nv12.
2492 decoded_image_.CreateEmptyFrame(width, height, width,
2493 width / 2, width / 2);
2494 libyuv::NV12ToI420(
2495 payload, stride,
2496 payload + stride * slice_height, stride,
2497 decoded_image_.buffer(webrtc::kYPlane),
2498 decoded_image_.stride(webrtc::kYPlane),
2499 decoded_image_.buffer(webrtc::kUPlane),
2500 decoded_image_.stride(webrtc::kUPlane),
2501 decoded_image_.buffer(webrtc::kVPlane),
2502 decoded_image_.stride(webrtc::kVPlane),
2503 width, height);
2504 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002505 }
2506
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002507 // Get frame timestamps from a queue.
2508 int32_t timestamp = timestamps_.front();
2509 timestamps_.erase(timestamps_.begin());
2510 int64_t ntp_time_ms = ntp_times_ms_.front();
2511 ntp_times_ms_.erase(ntp_times_ms_.begin());
2512 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2513 frame_rtc_times_ms_.front();
2514 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2515
2516 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2517 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2518 color_format, output_buffer_size, frame_decoding_time_ms);
2519
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002520 // Return output buffer back to codec.
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002521 bool success = jni->CallBooleanMethod(
2522 *j_media_codec_video_decoder_,
2523 j_release_output_buffer_method_,
2524 output_buffer_index,
2525 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002526 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002527 if (!success) {
2528 ALOGE("releaseOutputBuffer error");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002529 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002530 }
2531
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002532 // Calculate and print decoding statistics - every 3 seconds.
2533 frames_decoded_++;
2534 current_frames_++;
2535 current_decoding_time_ms_ += frame_decoding_time_ms;
2536 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2537 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2538 current_frames_ > 0) {
2539 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2540 current_bytes_ * 8 / statistic_time_ms,
2541 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2542 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2543 start_time_ms_ = GetCurrentTimeMs();
2544 current_frames_ = 0;
2545 current_bytes_= 0;
2546 current_decoding_time_ms_ = 0;
2547 }
2548
2549 // Callback - output decoded frame.
2550 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2551 if (use_surface_) {
2552 native_handle_.SetTextureObject(surface_texture_, texture_id);
2553 TextureVideoFrame texture_image(
2554 &native_handle_, width, height, timestamp, 0);
2555 texture_image.set_ntp_time_ms(ntp_time_ms);
2556 callback_status = callback_->Decoded(texture_image);
2557 } else {
2558 decoded_image_.set_timestamp(timestamp);
2559 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2560 callback_status = callback_->Decoded(decoded_image_);
2561 }
2562 if (callback_status > 0) {
2563 ALOGE("callback error");
2564 }
2565
2566 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002567}
2568
2569int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2570 DecodedImageCallback* callback) {
2571 callback_ = callback;
2572 return WEBRTC_VIDEO_CODEC_OK;
2573}
2574
2575int32_t MediaCodecVideoDecoder::Reset() {
2576 ALOGD("DecoderReset");
2577 if (!inited_) {
2578 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2579 }
2580 return InitDecode(&codec_, 1);
2581}
2582
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002583void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002584 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2585 ScopedLocalRefFrame local_ref_frame(jni);
2586 if (!inited_) {
2587 return;
2588 }
2589 // We only ever send one message to |this| directly (not through a Bind()'d
2590 // functor), so expect no ID/data.
2591 CHECK(!msg->message_id) << "Unexpected message!";
2592 CHECK(!msg->pdata) << "Unexpected message!";
2593 CheckOnCodecThread();
2594
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002595 if (!DeliverPendingOutputs(jni, 0)) {
2596 error_count_++;
2597 Reset();
2598 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002599 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002600}
2601
2602class MediaCodecVideoDecoderFactory
2603 : public cricket::WebRtcVideoDecoderFactory {
2604 public:
2605 MediaCodecVideoDecoderFactory();
2606 virtual ~MediaCodecVideoDecoderFactory();
2607 // WebRtcVideoDecoderFactory implementation.
2608 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2609 webrtc::VideoCodecType type) OVERRIDE;
2610
2611 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2612
2613 private:
2614 bool is_platform_supported_;
2615};
2616
2617MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2618 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2619 ScopedLocalRefFrame local_ref_frame(jni);
2620 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2621 is_platform_supported_ = jni->CallStaticBooleanMethod(
2622 j_decoder_class,
2623 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002624 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002625}
2626
2627MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2628
2629webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2630 webrtc::VideoCodecType type) {
2631 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2632 return NULL;
2633 }
2634 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2635}
2636
2637
2638void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2639 webrtc::VideoDecoder* decoder) {
2640 delete decoder;
2641}
2642
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002643#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002644
2645} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002646
2647// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2648// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2649#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2650 Java_org_webrtc_##name
2651
2652extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002653 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002654 g_jvm = jvm;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002655 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002656
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002657 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002658
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002659 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002660
2661 JNIEnv* jni;
2662 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2663 return -1;
2664 g_class_reference_holder = new ClassReferenceHolder(jni);
2665
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002666 return JNI_VERSION_1_6;
2667}
2668
2669extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002670 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002671 delete g_class_reference_holder;
2672 g_class_reference_holder = NULL;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002673 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002674 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002675}
2676
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002677static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002678 jfieldID native_dc_id = GetFieldID(jni,
2679 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2680 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002681 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002682}
2683
2684JOW(jlong, DataChannel_registerObserverNative)(
2685 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002686 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002687 new DataChannelObserverWrapper(jni, j_observer));
2688 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002689 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002690}
2691
2692JOW(void, DataChannel_unregisterObserverNative)(
2693 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2694 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2695 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2696}
2697
2698JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2699 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2700}
2701
2702JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2703 return JavaEnumFromIndex(
2704 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2705}
2706
2707JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2708 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002709 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2710 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002711 return static_cast<jlong>(buffered_amount);
2712}
2713
2714JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2715 ExtractNativeDC(jni, j_dc)->Close();
2716}
2717
2718JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2719 jbyteArray data, jboolean binary) {
2720 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2721 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002722 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002723 binary));
2724 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2725 return ret;
2726}
2727
2728JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002729 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002730}
2731
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002732JOW(void, Logging_nativeEnableTracing)(
2733 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2734 jint nativeSeverity) {
2735 std::string path = JavaToStdString(jni, j_path);
2736 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002737 webrtc::Trace::set_level_filter(nativeLevels);
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002738#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002739 if (path != "logcat:") {
2740#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002741 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2742 << "SetTraceFile failed";
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002743#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002744 } else {
2745 // Intentionally leak this to avoid needing to reason about its lifecycle.
2746 // It keeps no state and functions only as a dispatch point.
2747 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2748 }
2749#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002750 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002751 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002752}
2753
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002754JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002755 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002756}
2757
2758JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2759 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2760 delete p;
2761}
2762
2763JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002764 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765}
2766
2767JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2768 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2769}
2770
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002771JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002772 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2773}
2774
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002775JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2776 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2777}
2778
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002779JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002780 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002781}
2782
2783JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2784 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002785 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002786 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002787}
2788
2789JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2790 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002791 return reinterpret_cast<MediaStreamInterface*>(pointer)
2792 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793}
2794
2795JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2796 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002797 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002798 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002799}
2800
2801JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2802 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002803 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002804 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002805}
2806
2807JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2808 return JavaStringFromStdString(
2809 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2810}
2811
2812JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002813 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002814}
2815
2816JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2817 JNIEnv * jni, jclass, jobject j_observer) {
2818 return (jlong)new PCOJava(jni, j_observer);
2819}
2820
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002821#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002822JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002823 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002824 jboolean initialize_audio, jboolean initialize_video,
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002825 jboolean vp8_hw_acceleration, jobject render_egl_context) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002826 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002827 bool failure = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002828 vp8_hw_acceleration_enabled = vp8_hw_acceleration;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002829 if (!factory_static_initialized) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002830 if (initialize_video) {
2831 failure |= webrtc::SetCaptureAndroidVM(g_jvm, context);
2832 failure |= webrtc::SetRenderAndroidVM(g_jvm);
2833 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002834 if (initialize_audio)
2835 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2836 factory_static_initialized = true;
2837 }
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002838 if (initialize_video)
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002839 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2840 render_egl_context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002841 return !failure;
2842}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002843#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002844
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +00002845JOW(void, PeerConnectionFactory_initializeFieldTrials)(
2846 JNIEnv* jni, jclass, jstring j_trials_init_string) {
2847 field_trials_init_string = NULL;
2848 if (j_trials_init_string != NULL) {
2849 const char* init_string =
2850 jni->GetStringUTFChars(j_trials_init_string, NULL);
2851 int init_string_length = jni->GetStringUTFLength(j_trials_init_string);
2852 field_trials_init_string = new char[init_string_length + 1];
2853 rtc::strcpyn(field_trials_init_string, init_string_length + 1, init_string);
2854 jni->ReleaseStringUTFChars(j_trials_init_string, init_string);
2855 LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string ;
2856 }
2857 webrtc::field_trial::InitFieldTrialsFromString(field_trials_init_string);
2858}
2859
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002860// Helper struct for working around the fact that CreatePeerConnectionFactory()
2861// comes in two flavors: either entirely automagical (constructing its own
2862// threads and deleting them on teardown, but no external codec factory support)
2863// or entirely manual (requires caller to delete threads after factory
2864// teardown). This struct takes ownership of its ctor's arguments to present a
2865// single thing for Java to hold and eventually free.
2866class OwnedFactoryAndThreads {
2867 public:
2868 OwnedFactoryAndThreads(Thread* worker_thread,
2869 Thread* signaling_thread,
2870 PeerConnectionFactoryInterface* factory)
2871 : worker_thread_(worker_thread),
2872 signaling_thread_(signaling_thread),
2873 factory_(factory) {}
2874
2875 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2876
2877 PeerConnectionFactoryInterface* factory() { return factory_; }
2878
2879 private:
2880 const scoped_ptr<Thread> worker_thread_;
2881 const scoped_ptr<Thread> signaling_thread_;
2882 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2883};
2884
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002885JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2886 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002887 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2888 // ThreadManager only WrapCurrentThread()s the thread where it is first
2889 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002890 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002891 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002892 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002893 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002894 Thread* worker_thread = new Thread();
2895 worker_thread->SetName("worker_thread", NULL);
2896 Thread* signaling_thread = new Thread();
2897 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002898 CHECK(worker_thread->Start() && signaling_thread->Start())
2899 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002900 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002901 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002902#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002903 if (vp8_hw_acceleration_enabled) {
2904 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
2905 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
2906 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002907#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002908 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002909 webrtc::CreatePeerConnectionFactory(worker_thread,
2910 signaling_thread,
2911 NULL,
2912 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002913 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002914 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2915 worker_thread, signaling_thread, factory.release());
2916 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002917}
2918
2919JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002920 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +00002921 if (field_trials_init_string) {
2922 webrtc::field_trial::InitFieldTrialsFromString(NULL);
2923 delete field_trials_init_string;
2924 field_trials_init_string = NULL;
2925 }
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002926 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002927}
2928
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002929static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2930 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2931}
2932
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002933JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2934 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002935 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002936 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002937 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002938 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2939 return (jlong)stream.release();
2940}
2941
2942JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2943 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2944 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002945 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002946 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002947 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002948 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002949 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002950 factory->CreateVideoSource(
2951 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2952 constraints.get()));
2953 return (jlong)source.release();
2954}
2955
2956JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2957 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2958 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002959 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002960 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002961 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002962 factory->CreateVideoTrack(
2963 JavaToStdString(jni, id),
2964 reinterpret_cast<VideoSourceInterface*>(native_source)));
2965 return (jlong)track.release();
2966}
2967
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002968JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2969 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2970 scoped_ptr<ConstraintsWrapper> constraints(
2971 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002972 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002973 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002974 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002975 factory->CreateAudioSource(constraints.get()));
2976 return (jlong)source.release();
2977}
2978
2979JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2980 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2981 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002982 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002983 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002984 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002985 JavaToStdString(jni, id),
2986 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002987 return (jlong)track.release();
2988}
2989
2990static void JavaIceServersToJsepIceServers(
2991 JNIEnv* jni, jobject j_ice_servers,
2992 PeerConnectionInterface::IceServers* ice_servers) {
2993 jclass list_class = GetObjectClass(jni, j_ice_servers);
2994 jmethodID iterator_id = GetMethodID(
2995 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2996 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002997 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002998 jmethodID iterator_has_next = GetMethodID(
2999 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
3000 jmethodID iterator_next = GetMethodID(
3001 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
3002 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003003 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003004 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003005 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003006 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
3007 jfieldID j_ice_server_uri_id =
3008 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
3009 jfieldID j_ice_server_username_id =
3010 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
3011 jfieldID j_ice_server_password_id =
3012 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
3013 jstring uri = reinterpret_cast<jstring>(
3014 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
3015 jstring username = reinterpret_cast<jstring>(
3016 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
3017 jstring password = reinterpret_cast<jstring>(
3018 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
3019 PeerConnectionInterface::IceServer server;
3020 server.uri = JavaToStdString(jni, uri);
3021 server.username = JavaToStdString(jni, username);
3022 server.password = JavaToStdString(jni, password);
3023 ice_servers->push_back(server);
3024 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003025 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003026}
3027
3028JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
3029 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
3030 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003031 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003032 reinterpret_cast<PeerConnectionFactoryInterface*>(
3033 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003034 PeerConnectionInterface::IceServers servers;
3035 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
3036 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
3037 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003038 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00003039 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003040 return (jlong)pc.release();
3041}
3042
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003043static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003044 JNIEnv* jni, jobject j_pc) {
3045 jfieldID native_pc_id = GetFieldID(jni,
3046 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
3047 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003048 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003049 reinterpret_cast<PeerConnectionInterface*>(j_p));
3050}
3051
3052JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
3053 const SessionDescriptionInterface* sdp =
3054 ExtractNativePC(jni, j_pc)->local_description();
3055 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3056}
3057
3058JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
3059 const SessionDescriptionInterface* sdp =
3060 ExtractNativePC(jni, j_pc)->remote_description();
3061 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3062}
3063
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003064JOW(jobject, PeerConnection_createDataChannel)(
3065 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
3066 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003067 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003068 ExtractNativePC(jni, j_pc)->CreateDataChannel(
3069 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00003070 // Mustn't pass channel.get() directly through NewObject to avoid reading its
3071 // vararg parameter as 64-bit and reading memory that doesn't belong to the
3072 // 32-bit parameter.
3073 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003074 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003075 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
3076 jmethodID j_data_channel_ctor = GetMethodID(
3077 jni, j_data_channel_class, "<init>", "(J)V");
3078 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00003079 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003080 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003081 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003082 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003083 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003084 return j_channel;
3085}
3086
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003087JOW(void, PeerConnection_createOffer)(
3088 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3089 ConstraintsWrapper* constraints =
3090 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003091 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3092 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003093 jni, j_observer, constraints));
3094 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3095}
3096
3097JOW(void, PeerConnection_createAnswer)(
3098 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3099 ConstraintsWrapper* constraints =
3100 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003101 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3102 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003103 jni, j_observer, constraints));
3104 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3105}
3106
3107// Helper to create a SessionDescriptionInterface from a SessionDescription.
3108static SessionDescriptionInterface* JavaSdpToNativeSdp(
3109 JNIEnv* jni, jobject j_sdp) {
3110 jfieldID j_type_id = GetFieldID(
3111 jni, GetObjectClass(jni, j_sdp), "type",
3112 "Lorg/webrtc/SessionDescription$Type;");
3113 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3114 jmethodID j_canonical_form_id = GetMethodID(
3115 jni, GetObjectClass(jni, j_type), "canonicalForm",
3116 "()Ljava/lang/String;");
3117 jstring j_type_string = (jstring)jni->CallObjectMethod(
3118 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003119 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003120 std::string std_type = JavaToStdString(jni, j_type_string);
3121
3122 jfieldID j_description_id = GetFieldID(
3123 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3124 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3125 std::string std_description = JavaToStdString(jni, j_description);
3126
3127 return webrtc::CreateSessionDescription(
3128 std_type, std_description, NULL);
3129}
3130
3131JOW(void, PeerConnection_setLocalDescription)(
3132 JNIEnv* jni, jobject j_pc,
3133 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003134 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3135 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003136 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3137 ExtractNativePC(jni, j_pc)->SetLocalDescription(
3138 observer, JavaSdpToNativeSdp(jni, j_sdp));
3139}
3140
3141JOW(void, PeerConnection_setRemoteDescription)(
3142 JNIEnv* jni, jobject j_pc,
3143 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003144 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3145 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003146 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3147 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3148 observer, JavaSdpToNativeSdp(jni, j_sdp));
3149}
3150
3151JOW(jboolean, PeerConnection_updateIce)(
3152 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3153 PeerConnectionInterface::IceServers ice_servers;
3154 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003155 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003156 new ConstraintsWrapper(jni, j_constraints));
3157 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3158}
3159
3160JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3161 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3162 jint j_sdp_mline_index, jstring j_candidate_sdp) {
3163 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3164 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003165 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003166 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3167 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3168}
3169
3170JOW(jboolean, PeerConnection_nativeAddLocalStream)(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003171 JNIEnv* jni, jobject j_pc, jlong native_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003172 return ExtractNativePC(jni, j_pc)->AddStream(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003173 reinterpret_cast<MediaStreamInterface*>(native_stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003174}
3175
3176JOW(void, PeerConnection_nativeRemoveLocalStream)(
3177 JNIEnv* jni, jobject j_pc, jlong native_stream) {
3178 ExtractNativePC(jni, j_pc)->RemoveStream(
3179 reinterpret_cast<MediaStreamInterface*>(native_stream));
3180}
3181
3182JOW(bool, PeerConnection_nativeGetStats)(
3183 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003184 rtc::scoped_refptr<StatsObserverWrapper> observer(
3185 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003186 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00003187 observer,
3188 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3189 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003190}
3191
3192JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3193 PeerConnectionInterface::SignalingState state =
3194 ExtractNativePC(jni, j_pc)->signaling_state();
3195 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3196}
3197
3198JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3199 PeerConnectionInterface::IceConnectionState state =
3200 ExtractNativePC(jni, j_pc)->ice_connection_state();
3201 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3202}
3203
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00003204JOW(jobject, PeerConnection_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003205 PeerConnectionInterface::IceGatheringState state =
3206 ExtractNativePC(jni, j_pc)->ice_gathering_state();
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00003207 return JavaEnumFromIndex(jni, "PeerConnection$IceGatheringState", state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003208}
3209
3210JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3211 ExtractNativePC(jni, j_pc)->Close();
3212 return;
3213}
3214
3215JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003216 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003217 reinterpret_cast<MediaSourceInterface*>(j_p));
3218 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3219}
3220
3221JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
3222 JNIEnv* jni, jclass, jstring j_device_name) {
3223 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003224 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003225 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003226 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003227 cricket::Device device;
3228 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003229 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003230 return 0;
3231 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003232 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003233 device_manager->CreateVideoCapturer(device));
3234 return (jlong)capturer.release();
3235}
3236
3237JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3238 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003239 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3240 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003241 return (jlong)renderer.release();
3242}
3243
3244JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3245 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003246 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003247 new JavaVideoRendererWrapper(jni, j_callbacks));
3248 return (jlong)renderer.release();
3249}
3250
glaznev@webrtc.orgf6932292015-02-05 17:29:59 +00003251JOW(void, VideoRenderer_nativeCopyPlane)(
3252 JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height,
3253 jint src_stride, jobject j_dst_buffer, jint dst_stride) {
3254 size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer);
3255 size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer);
3256 CHECK(src_stride >= width) << "Wrong source stride " << src_stride;
3257 CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride;
3258 CHECK(src_size >= src_stride * height)
3259 << "Insufficient source buffer capacity " << src_size;
3260 CHECK(dst_size >= dst_stride * height)
3261 << "Isufficient destination buffer capacity " << dst_size;
3262 uint8_t *src =
3263 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
3264 uint8_t *dst =
3265 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_buffer));
3266 if (src_stride == dst_stride) {
3267 memcpy(dst, src, src_stride * height);
3268 } else {
3269 for (int i = 0; i < height; i++) {
3270 memcpy(dst, src, width);
3271 src += src_stride;
3272 dst += dst_stride;
3273 }
3274 }
3275}
3276
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003277JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3278 cricket::VideoCapturer* capturer =
3279 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003280 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003281 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3282 capturer->Stop();
3283 return jlongFromPointer(format.release());
3284}
3285
3286JOW(void, VideoSource_restart)(
3287 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003288 CHECK(j_p_source);
3289 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003290 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003291 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3292 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3293 StartCapturing(cricket::VideoFormat(*format));
3294}
3295
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00003296JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003297 JNIEnv* jni, jclass, jlong j_p) {
3298 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3299}
3300
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003301JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003302 return JavaStringFromStdString(
3303 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003304}
3305
3306JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003307 return JavaStringFromStdString(
3308 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003309}
3310
3311JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003312 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003313}
3314
3315JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003316 return JavaEnumFromIndex(
3317 jni,
3318 "MediaStreamTrack$State",
3319 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003320}
3321
3322JOW(jboolean, MediaStreamTrack_nativeSetState)(
3323 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003324 MediaStreamTrackInterface::TrackState new_state =
3325 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003326 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3327 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003328}
3329
3330JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3331 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003332 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3333 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003334}
3335
3336JOW(void, VideoTrack_nativeAddRenderer)(
3337 JNIEnv* jni, jclass,
3338 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003339 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003340 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3341}
3342
3343JOW(void, VideoTrack_nativeRemoveRenderer)(
3344 JNIEnv* jni, jclass,
3345 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003346 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003347 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3348}