blob: 9c8d7088deb6b0ff0b8f518c1c79701ead9cdb2a [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>
perkj@webrtc.org83bc7212015-02-11 11:26:56 +000094#include "talk/app/webrtc/androidvideocapturer.h"
andresp@webrtc.org85ef7702014-09-17 11:44:51 +000095#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");
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000282 LoadClass(jni, "org/webrtc/VideoCapturerAndroid");
283 LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeFrameObserver");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000284 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
285 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000286 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000287 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
glaznev@webrtc.orga8c0edd2014-10-20 19:08:05 +0000288 jclass j_decoder_class = GetClass("org/webrtc/MediaCodecVideoDecoder");
289 jmethodID j_is_egl14_supported_method = jni->GetStaticMethodID(
290 j_decoder_class, "isEGL14Supported", "()Z");
291 bool is_egl14_supported = jni->CallStaticBooleanMethod(
292 j_decoder_class, j_is_egl14_supported_method);
293 CHECK_EXCEPTION(jni);
294 if (is_egl14_supported) {
295 LoadClass(jni, "android/opengl/EGLContext");
296 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000297#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298 LoadClass(jni, "org/webrtc/MediaSource$State");
299 LoadClass(jni, "org/webrtc/MediaStream");
300 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
302 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000303 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000304 LoadClass(jni, "org/webrtc/SessionDescription");
305 LoadClass(jni, "org/webrtc/SessionDescription$Type");
306 LoadClass(jni, "org/webrtc/StatsReport");
307 LoadClass(jni, "org/webrtc/StatsReport$Value");
308 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000309 LoadClass(jni, "org/webrtc/VideoCapturer");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000310 LoadClass(jni, "org/webrtc/VideoTrack");
311 }
312
313 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000314 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000315 }
316
317 void FreeReferences(JNIEnv* jni) {
318 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
319 it != classes_.end(); ++it) {
320 jni->DeleteGlobalRef(it->second);
321 }
322 classes_.clear();
323 }
324
325 jclass GetClass(const std::string& name) {
326 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000327 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000328 return it->second;
329 }
330
331 private:
332 void LoadClass(JNIEnv* jni, const std::string& name) {
333 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000334 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
335 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000337 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
338 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000339 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000340 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000341 }
342
343 std::map<std::string, jclass> classes_;
344};
345
346// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
347static ClassReferenceHolder* g_class_reference_holder = NULL;
348
349// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
350// object/class/method/field is non-null.
351jmethodID GetMethodID(
352 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
353 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000354 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
355 << signature;
356 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 return m;
358}
359
360jmethodID GetStaticMethodID(
361 JNIEnv* jni, jclass c, const char* name, const char* signature) {
362 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000363 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
364 << signature;
365 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000366 return m;
367}
368
369jfieldID GetFieldID(
370 JNIEnv* jni, jclass c, const char* name, const char* signature) {
371 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000372 CHECK_EXCEPTION(jni) << "error during GetFieldID";
373 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000374 return f;
375}
376
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000377// Returns a global reference guaranteed to be valid for the lifetime of the
378// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000379jclass FindClass(JNIEnv* jni, const char* name) {
380 return g_class_reference_holder->GetClass(name);
381}
382
383jclass GetObjectClass(JNIEnv* jni, jobject object) {
384 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000385 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000386 CHECK(c) << "GetObjectClass returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 return c;
388}
389
390jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
391 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000392 CHECK_EXCEPTION(jni) << "error during GetObjectField";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000393 CHECK(o) << "GetObjectField returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000394 return o;
395}
396
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000397jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
398 return static_cast<jstring>(GetObjectField(jni, object, id));
399}
400
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000401jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
402 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000403 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000404 return l;
405}
406
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000407jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
408 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000409 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000410 return i;
411}
412
413bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
414 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000415 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000416 return b;
417}
418
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419jobject NewGlobalRef(JNIEnv* jni, jobject o) {
420 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000421 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
422 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423 return ret;
424}
425
426void DeleteGlobalRef(JNIEnv* jni, jobject o) {
427 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000428 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429}
430
perkj@webrtc.org83bc7212015-02-11 11:26:56 +0000431// Convenience macro defining JNI-accessible methods in the org.webrtc package.
432// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
433#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
434 Java_org_webrtc_##name
435
436extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
437 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
438 g_jvm = jvm;
439 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
440
441 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
442
443 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
444
445 JNIEnv* jni;
446 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
447 return -1;
448 g_class_reference_holder = new ClassReferenceHolder(jni);
449
450 return JNI_VERSION_1_6;
451}
452
453extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
454 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
455 delete g_class_reference_holder;
456 g_class_reference_holder = NULL;
457 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
458 g_jvm = NULL;
459}
460
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461// Given a jweak reference, allocate a (strong) local reference scoped to the
462// lifetime of this object if the weak reference is still valid, or NULL
463// otherwise.
464class WeakRef {
465 public:
466 WeakRef(JNIEnv* jni, jweak ref)
467 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000468 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000469 }
470 ~WeakRef() {
471 if (obj_) {
472 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000473 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474 }
475 }
476 jobject obj() { return obj_; }
477
478 private:
479 JNIEnv* const jni_;
480 jobject const obj_;
481};
482
fischman@webrtc.org41776152014-01-09 00:31:17 +0000483// Scope Java local references to the lifetime of this object. Use in all C++
484// callbacks (i.e. entry points that don't originate in a Java callstack
485// through a "native" method call).
486class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000488 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000489 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000491 ~ScopedLocalRefFrame() {
492 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000494
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000495 private:
496 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497};
498
499// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000500template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501class ScopedGlobalRef {
502 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000503 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000504 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 ~ScopedGlobalRef() {
506 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
507 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000508 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 return obj_;
510 }
511 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000512 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000513};
514
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000515// Java references to "null" can only be distinguished as such in C++ by
516// creating a local reference, so this helper wraps that logic.
517static bool IsNull(JNIEnv* jni, jobject obj) {
518 ScopedLocalRefFrame local_ref_frame(jni);
519 return jni->NewLocalRef(obj) == NULL;
520}
521
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000522// Return the (singleton) Java Enum object corresponding to |index|;
523// |state_class_fragment| is something like "MediaSource$State".
524jobject JavaEnumFromIndex(
525 JNIEnv* jni, const std::string& state_class_fragment, int index) {
526 std::string state_class_name = "org/webrtc/" + state_class_fragment;
527 jclass state_class = FindClass(jni, state_class_name.c_str());
528 jmethodID state_values_id = GetStaticMethodID(
529 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000530 jobjectArray state_values = static_cast<jobjectArray>(
531 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000532 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000533 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000534 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 return ret;
536}
537
538// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
539static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
540 UnicodeString ustr(UnicodeString::fromUTF8(native));
541 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000542 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 return jstr;
544}
545
546// Given a (UTF-16) jstring return a new UTF-8 native string.
547static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
548 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000549 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000551 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000553 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 std::string ret;
555 return ustr.toUTF8String(ret);
556}
557
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000558static DataChannelInit JavaDataChannelInitToNative(
559 JNIEnv* jni, jobject j_init) {
560 DataChannelInit init;
561
562 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
563 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
564 jfieldID max_retransmit_time_id =
565 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
566 jfieldID max_retransmits_id =
567 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
568 jfieldID protocol_id =
569 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
570 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
571 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
572
573 init.ordered = GetBooleanField(jni, j_init, ordered_id);
574 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
575 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
576 init.protocol = JavaToStdString(
577 jni, GetStringField(jni, j_init, protocol_id));
578 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
579 init.id = GetIntField(jni, j_init, id_id);
580
581 return init;
582}
583
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584class ConstraintsWrapper;
585
586// Adapter between the C++ PeerConnectionObserver interface and the Java
587// PeerConnection.Observer interface. Wraps an instance of the Java interface
588// and dispatches C++ callbacks to Java.
589class PCOJava : public PeerConnectionObserver {
590 public:
591 PCOJava(JNIEnv* jni, jobject j_observer)
592 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000593 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
594 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
595 j_media_stream_ctor_(GetMethodID(
596 jni, *j_media_stream_class_, "<init>", "(J)V")),
597 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000599 jni, *j_audio_track_class_, "<init>", "(J)V")),
600 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
601 j_video_track_ctor_(GetMethodID(
602 jni, *j_video_track_class_, "<init>", "(J)V")),
603 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
604 j_data_channel_ctor_(GetMethodID(
605 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 }
607
608 virtual ~PCOJava() {}
609
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000610 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000611 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000613 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
615 jmethodID ctor = GetMethodID(jni(), candidate_class,
616 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000617 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
618 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
619 jobject j_candidate = jni()->NewObject(
620 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000621 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000622 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000624 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000625 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 }
627
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000629 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000630 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000632 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000633 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000634 jobject new_state_enum =
635 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
636 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000637 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638 }
639
640 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000641 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000642 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000644 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000646 jobject new_state_enum = JavaEnumFromIndex(
647 jni(), "PeerConnection$IceConnectionState", new_state);
648 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000649 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650 }
651
652 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000653 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000654 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000656 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000658 jobject new_state_enum = JavaEnumFromIndex(
659 jni(), "PeerConnection$IceGatheringState", new_state);
660 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000661 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 }
663
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000664 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000665 ScopedLocalRefFrame local_ref_frame(jni());
666 jobject j_stream = jni()->NewObject(
667 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000668 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669
670 AudioTrackVector audio_tracks = stream->GetAudioTracks();
671 for (size_t i = 0; i < audio_tracks.size(); ++i) {
672 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000673 jstring id = JavaStringFromStdString(jni(), track->id());
674 jobject j_track = jni()->NewObject(
675 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000676 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000677 jfieldID audio_tracks_id = GetFieldID(jni(),
678 *j_media_stream_class_,
679 "audioTracks",
680 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000681 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000682 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000683 GetObjectClass(jni(), audio_tracks),
684 "add",
685 "(Ljava/lang/Object;)Z");
686 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000687 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
688 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 }
690
691 VideoTrackVector video_tracks = stream->GetVideoTracks();
692 for (size_t i = 0; i < video_tracks.size(); ++i) {
693 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000694 jstring id = JavaStringFromStdString(jni(), track->id());
695 jobject j_track = jni()->NewObject(
696 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000697 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000698 jfieldID video_tracks_id = GetFieldID(jni(),
699 *j_media_stream_class_,
700 "videoTracks",
701 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000702 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000703 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000704 GetObjectClass(jni(), video_tracks),
705 "add",
706 "(Ljava/lang/Object;)Z");
707 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000708 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
709 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000711 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000712 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000714 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
715 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000716 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000717 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718 }
719
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000720 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000721 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000723 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724
725 WeakRef s(jni(), it->second);
726 streams_.erase(it);
727 if (!s.obj())
728 return;
729
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000730 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
731 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000733 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734 }
735
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000736 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000737 ScopedLocalRefFrame local_ref_frame(jni());
738 jobject j_channel = jni()->NewObject(
739 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000740 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000741
742 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
743 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000744 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000745
746 // Channel is now owned by Java object, and will be freed from
747 // DataChannel.dispose(). Important that this be done _after_ the
748 // CallVoidMethod above as Java code might call back into native code and be
749 // surprised to see a refcount of 2.
750 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000751 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000752
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000753 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000754 }
755
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000756 virtual void OnRenegotiationNeeded() OVERRIDE {
757 ScopedLocalRefFrame local_ref_frame(jni());
758 jmethodID m =
759 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
760 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000761 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000762 }
763
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000765 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000766 constraints_.reset(constraints);
767 }
768
769 const ConstraintsWrapper* constraints() { return constraints_.get(); }
770
771 private:
772 JNIEnv* jni() {
773 return AttachCurrentThreadIfNeeded();
774 }
775
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000776 const ScopedGlobalRef<jobject> j_observer_global_;
777 const ScopedGlobalRef<jclass> j_observer_class_;
778 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000780 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000781 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000782 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000784 const ScopedGlobalRef<jclass> j_data_channel_class_;
785 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
787 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000788 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789};
790
791// Wrapper for a Java MediaConstraints object. Copies all needed data so when
792// the constructor returns the Java object is no longer needed.
793class ConstraintsWrapper : public MediaConstraintsInterface {
794 public:
795 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
796 PopulateConstraintsFromJavaPairList(
797 jni, j_constraints, "mandatory", &mandatory_);
798 PopulateConstraintsFromJavaPairList(
799 jni, j_constraints, "optional", &optional_);
800 }
801
802 virtual ~ConstraintsWrapper() {}
803
804 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000805 virtual const Constraints& GetMandatory() const OVERRIDE {
806 return mandatory_;
807 }
808
809 virtual const Constraints& GetOptional() const OVERRIDE {
810 return optional_;
811 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000812
813 private:
814 // Helper for translating a List<Pair<String, String>> to a Constraints.
815 static void PopulateConstraintsFromJavaPairList(
816 JNIEnv* jni, jobject j_constraints,
817 const char* field_name, Constraints* field) {
818 jfieldID j_id = GetFieldID(jni,
819 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
820 jobject j_list = GetObjectField(jni, j_constraints, j_id);
821 jmethodID j_iterator_id = GetMethodID(jni,
822 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
823 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000824 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825 jmethodID j_has_next = GetMethodID(jni,
826 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
827 jmethodID j_next = GetMethodID(jni,
828 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
829 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000830 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000831 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000832 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000833 jmethodID get_key = GetMethodID(jni,
834 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
835 jstring j_key = reinterpret_cast<jstring>(
836 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000837 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 jmethodID get_value = GetMethodID(jni,
839 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
840 jstring j_value = reinterpret_cast<jstring>(
841 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000842 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 field->push_back(Constraint(JavaToStdString(jni, j_key),
844 JavaToStdString(jni, j_value)));
845 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000846 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 }
848
849 Constraints mandatory_;
850 Constraints optional_;
851};
852
853static jobject JavaSdpFromNativeSdp(
854 JNIEnv* jni, const SessionDescriptionInterface* desc) {
855 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000856 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000857 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858
859 jclass j_type_class = FindClass(
860 jni, "org/webrtc/SessionDescription$Type");
861 jmethodID j_type_from_canonical = GetStaticMethodID(
862 jni, j_type_class, "fromCanonicalForm",
863 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000864 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000865 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000866 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000867 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868
869 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
870 jmethodID j_sdp_ctor = GetMethodID(
871 jni, j_sdp_class, "<init>",
872 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
873 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000874 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000875 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000876 return j_sdp;
877}
878
879template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
880class SdpObserverWrapper : public T {
881 public:
882 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
883 ConstraintsWrapper* constraints)
884 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000885 j_observer_global_(jni, j_observer),
886 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 }
888
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000889 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000890
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000891 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000893 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000894 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
895 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000896 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897 }
898
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000899 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000901 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000903 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000905 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
906 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000907 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908 }
909
910 protected:
911 // Common implementation for failure of Set & Create types, distinguished by
912 // |op| being "Set" or "Create".
913 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000914 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
915 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000916 jstring j_error_string = JavaStringFromStdString(jni(), error);
917 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000918 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000919 }
920
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000921 JNIEnv* jni() {
922 return AttachCurrentThreadIfNeeded();
923 }
924
fischman@webrtc.org41776152014-01-09 00:31:17 +0000925 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000926 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000927 const ScopedGlobalRef<jobject> j_observer_global_;
928 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000929};
930
931class CreateSdpObserverWrapper
932 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
933 public:
934 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
935 ConstraintsWrapper* constraints)
936 : SdpObserverWrapper(jni, j_observer, constraints) {}
937
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000938 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000939 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940 SdpObserverWrapper::OnFailure(std::string("Create"), error);
941 }
942};
943
944class SetSdpObserverWrapper
945 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
946 public:
947 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
948 ConstraintsWrapper* constraints)
949 : SdpObserverWrapper(jni, j_observer, constraints) {}
950
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000951 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000952 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000953 SdpObserverWrapper::OnFailure(std::string("Set"), error);
954 }
955};
956
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000957// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
958// and dispatching the callback from C++ back to Java.
959class DataChannelObserverWrapper : public DataChannelObserver {
960 public:
961 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
962 : j_observer_global_(jni, j_observer),
963 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000964 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000965 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
966 "onStateChange", "()V")),
967 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
968 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000969 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
970 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
971 }
972
973 virtual ~DataChannelObserverWrapper() {}
974
975 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000976 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000977 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000978 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000979 }
980
981 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000982 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000983 jobject byte_buffer =
984 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
985 buffer.data.length());
986 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
987 byte_buffer, buffer.binary);
988 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000989 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000990 }
991
992 private:
993 JNIEnv* jni() {
994 return AttachCurrentThreadIfNeeded();
995 }
996
997 const ScopedGlobalRef<jobject> j_observer_global_;
998 const ScopedGlobalRef<jclass> j_observer_class_;
999 const ScopedGlobalRef<jclass> j_buffer_class_;
1000 const jmethodID j_on_state_change_mid_;
1001 const jmethodID j_on_message_mid_;
1002 const jmethodID j_buffer_ctor_;
1003};
1004
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
1006// dispatching the callback from C++ back to Java.
1007class StatsObserverWrapper : public StatsObserver {
1008 public:
1009 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001010 : j_observer_global_(jni, j_observer),
1011 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
1012 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001014 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001015 "(Ljava/lang/String;Ljava/lang/String;D"
1016 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001017 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 jni, "org/webrtc/StatsReport$Value")),
1019 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001020 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001021 "(Ljava/lang/String;Ljava/lang/String;)V")) {
1022 }
1023
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001024 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001026 virtual void OnComplete(const StatsReports& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001027 ScopedLocalRefFrame local_ref_frame(jni());
1028 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001029 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
1030 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +00001031 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001032 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001033 }
1034
1035 private:
1036 jobjectArray ReportsToJava(
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001037 JNIEnv* jni, const StatsReports& reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001039 reports.size(), *j_stats_report_class_, NULL);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001040 int i = 0;
1041 for (const auto* report : reports) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001042 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001043 jstring j_id = JavaStringFromStdString(jni, report->id().ToString());
1044 jstring j_type = JavaStringFromStdString(jni, report->TypeToString());
1045 jobjectArray j_values = ValuesToJava(jni, report->values());
fischman@webrtc.org41776152014-01-09 00:31:17 +00001046 jobject j_report = jni->NewObject(*j_stats_report_class_,
1047 j_stats_report_ctor_,
1048 j_id,
1049 j_type,
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001050 report->timestamp(),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001051 j_values);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001052 jni->SetObjectArrayElement(reports_array, i++, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001053 }
1054 return reports_array;
1055 }
1056
1057 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1058 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001059 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001060 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001061 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001062 const auto& value = values[i];
tommi@webrtc.orgc57310b2014-12-12 17:41:28 +00001063 // Should we use the '.name' enum value here instead of converting the
1064 // name to a string?
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001065 jstring j_name = JavaStringFromStdString(jni, value->display_name());
1066 jstring j_value = JavaStringFromStdString(jni, value->value);
fischman@webrtc.org41776152014-01-09 00:31:17 +00001067 jobject j_element_value =
1068 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1069 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001070 }
1071 return j_values;
1072 }
1073
1074 JNIEnv* jni() {
1075 return AttachCurrentThreadIfNeeded();
1076 }
1077
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001078 const ScopedGlobalRef<jobject> j_observer_global_;
1079 const ScopedGlobalRef<jclass> j_observer_class_;
1080 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001082 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001083 const jmethodID j_value_ctor_;
1084};
1085
1086// Adapter presenting a cricket::VideoRenderer as a
1087// webrtc::VideoRendererInterface.
1088class VideoRendererWrapper : public VideoRendererInterface {
1089 public:
1090 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1091 if (renderer)
1092 return new VideoRendererWrapper(renderer);
1093 return NULL;
1094 }
1095
1096 virtual ~VideoRendererWrapper() {}
1097
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001098 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001099 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001100 const bool kNotReserved = false; // What does this param mean??
1101 renderer_->SetSize(width, height, kNotReserved);
1102 }
1103
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001104 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001105 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001106 renderer_->RenderFrame(frame);
1107 }
1108
1109 private:
1110 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1111 : renderer_(renderer) {}
1112
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001113 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001114};
1115
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001116// Wrapper for texture object in TextureVideoFrame.
1117class NativeHandleImpl : public NativeHandle {
1118 public:
1119 NativeHandleImpl() :
1120 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1121 virtual ~NativeHandleImpl() {}
1122 virtual int32_t AddRef() {
1123 return ++ref_count_;
1124 }
1125 virtual int32_t Release() {
1126 return --ref_count_;
1127 }
1128 virtual void* GetHandle() {
1129 return texture_object_;
1130 }
1131 int GetTextureId() {
1132 return texture_id_;
1133 }
1134 void SetTextureObject(void *texture_object, int texture_id) {
1135 texture_object_ = reinterpret_cast<jobject>(texture_object);
1136 texture_id_ = texture_id;
1137 }
1138 int32_t ref_count() {
1139 return ref_count_;
1140 }
1141
1142 private:
1143 int32_t ref_count_;
1144 jobject texture_object_;
1145 int32_t texture_id_;
1146};
1147
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001148// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1149// instance.
1150class JavaVideoRendererWrapper : public VideoRendererInterface {
1151 public:
1152 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001153 : j_callbacks_(jni, j_callbacks),
1154 j_set_size_id_(GetMethodID(
1155 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1156 j_render_frame_id_(GetMethodID(
1157 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1158 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1159 j_frame_class_(jni,
1160 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001161 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001162 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001163 j_texture_frame_ctor_id_(GetMethodID(
1164 jni, *j_frame_class_, "<init>",
1165 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001166 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001167 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001168 }
1169
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001170 virtual ~JavaVideoRendererWrapper() {}
1171
1172 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001173 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001174 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001175 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001176 }
1177
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001178 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001179 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001180 if (frame->GetNativeHandle() != NULL) {
1181 jobject j_frame = CricketToJavaTextureFrame(frame);
1182 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1183 CHECK_EXCEPTION(jni());
1184 } else {
1185 jobject j_frame = CricketToJavaI420Frame(frame);
1186 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1187 CHECK_EXCEPTION(jni());
1188 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189 }
1190
1191 private:
1192 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001193 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001194 jintArray strides = jni()->NewIntArray(3);
1195 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001196 strides_array[0] = frame->GetYPitch();
1197 strides_array[1] = frame->GetUPitch();
1198 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001199 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1200 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1201 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001203 frame->GetYPitch() * frame->GetHeight());
1204 jobject u_buffer = jni()->NewDirectByteBuffer(
1205 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1206 jobject v_buffer = jni()->NewDirectByteBuffer(
1207 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1208 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1209 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1210 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001211 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001212 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001213 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001214 }
1215
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001216 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1217 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1218 NativeHandleImpl* handle =
1219 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1220 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1221 int texture_id = handle->GetTextureId();
1222 return jni()->NewObject(
1223 *j_frame_class_, j_texture_frame_ctor_id_,
1224 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1225 }
1226
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227 JNIEnv* jni() {
1228 return AttachCurrentThreadIfNeeded();
1229 }
1230
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001231 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001232 jmethodID j_set_size_id_;
1233 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001234 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001235 jmethodID j_i420_frame_ctor_id_;
1236 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001237 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001238};
1239
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001240#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001241// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1242// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1243// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001245//#define TRACK_BUFFER_TIMING
1246#define TAG "MediaCodecVideo"
1247#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001248#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1249#else
1250#define ALOGV(...)
1251#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001252#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1253#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001254
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001255// Color formats supported by encoder - should mirror supportedColorList
1256// from MediaCodecVideoEncoder.java
1257enum COLOR_FORMATTYPE {
1258 COLOR_FormatYUV420Planar = 0x13,
1259 COLOR_FormatYUV420SemiPlanar = 0x15,
1260 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1261 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1262 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1263 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1264 // but requires some (16, 32?) byte alignment.
1265 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1266};
1267
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001268// Arbitrary interval to poll the codec for new outputs.
1269enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001270// Media codec maximum output buffer ready timeout.
1271enum { kMediaCodecTimeoutMs = 500 };
1272// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1273enum { kMediaCodecStatisticsIntervalMs = 3000 };
1274
1275static int64_t GetCurrentTimeMs() {
1276 return TickTime::Now().Ticks() / 1000000LL;
1277}
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001278
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001279// Allow Invoke() calls from from current thread.
1280static void AllowBlockingCalls() {
1281 Thread* current_thread = Thread::Current();
1282 if (current_thread != NULL)
1283 current_thread->SetAllowBlockingCalls(true);
1284}
1285
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001286// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1287// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1288// HW-backed video encode. This C++ class is implemented as a very thin shim,
1289// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1290// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1291// thread, currently the libjingle Worker thread.
1292class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001293 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001294 public:
1295 virtual ~MediaCodecVideoEncoder();
1296 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1297
1298 // webrtc::VideoEncoder implementation. Everything trampolines to
1299 // |codec_thread_| for execution.
1300 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1301 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001302 size_t /* max_payload_size */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001303 virtual int32_t Encode(
1304 const webrtc::I420VideoFrame& input_image,
1305 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1306 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1307 virtual int32_t RegisterEncodeCompleteCallback(
1308 webrtc::EncodedImageCallback* callback) OVERRIDE;
1309 virtual int32_t Release() OVERRIDE;
1310 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001311 int64_t /* rtt */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001312 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1313
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001314 // rtc::MessageHandler implementation.
1315 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001316
1317 private:
1318 // CHECK-fail if not running on |codec_thread_|.
1319 void CheckOnCodecThread();
1320
1321 // Release() and InitEncode() in an attempt to restore the codec to an
1322 // operable state. Necessary after all manner of OMX-layer errors.
1323 void ResetCodec();
1324
1325 // Implementation of webrtc::VideoEncoder methods above, all running on the
1326 // codec thread exclusively.
1327 //
1328 // If width==0 then this is assumed to be a re-initialization and the
1329 // previously-current values are reused instead of the passed parameters
1330 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001331 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001332 int32_t EncodeOnCodecThread(
1333 const webrtc::I420VideoFrame& input_image,
1334 const std::vector<webrtc::VideoFrameType>* frame_types);
1335 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1336 webrtc::EncodedImageCallback* callback);
1337 int32_t ReleaseOnCodecThread();
1338 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1339
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001340 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1341 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1342 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1343 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1344 jlong GetOutputBufferInfoPresentationTimestampUs(
1345 JNIEnv* jni,
1346 jobject j_output_buffer_info);
1347
1348 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1349 // true on success.
1350 bool DeliverPendingOutputs(JNIEnv* jni);
1351
1352 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1353 // |codec_thread_| synchronously.
1354 webrtc::EncodedImageCallback* callback_;
1355
1356 // State that is constant for the lifetime of this object once the ctor
1357 // returns.
1358 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1359 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1360 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1361 jmethodID j_init_encode_method_;
1362 jmethodID j_dequeue_input_buffer_method_;
1363 jmethodID j_encode_method_;
1364 jmethodID j_release_method_;
1365 jmethodID j_set_rates_method_;
1366 jmethodID j_dequeue_output_buffer_method_;
1367 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001368 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001369 jfieldID j_info_index_field_;
1370 jfieldID j_info_buffer_field_;
1371 jfieldID j_info_is_key_frame_field_;
1372 jfieldID j_info_presentation_timestamp_us_field_;
1373
1374 // State that is valid only between InitEncode() and the next Release().
1375 // Touched only on codec_thread_ so no explicit synchronization necessary.
1376 int width_; // Frame width in pixels.
1377 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001378 bool inited_;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001379 uint16_t picture_id_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001380 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001381 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001382 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001383 int64_t current_timestamp_us_; // Current frame timestamps in us.
1384 int frames_received_; // Number of frames received by encoder.
1385 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001386 int frames_resolution_update_; // Number of frames with new codec resolution.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001387 int frames_in_queue_; // Number of frames in encoder queue.
1388 int64_t start_time_ms_; // Start time for statistics.
1389 int current_frames_; // Number of frames in the current statistics interval.
1390 int current_bytes_; // Encoded bytes in the current statistics interval.
1391 int current_encoding_time_ms_; // Overall encoding time in the current second
1392 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1393 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
1394 std::vector<int32_t> timestamps_; // Video frames timestamp queue.
1395 std::vector<int64_t> render_times_ms_; // Video frames render time queue.
1396 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1397 // encoder input.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001398 // Frame size in bytes fed to MediaCodec.
1399 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001400 // True only when between a callback_->Encoded() call return a positive value
1401 // and the next Encode() call being ignored.
1402 bool drop_next_input_frame_;
1403 // Global references; must be deleted in Release().
1404 std::vector<jobject> input_buffers_;
1405};
1406
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001407MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001408 // Call Release() to ensure no more callbacks to us after we are deleted.
1409 Release();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001410}
1411
1412MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001413 : callback_(NULL),
1414 inited_(false),
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001415 picture_id_(0),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001416 codec_thread_(new Thread()),
1417 j_media_codec_video_encoder_class_(
1418 jni,
1419 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1420 j_media_codec_video_encoder_(
1421 jni,
1422 jni->NewObject(*j_media_codec_video_encoder_class_,
1423 GetMethodID(jni,
1424 *j_media_codec_video_encoder_class_,
1425 "<init>",
1426 "()V"))) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001427 ScopedLocalRefFrame local_ref_frame(jni);
1428 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1429 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1430 // 2732 means that deadlocks abound. This class synchronously trampolines
1431 // to |codec_thread_|, so if anything else can be coming to _us_ from
1432 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1433 // in the bug, we have a problem. For now work around that with a dedicated
1434 // thread.
1435 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001436 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001437
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001438 jclass j_output_buffer_info_class =
1439 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1440 j_init_encode_method_ = GetMethodID(jni,
1441 *j_media_codec_video_encoder_class_,
1442 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001443 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001444 j_dequeue_input_buffer_method_ = GetMethodID(
1445 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1446 j_encode_method_ = GetMethodID(
1447 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1448 j_release_method_ =
1449 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1450 j_set_rates_method_ = GetMethodID(
1451 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1452 j_dequeue_output_buffer_method_ =
1453 GetMethodID(jni,
1454 *j_media_codec_video_encoder_class_,
1455 "dequeueOutputBuffer",
1456 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1457 j_release_output_buffer_method_ = GetMethodID(
1458 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1459
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001460 j_color_format_field_ =
1461 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001462 j_info_index_field_ =
1463 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1464 j_info_buffer_field_ = GetFieldID(
1465 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1466 j_info_is_key_frame_field_ =
1467 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1468 j_info_presentation_timestamp_us_field_ = GetFieldID(
1469 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001470 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001471 AllowBlockingCalls();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001472}
1473
1474int32_t MediaCodecVideoEncoder::InitEncode(
1475 const webrtc::VideoCodec* codec_settings,
1476 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001477 size_t /* max_payload_size */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001478 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001479 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001480
1481 return codec_thread_->Invoke<int32_t>(
1482 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1483 this,
1484 codec_settings->width,
1485 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001486 codec_settings->startBitrate,
1487 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001488}
1489
1490int32_t MediaCodecVideoEncoder::Encode(
1491 const webrtc::I420VideoFrame& frame,
1492 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1493 const std::vector<webrtc::VideoFrameType>* frame_types) {
1494 return codec_thread_->Invoke<int32_t>(Bind(
1495 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1496}
1497
1498int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1499 webrtc::EncodedImageCallback* callback) {
1500 return codec_thread_->Invoke<int32_t>(
1501 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1502 this,
1503 callback));
1504}
1505
1506int32_t MediaCodecVideoEncoder::Release() {
1507 return codec_thread_->Invoke<int32_t>(
1508 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1509}
1510
1511int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001512 int64_t /* rtt */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001513 return WEBRTC_VIDEO_CODEC_OK;
1514}
1515
1516int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1517 uint32_t frame_rate) {
1518 return codec_thread_->Invoke<int32_t>(
1519 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1520 this,
1521 new_bit_rate,
1522 frame_rate));
1523}
1524
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001525void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001526 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1527 ScopedLocalRefFrame local_ref_frame(jni);
1528
1529 // We only ever send one message to |this| directly (not through a Bind()'d
1530 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001531 CHECK(!msg->message_id) << "Unexpected message!";
1532 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001533 CheckOnCodecThread();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001534 if (!inited_) {
1535 return;
1536 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001537
1538 // It would be nice to recover from a failure here if one happened, but it's
1539 // unclear how to signal such a failure to the app, so instead we stay silent
1540 // about it and let the next app-called API method reveal the borkedness.
1541 DeliverPendingOutputs(jni);
1542 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1543}
1544
1545void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001546 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1547 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001548}
1549
1550void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001551 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001552 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1553 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001554 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1555 width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001556 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1557 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1558 // https://code.google.com/p/webrtc/issues/detail?id=2920
1559 }
1560}
1561
1562int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001563 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001564 CheckOnCodecThread();
1565 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1566 ScopedLocalRefFrame local_ref_frame(jni);
1567
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001568 ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1569 width, height, kbps, fps);
1570 if (kbps == 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001571 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001572 }
1573 if (fps == 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001574 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001575 }
1576
1577 width_ = width;
1578 height_ = height;
1579 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001580 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001581 yuv_size_ = width_ * height_ * 3 / 2;
1582 frames_received_ = 0;
1583 frames_dropped_ = 0;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001584 frames_resolution_update_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001585 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001586 current_timestamp_us_ = 0;
1587 start_time_ms_ = GetCurrentTimeMs();
1588 current_frames_ = 0;
1589 current_bytes_ = 0;
1590 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001591 last_input_timestamp_ms_ = -1;
1592 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001593 timestamps_.clear();
1594 render_times_ms_.clear();
1595 frame_rtc_times_ms_.clear();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001596 drop_next_input_frame_ = false;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001597 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001598 // We enforce no extra stride/padding in the format creation step.
1599 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1600 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1601 j_init_encode_method_,
1602 width_,
1603 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001604 kbps,
1605 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001606 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001607 if (IsNull(jni, input_buffers))
1608 return WEBRTC_VIDEO_CODEC_ERROR;
1609
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001610 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001611 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1612 j_color_format_field_)) {
1613 case COLOR_FormatYUV420Planar:
1614 encoder_fourcc_ = libyuv::FOURCC_YU12;
1615 break;
1616 case COLOR_FormatYUV420SemiPlanar:
1617 case COLOR_QCOM_FormatYUV420SemiPlanar:
1618 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1619 encoder_fourcc_ = libyuv::FOURCC_NV12;
1620 break;
1621 default:
1622 LOG(LS_ERROR) << "Wrong color format.";
1623 return WEBRTC_VIDEO_CODEC_ERROR;
1624 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001625 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001626 CHECK(input_buffers_.empty())
1627 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001628 input_buffers_.resize(num_input_buffers);
1629 for (size_t i = 0; i < num_input_buffers; ++i) {
1630 input_buffers_[i] =
1631 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001632 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001633 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001634 CHECK_EXCEPTION(jni);
1635 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001636 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001637 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001638
1639 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1640 return WEBRTC_VIDEO_CODEC_OK;
1641}
1642
1643int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1644 const webrtc::I420VideoFrame& frame,
1645 const std::vector<webrtc::VideoFrameType>* frame_types) {
1646 CheckOnCodecThread();
1647 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1648 ScopedLocalRefFrame local_ref_frame(jni);
1649
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001650 if (!inited_) {
1651 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1652 }
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001653 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001654 if (!DeliverPendingOutputs(jni)) {
1655 ResetCodec();
1656 // Continue as if everything's fine.
1657 }
1658
1659 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001660 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001661 drop_next_input_frame_ = false;
1662 return WEBRTC_VIDEO_CODEC_OK;
1663 }
1664
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001665 CHECK(frame_types->size() == 1) << "Unexpected stream count";
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001666 if (frame.width() != width_ || frame.height() != height_) {
1667 frames_resolution_update_++;
1668 ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1669 width_, height_, frame.width(), frame.height());
1670 if (frames_resolution_update_ > 3) {
1671 // Reset codec if we received more than 3 frames with new resolution.
1672 width_ = frame.width();
1673 height_ = frame.height();
1674 frames_resolution_update_ = 0;
1675 ResetCodec();
1676 }
1677 return WEBRTC_VIDEO_CODEC_OK;
1678 }
1679 frames_resolution_update_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001680
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001681 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1682
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001683 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001684 // or the encoder latency exceeds 70 ms and drop frame if so.
1685 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001686 int encoder_latency_ms = last_input_timestamp_ms_ -
1687 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001688 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001689 ALOGD("Drop frame - encoder is behind by %d ms. Q size: %d",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001690 encoder_latency_ms, frames_in_queue_);
1691 frames_dropped_++;
1692 return WEBRTC_VIDEO_CODEC_OK;
1693 }
1694 }
1695
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001696 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1697 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001698 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001699 if (j_input_buffer_index == -1) {
1700 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001701 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001702 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001703 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001704 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001705 if (j_input_buffer_index == -2) {
1706 ResetCodec();
1707 return WEBRTC_VIDEO_CODEC_ERROR;
1708 }
1709
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001710 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001711 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001712
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001713 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001714 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001715 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001716 CHECK_EXCEPTION(jni);
1717 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001718 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001719 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1720 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1721 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1722 yuv_buffer, width_,
1723 width_, height_,
1724 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001725 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001726 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001727 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001728
1729 // Save input image timestamps for later output
1730 timestamps_.push_back(frame.timestamp());
1731 render_times_ms_.push_back(frame.render_time_ms());
1732 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1733
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001734 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1735 j_encode_method_,
1736 key_frame,
1737 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001738 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001739 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001740 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001741 current_timestamp_us_ += 1000000 / last_set_fps_;
1742
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001743 if (!encode_status || !DeliverPendingOutputs(jni)) {
1744 ResetCodec();
1745 return WEBRTC_VIDEO_CODEC_ERROR;
1746 }
1747
1748 return WEBRTC_VIDEO_CODEC_OK;
1749}
1750
1751int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1752 webrtc::EncodedImageCallback* callback) {
1753 CheckOnCodecThread();
1754 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1755 ScopedLocalRefFrame local_ref_frame(jni);
1756 callback_ = callback;
1757 return WEBRTC_VIDEO_CODEC_OK;
1758}
1759
1760int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001761 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001762 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001763 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001764 CheckOnCodecThread();
1765 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001766 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1767 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001768 ScopedLocalRefFrame local_ref_frame(jni);
1769 for (size_t i = 0; i < input_buffers_.size(); ++i)
1770 jni->DeleteGlobalRef(input_buffers_[i]);
1771 input_buffers_.clear();
1772 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001773 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001774 rtc::MessageQueueManager::Clear(this);
1775 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001776 return WEBRTC_VIDEO_CODEC_OK;
1777}
1778
1779int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1780 uint32_t frame_rate) {
1781 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001782 if (last_set_bitrate_kbps_ == new_bit_rate &&
1783 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001784 return WEBRTC_VIDEO_CODEC_OK;
1785 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001786 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1787 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001788 if (new_bit_rate > 0) {
1789 last_set_bitrate_kbps_ = new_bit_rate;
1790 }
1791 if (frame_rate > 0) {
1792 last_set_fps_ = frame_rate;
1793 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001794 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1795 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001796 last_set_bitrate_kbps_,
1797 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001798 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001799 if (!ret) {
1800 ResetCodec();
1801 return WEBRTC_VIDEO_CODEC_ERROR;
1802 }
1803 return WEBRTC_VIDEO_CODEC_OK;
1804}
1805
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001806int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1807 JNIEnv* jni,
1808 jobject j_output_buffer_info) {
1809 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1810}
1811
1812jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1813 JNIEnv* jni,
1814 jobject j_output_buffer_info) {
1815 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1816}
1817
1818bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1819 JNIEnv* jni,
1820 jobject j_output_buffer_info) {
1821 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1822}
1823
1824jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1825 JNIEnv* jni,
1826 jobject j_output_buffer_info) {
1827 return GetLongField(
1828 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1829}
1830
1831bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1832 while (true) {
1833 jobject j_output_buffer_info = jni->CallObjectMethod(
1834 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001835 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001836 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001837 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001838 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001839
1840 int output_buffer_index =
1841 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1842 if (output_buffer_index == -1) {
1843 ResetCodec();
1844 return false;
1845 }
1846
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001847 // Get frame timestamps from a queue.
1848 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001849 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1850 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001851 int32_t timestamp = timestamps_.front();
1852 timestamps_.erase(timestamps_.begin());
1853 int64_t render_time_ms = render_times_ms_.front();
1854 render_times_ms_.erase(render_times_ms_.begin());
1855 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1856 frame_rtc_times_ms_.front();
1857 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001858 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001859
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001860 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001861 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001862 jobject j_output_buffer =
1863 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1864 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1865 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1866 uint8* payload = reinterpret_cast<uint8_t*>(
1867 jni->GetDirectBufferAddress(j_output_buffer));
1868 CHECK_EXCEPTION(jni);
1869
1870 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1871 " EncTime: %lld",
1872 output_buffer_index, payload_size, last_output_timestamp_ms_,
1873 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1874 frame_encoding_time_ms);
1875
1876 // Calculate and print encoding statistics - every 3 seconds.
1877 current_frames_++;
1878 current_bytes_ += payload_size;
1879 current_encoding_time_ms_ += frame_encoding_time_ms;
1880 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1881 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1882 current_frames_ > 0) {
1883 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1884 " encTime: %d for last %d ms",
1885 current_bytes_ * 8 / statistic_time_ms,
1886 last_set_bitrate_kbps_,
1887 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1888 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1889 start_time_ms_ = GetCurrentTimeMs();
1890 current_frames_ = 0;
1891 current_bytes_= 0;
1892 current_encoding_time_ms_ = 0;
1893 }
1894
1895 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001896 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001897 scoped_ptr<webrtc::EncodedImage> image(
1898 new webrtc::EncodedImage(payload, payload_size, payload_size));
1899 image->_encodedWidth = width_;
1900 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001901 image->_timeStamp = timestamp;
1902 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001903 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1904 image->_completeFrame = true;
1905
1906 webrtc::CodecSpecificInfo info;
1907 memset(&info, 0, sizeof(info));
1908 info.codecType = kVideoCodecVP8;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001909 info.codecSpecific.VP8.pictureId = picture_id_;
1910 info.codecSpecific.VP8.nonReference = false;
1911 info.codecSpecific.VP8.simulcastIdx = 0;
1912 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx;
1913 info.codecSpecific.VP8.layerSync = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001914 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1915 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001916 picture_id_ = (picture_id_ + 1) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001917
1918 // Generate a header describing a single fragment.
1919 webrtc::RTPFragmentationHeader header;
1920 memset(&header, 0, sizeof(header));
1921 header.VerifyAndAllocateFragmentationHeader(1);
1922 header.fragmentationOffset[0] = 0;
1923 header.fragmentationLength[0] = image->_length;
1924 header.fragmentationPlType[0] = 0;
1925 header.fragmentationTimeDiff[0] = 0;
1926
1927 callback_status = callback_->Encoded(*image, &info, &header);
1928 }
1929
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001930 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001931 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1932 j_release_output_buffer_method_,
1933 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001934 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001935 if (!success) {
1936 ResetCodec();
1937 return false;
1938 }
1939
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001940 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001941 drop_next_input_frame_ = true;
1942 // Theoretically could handle callback_status<0 here, but unclear what that
1943 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001944 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001945 }
1946
1947 return true;
1948}
1949
1950// Simplest-possible implementation of an encoder factory, churns out
1951// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1952class MediaCodecVideoEncoderFactory
1953 : public cricket::WebRtcVideoEncoderFactory {
1954 public:
1955 MediaCodecVideoEncoderFactory();
1956 virtual ~MediaCodecVideoEncoderFactory();
1957
1958 // WebRtcVideoEncoderFactory implementation.
1959 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1960 OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001961 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1962 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1963
1964 private:
1965 // Empty if platform support is lacking, const after ctor returns.
1966 std::vector<VideoCodec> supported_codecs_;
1967};
1968
1969MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1970 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1971 ScopedLocalRefFrame local_ref_frame(jni);
1972 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1973 bool is_platform_supported = jni->CallStaticBooleanMethod(
1974 j_encoder_class,
1975 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001976 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001977 if (!is_platform_supported)
1978 return;
1979
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001980 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1981 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1982 // reasonable defaults.
1983 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001984 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001985}
1986
1987MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1988
1989webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1990 webrtc::VideoCodecType type) {
1991 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1992 return NULL;
1993 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1994}
1995
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001996const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1997MediaCodecVideoEncoderFactory::codecs() const {
1998 return supported_codecs_;
1999}
2000
2001void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
2002 webrtc::VideoEncoder* encoder) {
2003 delete encoder;
2004}
2005
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002006class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002007 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002008 public:
2009 explicit MediaCodecVideoDecoder(JNIEnv* jni);
2010 virtual ~MediaCodecVideoDecoder();
2011
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002012 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
2013
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002014 virtual int32_t InitDecode(const VideoCodec* codecSettings,
2015 int32_t numberOfCores) OVERRIDE;
2016
2017 virtual int32_t
2018 Decode(const EncodedImage& inputImage, bool missingFrames,
2019 const RTPFragmentationHeader* fragmentation,
2020 const CodecSpecificInfo* codecSpecificInfo = NULL,
2021 int64_t renderTimeMs = -1) OVERRIDE;
2022
2023 virtual int32_t RegisterDecodeCompleteCallback(
2024 DecodedImageCallback* callback) OVERRIDE;
2025
2026 virtual int32_t Release() OVERRIDE;
2027
2028 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002029 // rtc::MessageHandler implementation.
2030 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002031
2032 private:
2033 // CHECK-fail if not running on |codec_thread_|.
2034 void CheckOnCodecThread();
2035
2036 int32_t InitDecodeOnCodecThread();
2037 int32_t ReleaseOnCodecThread();
2038 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002039 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
2040 // true on success.
2041 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
2042
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002043
2044 bool key_frame_required_;
2045 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002046 bool use_surface_;
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002047 int error_count_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002048 VideoCodec codec_;
2049 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002050 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002051 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002052 int frames_received_; // Number of frames received by decoder.
2053 int frames_decoded_; // Number of frames decoded by decoder
2054 int64_t start_time_ms_; // Start time for statistics.
2055 int current_frames_; // Number of frames in the current statistics interval.
2056 int current_bytes_; // Encoded bytes in the current statistics interval.
2057 int current_decoding_time_ms_; // Overall decoding time in the current second
2058 uint32_t max_pending_frames_; // Maximum number of pending input frames
2059 std::vector<int32_t> timestamps_;
2060 std::vector<int64_t> ntp_times_ms_;
2061 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
2062 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002063
2064 // State that is constant for the lifetime of this object once the ctor
2065 // returns.
2066 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
2067 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2068 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2069 jmethodID j_init_decode_method_;
2070 jmethodID j_release_method_;
2071 jmethodID j_dequeue_input_buffer_method_;
2072 jmethodID j_queue_input_buffer_method_;
2073 jmethodID j_dequeue_output_buffer_method_;
2074 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002075 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002076 jfieldID j_input_buffers_field_;
2077 jfieldID j_output_buffers_field_;
2078 jfieldID j_color_format_field_;
2079 jfieldID j_width_field_;
2080 jfieldID j_height_field_;
2081 jfieldID j_stride_field_;
2082 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002083 jfieldID j_surface_texture_field_;
2084 jfieldID j_textureID_field_;
2085 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2086 jfieldID j_info_index_field_;
2087 jfieldID j_info_offset_field_;
2088 jfieldID j_info_size_field_;
2089 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002090
2091 // Global references; must be deleted in Release().
2092 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002093 jobject surface_texture_;
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002094 jobject previous_surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002095
2096 // Render EGL context.
2097 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002098};
2099
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002100jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2101
2102int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2103 jobject render_egl_context) {
2104 if (render_egl_context_) {
2105 jni->DeleteGlobalRef(render_egl_context_);
2106 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002107 if (IsNull(jni, render_egl_context)) {
2108 render_egl_context_ = NULL;
2109 } else {
2110 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002111 CHECK_EXCEPTION(jni) << "error calling NewGlobalRef for EGL Context.";
2112 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
2113 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
2114 ALOGE("Wrong EGL Context.");
2115 jni->DeleteGlobalRef(render_egl_context_);
2116 render_egl_context_ = NULL;
2117 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002118 }
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002119 if (render_egl_context_ == NULL) {
2120 ALOGD("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
2121 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002122 return 0;
2123}
2124
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002125MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
2126 : key_frame_required_(true),
2127 inited_(false),
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002128 error_count_(0),
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002129 surface_texture_(NULL),
2130 previous_surface_texture_(NULL),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002131 codec_thread_(new Thread()),
2132 j_media_codec_video_decoder_class_(
2133 jni,
2134 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2135 j_media_codec_video_decoder_(
2136 jni,
2137 jni->NewObject(*j_media_codec_video_decoder_class_,
2138 GetMethodID(jni,
2139 *j_media_codec_video_decoder_class_,
2140 "<init>",
2141 "()V"))) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002142 ScopedLocalRefFrame local_ref_frame(jni);
2143 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002144 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002145
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002146 j_init_decode_method_ = GetMethodID(
2147 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002148 "(IIZZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002149 j_release_method_ =
2150 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2151 j_dequeue_input_buffer_method_ = GetMethodID(
2152 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2153 j_queue_input_buffer_method_ = GetMethodID(
2154 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2155 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002156 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2157 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002158 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002159 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002160
2161 j_input_buffers_field_ = GetFieldID(
2162 jni, *j_media_codec_video_decoder_class_,
2163 "inputBuffers", "[Ljava/nio/ByteBuffer;");
2164 j_output_buffers_field_ = GetFieldID(
2165 jni, *j_media_codec_video_decoder_class_,
2166 "outputBuffers", "[Ljava/nio/ByteBuffer;");
2167 j_color_format_field_ = GetFieldID(
2168 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2169 j_width_field_ = GetFieldID(
2170 jni, *j_media_codec_video_decoder_class_, "width", "I");
2171 j_height_field_ = GetFieldID(
2172 jni, *j_media_codec_video_decoder_class_, "height", "I");
2173 j_stride_field_ = GetFieldID(
2174 jni, *j_media_codec_video_decoder_class_, "stride", "I");
2175 j_slice_height_field_ = GetFieldID(
2176 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002177 j_textureID_field_ = GetFieldID(
2178 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2179 j_surface_texture_field_ = GetFieldID(
2180 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2181 "Landroid/graphics/SurfaceTexture;");
2182
2183 jclass j_decoder_output_buffer_info_class = FindClass(jni,
2184 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2185 j_info_index_field_ = GetFieldID(
2186 jni, j_decoder_output_buffer_info_class, "index", "I");
2187 j_info_offset_field_ = GetFieldID(
2188 jni, j_decoder_output_buffer_info_class, "offset", "I");
2189 j_info_size_field_ = GetFieldID(
2190 jni, j_decoder_output_buffer_info_class, "size", "I");
2191 j_info_presentation_timestamp_us_field_ = GetFieldID(
2192 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002193
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002194 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002195 use_surface_ = true;
2196 if (render_egl_context_ == NULL)
2197 use_surface_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002198 memset(&codec_, 0, sizeof(codec_));
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00002199 AllowBlockingCalls();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002200}
2201
2202MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002203 // Call Release() to ensure no more callbacks to us after we are deleted.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002204 Release();
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002205 // Delete global references.
2206 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2207 if (previous_surface_texture_ != NULL)
2208 jni->DeleteGlobalRef(previous_surface_texture_);
2209 if (surface_texture_ != NULL)
2210 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002211}
2212
2213int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2214 int32_t numberOfCores) {
2215 if (inst == NULL) {
2216 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2217 }
2218 int ret_val = Release();
2219 if (ret_val < 0) {
2220 return ret_val;
2221 }
2222 // Save VideoCodec instance for later.
2223 if (&codec_ != inst) {
2224 codec_ = *inst;
2225 }
2226 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2227
2228 // Always start with a complete key frame.
2229 key_frame_required_ = true;
2230 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002231 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002232
2233 // Call Java init.
2234 return codec_thread_->Invoke<int32_t>(
2235 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2236}
2237
2238int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2239 CheckOnCodecThread();
2240 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2241 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002242 ALOGD("InitDecodeOnCodecThread: %d x %d. Fps: %d. Errors: %d",
2243 codec_.width, codec_.height, codec_.maxFramerate, error_count_);
2244 bool use_sw_codec = false;
2245 if (error_count_ > 1) {
2246 // If more than one critical errors happen for HW codec, switch to SW codec.
2247 use_sw_codec = true;
2248 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002249
2250 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2251 j_init_decode_method_,
2252 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002253 codec_.height,
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002254 use_sw_codec,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002255 use_surface_,
2256 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002257 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002258 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002259 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002260 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002261 inited_ = true;
2262
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002263 max_pending_frames_ = 0;
2264 if (use_surface_) {
2265 max_pending_frames_ = 1;
2266 }
2267 start_time_ms_ = GetCurrentTimeMs();
2268 current_frames_ = 0;
2269 current_bytes_ = 0;
2270 current_decoding_time_ms_ = 0;
2271 timestamps_.clear();
2272 ntp_times_ms_.clear();
2273 frame_rtc_times_ms_.clear();
2274
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002275 jobjectArray input_buffers = (jobjectArray)GetObjectField(
2276 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2277 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002278 input_buffers_.resize(num_input_buffers);
2279 for (size_t i = 0; i < num_input_buffers; ++i) {
2280 input_buffers_[i] =
2281 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002282 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002283 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002284
2285 if (use_surface_) {
2286 jobject surface_texture = GetObjectField(
2287 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002288 if (previous_surface_texture_ != NULL) {
2289 jni->DeleteGlobalRef(previous_surface_texture_);
2290 }
2291 previous_surface_texture_ = surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002292 surface_texture_ = jni->NewGlobalRef(surface_texture);
2293 }
2294 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2295
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002296 return WEBRTC_VIDEO_CODEC_OK;
2297}
2298
2299int32_t MediaCodecVideoDecoder::Release() {
2300 return codec_thread_->Invoke<int32_t>(
2301 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2302}
2303
2304int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002305 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002306 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002307 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002308 CheckOnCodecThread();
2309 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2310 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2311 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002312 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002313 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002314 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002315 input_buffers_.clear();
2316 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002317 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002318 rtc::MessageQueueManager::Clear(this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002319 inited_ = false;
2320 return WEBRTC_VIDEO_CODEC_OK;
2321}
2322
2323
2324void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002325 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2326 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002327}
2328
2329int32_t MediaCodecVideoDecoder::Decode(
2330 const EncodedImage& inputImage,
2331 bool missingFrames,
2332 const RTPFragmentationHeader* fragmentation,
2333 const CodecSpecificInfo* codecSpecificInfo,
2334 int64_t renderTimeMs) {
2335 if (!inited_) {
2336 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2337 }
2338 if (callback_ == NULL) {
2339 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2340 }
2341 if (inputImage._buffer == NULL && inputImage._length > 0) {
2342 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2343 }
2344 // Check if encoded frame dimension has changed.
2345 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2346 (inputImage._encodedWidth != codec_.width ||
2347 inputImage._encodedHeight != codec_.height)) {
2348 codec_.width = inputImage._encodedWidth;
2349 codec_.height = inputImage._encodedHeight;
2350 InitDecode(&codec_, 1);
2351 }
2352
2353 // Always start with a complete key frame.
2354 if (key_frame_required_) {
2355 if (inputImage._frameType != webrtc::kKeyFrame) {
2356 return WEBRTC_VIDEO_CODEC_ERROR;
2357 }
2358 if (!inputImage._completeFrame) {
2359 return WEBRTC_VIDEO_CODEC_ERROR;
2360 }
2361 key_frame_required_ = false;
2362 }
2363 if (inputImage._length == 0) {
2364 return WEBRTC_VIDEO_CODEC_ERROR;
2365 }
2366
2367 return codec_thread_->Invoke<int32_t>(Bind(
2368 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2369}
2370
2371int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2372 const EncodedImage& inputImage) {
2373 static uint8_t yVal_ = 0x7f;
2374
2375 CheckOnCodecThread();
2376 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2377 ScopedLocalRefFrame local_ref_frame(jni);
2378
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002379 // Try to drain the decoder and wait until output is not too
2380 // much behind the input.
2381 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2382 ALOGV("Wait for output...");
2383 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002384 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002385 Reset();
2386 return WEBRTC_VIDEO_CODEC_ERROR;
2387 }
2388 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2389 ALOGE("Output buffer dequeue timeout");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002390 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002391 Reset();
2392 return WEBRTC_VIDEO_CODEC_ERROR;
2393 }
2394 }
2395
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002396 // Get input buffer.
2397 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2398 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002399 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002400 if (j_input_buffer_index < 0) {
2401 ALOGE("dequeueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002402 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002403 Reset();
2404 return WEBRTC_VIDEO_CODEC_ERROR;
2405 }
2406
2407 // Copy encoded data to Java ByteBuffer.
2408 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2409 uint8* buffer =
2410 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002411 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002412 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002413 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002414 if (buffer_capacity < inputImage._length) {
2415 ALOGE("Input frame size %d is bigger than buffer size %d.",
2416 inputImage._length, buffer_capacity);
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 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002421 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002422 frames_received_, j_input_buffer_index, inputImage._length);
2423 memcpy(buffer, inputImage._buffer, inputImage._length);
2424
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002425 // Save input image timestamps for later output.
2426 frames_received_++;
2427 current_bytes_ += inputImage._length;
2428 timestamps_.push_back(inputImage._timeStamp);
2429 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2430 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2431
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002432 // Feed input to decoder.
2433 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2434 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2435 j_queue_input_buffer_method_,
2436 j_input_buffer_index,
2437 inputImage._length,
2438 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002439 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002440 if (!success) {
2441 ALOGE("queueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002442 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002443 Reset();
2444 return WEBRTC_VIDEO_CODEC_ERROR;
2445 }
2446
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002447 // Try to drain the decoder
2448 if (!DeliverPendingOutputs(jni, 0)) {
2449 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002450 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002451 Reset();
2452 return WEBRTC_VIDEO_CODEC_ERROR;
2453 }
2454
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002455 return WEBRTC_VIDEO_CODEC_OK;
2456}
2457
2458bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2459 JNIEnv* jni, int dequeue_timeout_us) {
2460 if (frames_received_ <= frames_decoded_) {
2461 // No need to query for output buffers - decoder is drained.
2462 return true;
2463 }
2464 // Get decoder output.
2465 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2466 *j_media_codec_video_decoder_,
2467 j_dequeue_output_buffer_method_,
2468 dequeue_timeout_us);
2469
2470 CHECK_EXCEPTION(jni);
2471 if (IsNull(jni, j_decoder_output_buffer_info)) {
2472 return true;
2473 }
2474
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002475 // Extract output buffer info from Java DecoderOutputBufferInfo.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002476 int output_buffer_index =
2477 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2478 if (output_buffer_index < 0) {
2479 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002480 return false;
2481 }
2482 int output_buffer_offset =
2483 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2484 int output_buffer_size =
2485 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2486 CHECK_EXCEPTION(jni);
2487
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002488 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002489 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2490 j_color_format_field_);
2491 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2492 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2493 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2494 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2495 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002496 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2497 j_textureID_field_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002498
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002499 // Extract data from Java ByteBuffer and create output yuv420 frame -
2500 // for non surface decoding only.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002501 if (!use_surface_) {
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002502 if (output_buffer_size < width * height * 3 / 2) {
2503 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002504 return false;
2505 }
2506 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2507 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2508 jobject output_buffer =
2509 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
2510 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
2511 output_buffer));
2512 CHECK_EXCEPTION(jni);
2513 payload += output_buffer_offset;
2514
2515 // Create yuv420 frame.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002516 if (color_format == COLOR_FormatYUV420Planar) {
2517 decoded_image_.CreateFrame(
2518 stride * slice_height, payload,
2519 (stride * slice_height) / 4, payload + (stride * slice_height),
2520 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2521 width, height,
2522 stride, stride / 2, stride / 2);
2523 } else {
2524 // All other supported formats are nv12.
2525 decoded_image_.CreateEmptyFrame(width, height, width,
2526 width / 2, width / 2);
2527 libyuv::NV12ToI420(
2528 payload, stride,
2529 payload + stride * slice_height, stride,
2530 decoded_image_.buffer(webrtc::kYPlane),
2531 decoded_image_.stride(webrtc::kYPlane),
2532 decoded_image_.buffer(webrtc::kUPlane),
2533 decoded_image_.stride(webrtc::kUPlane),
2534 decoded_image_.buffer(webrtc::kVPlane),
2535 decoded_image_.stride(webrtc::kVPlane),
2536 width, height);
2537 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002538 }
2539
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002540 // Get frame timestamps from a queue.
2541 int32_t timestamp = timestamps_.front();
2542 timestamps_.erase(timestamps_.begin());
2543 int64_t ntp_time_ms = ntp_times_ms_.front();
2544 ntp_times_ms_.erase(ntp_times_ms_.begin());
2545 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2546 frame_rtc_times_ms_.front();
2547 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2548
2549 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2550 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2551 color_format, output_buffer_size, frame_decoding_time_ms);
2552
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002553 // Return output buffer back to codec.
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002554 bool success = jni->CallBooleanMethod(
2555 *j_media_codec_video_decoder_,
2556 j_release_output_buffer_method_,
2557 output_buffer_index,
2558 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002559 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002560 if (!success) {
2561 ALOGE("releaseOutputBuffer error");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002562 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002563 }
2564
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002565 // Calculate and print decoding statistics - every 3 seconds.
2566 frames_decoded_++;
2567 current_frames_++;
2568 current_decoding_time_ms_ += frame_decoding_time_ms;
2569 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2570 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2571 current_frames_ > 0) {
2572 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2573 current_bytes_ * 8 / statistic_time_ms,
2574 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2575 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2576 start_time_ms_ = GetCurrentTimeMs();
2577 current_frames_ = 0;
2578 current_bytes_= 0;
2579 current_decoding_time_ms_ = 0;
2580 }
2581
2582 // Callback - output decoded frame.
2583 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2584 if (use_surface_) {
2585 native_handle_.SetTextureObject(surface_texture_, texture_id);
2586 TextureVideoFrame texture_image(
2587 &native_handle_, width, height, timestamp, 0);
2588 texture_image.set_ntp_time_ms(ntp_time_ms);
2589 callback_status = callback_->Decoded(texture_image);
2590 } else {
2591 decoded_image_.set_timestamp(timestamp);
2592 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2593 callback_status = callback_->Decoded(decoded_image_);
2594 }
2595 if (callback_status > 0) {
2596 ALOGE("callback error");
2597 }
2598
2599 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002600}
2601
2602int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2603 DecodedImageCallback* callback) {
2604 callback_ = callback;
2605 return WEBRTC_VIDEO_CODEC_OK;
2606}
2607
2608int32_t MediaCodecVideoDecoder::Reset() {
2609 ALOGD("DecoderReset");
2610 if (!inited_) {
2611 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2612 }
2613 return InitDecode(&codec_, 1);
2614}
2615
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002616void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002617 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2618 ScopedLocalRefFrame local_ref_frame(jni);
2619 if (!inited_) {
2620 return;
2621 }
2622 // We only ever send one message to |this| directly (not through a Bind()'d
2623 // functor), so expect no ID/data.
2624 CHECK(!msg->message_id) << "Unexpected message!";
2625 CHECK(!msg->pdata) << "Unexpected message!";
2626 CheckOnCodecThread();
2627
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002628 if (!DeliverPendingOutputs(jni, 0)) {
2629 error_count_++;
2630 Reset();
2631 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002632 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002633}
2634
2635class MediaCodecVideoDecoderFactory
2636 : public cricket::WebRtcVideoDecoderFactory {
2637 public:
2638 MediaCodecVideoDecoderFactory();
2639 virtual ~MediaCodecVideoDecoderFactory();
2640 // WebRtcVideoDecoderFactory implementation.
2641 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2642 webrtc::VideoCodecType type) OVERRIDE;
2643
2644 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2645
2646 private:
2647 bool is_platform_supported_;
2648};
2649
2650MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2651 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2652 ScopedLocalRefFrame local_ref_frame(jni);
2653 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2654 is_platform_supported_ = jni->CallStaticBooleanMethod(
2655 j_decoder_class,
2656 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002657 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002658}
2659
2660MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2661
2662webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2663 webrtc::VideoCodecType type) {
2664 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2665 return NULL;
2666 }
2667 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2668}
2669
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002670void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2671 webrtc::VideoDecoder* decoder) {
2672 delete decoder;
2673}
2674
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002675// AndroidVideoCapturerJni implements AndroidVideoCapturerDelegate.
2676// The purpose of the delegate is to hide the JNI specifics from the C++ only
2677// AndroidVideoCapturer.
2678// TODO(perkj): Refactor this to a separate file once the jni utility functions
2679// and classes have been moved.
2680class AndroidVideoCapturerJni : public webrtc::AndroidVideoCapturerDelegate {
2681 public:
2682 static int SetAndroidObjects(JNIEnv* jni, jobject appliction_context) {
2683 if (application_context_) {
2684 jni->DeleteGlobalRef(application_context_);
2685 }
2686 application_context_ = NewGlobalRef(jni, appliction_context);
2687
2688 return 0;
2689 }
2690
2691 AndroidVideoCapturerJni(JNIEnv* jni, jobject j_video_capturer)
2692 : j_capturer_global_(jni, j_video_capturer),
2693 j_video_capturer_class_(
2694 jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")),
2695 j_frame_observer_class_(
2696 jni,
2697 FindClass(jni,
2698 "org/webrtc/VideoCapturerAndroid$NativeFrameObserver")) {
2699 }
2700
2701 void Start(int width, int height, int framerate,
2702 webrtc::AndroidVideoCapturer* capturer) override {
2703 j_frame_observer_ = NewGlobalRef(
2704 jni(),
2705 jni()->NewObject(*j_frame_observer_class_,
2706 GetMethodID(jni(),
2707 *j_frame_observer_class_,
2708 "<init>",
2709 "(J)V"),
2710 jlongFromPointer(capturer)));
2711 CHECK_EXCEPTION(jni()) << "error during NewObject";
2712
2713 jmethodID m = GetMethodID(
2714 jni(), *j_video_capturer_class_, "startCapture",
2715 "(IIILandroid/content/Context;"
2716 "Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V");
2717 jni()->CallVoidMethod(*j_capturer_global_,
2718 m, width, height,
2719 framerate,
2720 application_context_,
2721 j_frame_observer_);
2722 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture";
2723 }
2724
2725 bool Stop() override {
2726 jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
2727 "stopCapture", "()Z");
2728 jboolean result = jni()->CallBooleanMethod(*j_capturer_global_, m);
2729 CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture";
2730 DeleteGlobalRef(jni(), j_frame_observer_);
2731 return result;
2732 }
2733
2734 std::string GetSupportedFormats() override {
2735 jmethodID m =
2736 GetMethodID(jni(), *j_video_capturer_class_,
2737 "getSupportedFormatsAsJson", "()Ljava/lang/String;");
2738 jstring j_json_caps =
2739 (jstring) jni()->CallObjectMethod(*j_capturer_global_, m);
2740 CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson";
2741 return JavaToStdString(jni(), j_json_caps);
2742 }
2743
2744 private:
2745 JNIEnv* jni() { return AttachCurrentThreadIfNeeded(); }
2746
2747 const ScopedGlobalRef<jobject> j_capturer_global_;
2748 const ScopedGlobalRef<jclass> j_video_capturer_class_;
2749 const ScopedGlobalRef<jclass> j_frame_observer_class_;
2750 jobject j_frame_observer_;
2751
2752 static jobject application_context_;
2753};
2754
2755jobject AndroidVideoCapturerJni::application_context_ = nullptr;
2756
2757JOW(void, VideoCapturerAndroid_00024NativeFrameObserver_nativeOnFrameCaptured)
2758 (JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame,
2759 jint rotation, jlong ts) {
2760 jbyte* bytes = jni->GetByteArrayElements(j_frame, NULL);
2761 reinterpret_cast<webrtc::AndroidVideoCapturer*>(
2762 j_capturer)->OnIncomingFrame(bytes, jni->GetArrayLength(j_frame),
2763 rotation, ts);
2764 jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
2765}
2766
2767JOW(void, VideoCapturerAndroid_00024NativeFrameObserver_nativeCapturerStarted)
2768 (JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) {
2769 reinterpret_cast<webrtc::AndroidVideoCapturer*>(
2770 j_capturer)->OnCapturerStarted(j_success);
2771}
2772
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002773#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002774
2775} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002776
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002777static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002778 jfieldID native_dc_id = GetFieldID(jni,
2779 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2780 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002781 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002782}
2783
2784JOW(jlong, DataChannel_registerObserverNative)(
2785 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002786 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002787 new DataChannelObserverWrapper(jni, j_observer));
2788 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002789 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002790}
2791
2792JOW(void, DataChannel_unregisterObserverNative)(
2793 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2794 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2795 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2796}
2797
2798JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2799 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2800}
2801
2802JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2803 return JavaEnumFromIndex(
2804 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2805}
2806
2807JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2808 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002809 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2810 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002811 return static_cast<jlong>(buffered_amount);
2812}
2813
2814JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2815 ExtractNativeDC(jni, j_dc)->Close();
2816}
2817
2818JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2819 jbyteArray data, jboolean binary) {
2820 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2821 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002822 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002823 binary));
2824 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2825 return ret;
2826}
2827
2828JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002829 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002830}
2831
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002832JOW(void, Logging_nativeEnableTracing)(
2833 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2834 jint nativeSeverity) {
2835 std::string path = JavaToStdString(jni, j_path);
2836 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002837 webrtc::Trace::set_level_filter(nativeLevels);
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002838#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002839 if (path != "logcat:") {
2840#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002841 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2842 << "SetTraceFile failed";
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002843#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002844 } else {
2845 // Intentionally leak this to avoid needing to reason about its lifecycle.
2846 // It keeps no state and functions only as a dispatch point.
2847 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2848 }
2849#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002850 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002851 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002852}
2853
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002854JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002855 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002856}
2857
2858JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2859 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2860 delete p;
2861}
2862
2863JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002864 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002865}
2866
2867JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2868 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2869}
2870
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002871JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002872 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2873}
2874
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002875JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2876 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2877}
2878
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002879JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002880 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002881}
2882
2883JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2884 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002885 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002886 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002887}
2888
2889JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2890 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002891 return reinterpret_cast<MediaStreamInterface*>(pointer)
2892 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002893}
2894
2895JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2896 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002897 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002898 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002899}
2900
2901JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2902 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002903 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002904 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002905}
2906
2907JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2908 return JavaStringFromStdString(
2909 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2910}
2911
2912JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002913 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002914}
2915
2916JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2917 JNIEnv * jni, jclass, jobject j_observer) {
2918 return (jlong)new PCOJava(jni, j_observer);
2919}
2920
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002921#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002922JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002923 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002924 jboolean initialize_audio, jboolean initialize_video,
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002925 jboolean vp8_hw_acceleration, jobject render_egl_context) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002926 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002927 bool failure = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002928 vp8_hw_acceleration_enabled = vp8_hw_acceleration;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002929 if (!factory_static_initialized) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002930 if (initialize_video) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002931 failure |= webrtc::SetRenderAndroidVM(g_jvm);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002932 failure |= AndroidVideoCapturerJni::SetAndroidObjects(jni, context);
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002933 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002934 if (initialize_audio)
2935 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2936 factory_static_initialized = true;
2937 }
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002938 if (initialize_video) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002939 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2940 render_egl_context);
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00002941 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002942 return !failure;
2943}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002944#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002945
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +00002946JOW(void, PeerConnectionFactory_initializeFieldTrials)(
2947 JNIEnv* jni, jclass, jstring j_trials_init_string) {
2948 field_trials_init_string = NULL;
2949 if (j_trials_init_string != NULL) {
2950 const char* init_string =
2951 jni->GetStringUTFChars(j_trials_init_string, NULL);
2952 int init_string_length = jni->GetStringUTFLength(j_trials_init_string);
2953 field_trials_init_string = new char[init_string_length + 1];
2954 rtc::strcpyn(field_trials_init_string, init_string_length + 1, init_string);
2955 jni->ReleaseStringUTFChars(j_trials_init_string, init_string);
2956 LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string ;
2957 }
2958 webrtc::field_trial::InitFieldTrialsFromString(field_trials_init_string);
2959}
2960
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002961// Helper struct for working around the fact that CreatePeerConnectionFactory()
2962// comes in two flavors: either entirely automagical (constructing its own
2963// threads and deleting them on teardown, but no external codec factory support)
2964// or entirely manual (requires caller to delete threads after factory
2965// teardown). This struct takes ownership of its ctor's arguments to present a
2966// single thing for Java to hold and eventually free.
2967class OwnedFactoryAndThreads {
2968 public:
2969 OwnedFactoryAndThreads(Thread* worker_thread,
2970 Thread* signaling_thread,
2971 PeerConnectionFactoryInterface* factory)
2972 : worker_thread_(worker_thread),
2973 signaling_thread_(signaling_thread),
2974 factory_(factory) {}
2975
2976 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2977
2978 PeerConnectionFactoryInterface* factory() { return factory_; }
2979
2980 private:
2981 const scoped_ptr<Thread> worker_thread_;
2982 const scoped_ptr<Thread> signaling_thread_;
2983 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2984};
2985
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002986JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2987 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002988 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2989 // ThreadManager only WrapCurrentThread()s the thread where it is first
2990 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002991 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002992 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002993 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002994 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002995 Thread* worker_thread = new Thread();
2996 worker_thread->SetName("worker_thread", NULL);
2997 Thread* signaling_thread = new Thread();
2998 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002999 CHECK(worker_thread->Start() && signaling_thread->Start())
3000 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003001 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00003002 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00003003#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00003004 if (vp8_hw_acceleration_enabled) {
3005 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
3006 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
3007 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003008#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003009 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003010 webrtc::CreatePeerConnectionFactory(worker_thread,
3011 signaling_thread,
3012 NULL,
3013 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00003014 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003015 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
3016 worker_thread, signaling_thread, factory.release());
3017 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003018}
3019
3020JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003021 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
glaznev@webrtc.org44ae4c82015-02-09 23:25:58 +00003022 if (field_trials_init_string) {
3023 webrtc::field_trial::InitFieldTrialsFromString(NULL);
3024 delete field_trials_init_string;
3025 field_trials_init_string = NULL;
3026 }
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003027 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003028}
3029
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003030static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
3031 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
3032}
3033
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003034JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
3035 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003036 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003037 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003038 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003039 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
3040 return (jlong)stream.release();
3041}
3042
3043JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
3044 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
3045 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003046 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003047 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003048 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003049 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003050 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003051 factory->CreateVideoSource(
3052 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
3053 constraints.get()));
3054 return (jlong)source.release();
3055}
3056
3057JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
3058 JNIEnv* jni, jclass, jlong native_factory, jstring id,
3059 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003060 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003061 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003062 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003063 factory->CreateVideoTrack(
3064 JavaToStdString(jni, id),
3065 reinterpret_cast<VideoSourceInterface*>(native_source)));
3066 return (jlong)track.release();
3067}
3068
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00003069JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
3070 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
3071 scoped_ptr<ConstraintsWrapper> constraints(
3072 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003073 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003074 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003075 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00003076 factory->CreateAudioSource(constraints.get()));
3077 return (jlong)source.release();
3078}
3079
3080JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
3081 JNIEnv* jni, jclass, jlong native_factory, jstring id,
3082 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003083 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00003084 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003085 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00003086 JavaToStdString(jni, id),
3087 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003088 return (jlong)track.release();
3089}
3090
phoglund@webrtc.org006521d2015-02-12 09:23:59 +00003091JOW(void, PeerConnectionFactory_nativeSetOptions)(
3092 JNIEnv* jni, jclass, jlong native_factory, jobject options) {
3093 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
3094 factoryFromJava(native_factory));
3095 jclass options_class = jni->GetObjectClass(options);
3096 jfieldID network_ignore_mask_field =
3097 jni->GetFieldID(options_class, "networkIgnoreMask", "I");
3098 int network_ignore_mask =
3099 jni->GetIntField(options, network_ignore_mask_field);
3100 PeerConnectionFactoryInterface::Options options_to_set;
3101
3102 // This doesn't necessarily match the c++ version of this struct; feel free
3103 // to add more parameters as necessary.
3104 options_to_set.network_ignore_mask = network_ignore_mask;
3105 factory->SetOptions(options_to_set);
3106}
3107
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003108static void JavaIceServersToJsepIceServers(
3109 JNIEnv* jni, jobject j_ice_servers,
3110 PeerConnectionInterface::IceServers* ice_servers) {
3111 jclass list_class = GetObjectClass(jni, j_ice_servers);
3112 jmethodID iterator_id = GetMethodID(
3113 jni, list_class, "iterator", "()Ljava/util/Iterator;");
3114 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003115 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003116 jmethodID iterator_has_next = GetMethodID(
3117 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
3118 jmethodID iterator_next = GetMethodID(
3119 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
3120 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003121 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003122 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003123 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003124 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
3125 jfieldID j_ice_server_uri_id =
3126 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
3127 jfieldID j_ice_server_username_id =
3128 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
3129 jfieldID j_ice_server_password_id =
3130 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
3131 jstring uri = reinterpret_cast<jstring>(
3132 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
3133 jstring username = reinterpret_cast<jstring>(
3134 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
3135 jstring password = reinterpret_cast<jstring>(
3136 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
3137 PeerConnectionInterface::IceServer server;
3138 server.uri = JavaToStdString(jni, uri);
3139 server.username = JavaToStdString(jni, username);
3140 server.password = JavaToStdString(jni, password);
3141 ice_servers->push_back(server);
3142 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003143 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003144}
3145
3146JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
3147 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
3148 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003149 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003150 reinterpret_cast<PeerConnectionFactoryInterface*>(
3151 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003152 PeerConnectionInterface::IceServers servers;
3153 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
3154 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
3155 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003156 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00003157 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003158 return (jlong)pc.release();
3159}
3160
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003161static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003162 JNIEnv* jni, jobject j_pc) {
3163 jfieldID native_pc_id = GetFieldID(jni,
3164 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
3165 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003166 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003167 reinterpret_cast<PeerConnectionInterface*>(j_p));
3168}
3169
3170JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
3171 const SessionDescriptionInterface* sdp =
3172 ExtractNativePC(jni, j_pc)->local_description();
3173 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3174}
3175
3176JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
3177 const SessionDescriptionInterface* sdp =
3178 ExtractNativePC(jni, j_pc)->remote_description();
3179 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3180}
3181
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003182JOW(jobject, PeerConnection_createDataChannel)(
3183 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
3184 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003185 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003186 ExtractNativePC(jni, j_pc)->CreateDataChannel(
3187 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00003188 // Mustn't pass channel.get() directly through NewObject to avoid reading its
3189 // vararg parameter as 64-bit and reading memory that doesn't belong to the
3190 // 32-bit parameter.
3191 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003192 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003193 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
3194 jmethodID j_data_channel_ctor = GetMethodID(
3195 jni, j_data_channel_class, "<init>", "(J)V");
3196 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00003197 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003198 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003199 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003200 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003201 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003202 return j_channel;
3203}
3204
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003205JOW(void, PeerConnection_createOffer)(
3206 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3207 ConstraintsWrapper* constraints =
3208 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003209 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3210 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003211 jni, j_observer, constraints));
3212 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3213}
3214
3215JOW(void, PeerConnection_createAnswer)(
3216 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3217 ConstraintsWrapper* constraints =
3218 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003219 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3220 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003221 jni, j_observer, constraints));
3222 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3223}
3224
3225// Helper to create a SessionDescriptionInterface from a SessionDescription.
3226static SessionDescriptionInterface* JavaSdpToNativeSdp(
3227 JNIEnv* jni, jobject j_sdp) {
3228 jfieldID j_type_id = GetFieldID(
3229 jni, GetObjectClass(jni, j_sdp), "type",
3230 "Lorg/webrtc/SessionDescription$Type;");
3231 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3232 jmethodID j_canonical_form_id = GetMethodID(
3233 jni, GetObjectClass(jni, j_type), "canonicalForm",
3234 "()Ljava/lang/String;");
3235 jstring j_type_string = (jstring)jni->CallObjectMethod(
3236 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003237 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003238 std::string std_type = JavaToStdString(jni, j_type_string);
3239
3240 jfieldID j_description_id = GetFieldID(
3241 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3242 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3243 std::string std_description = JavaToStdString(jni, j_description);
3244
3245 return webrtc::CreateSessionDescription(
3246 std_type, std_description, NULL);
3247}
3248
3249JOW(void, PeerConnection_setLocalDescription)(
3250 JNIEnv* jni, jobject j_pc,
3251 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003252 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3253 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003254 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3255 ExtractNativePC(jni, j_pc)->SetLocalDescription(
3256 observer, JavaSdpToNativeSdp(jni, j_sdp));
3257}
3258
3259JOW(void, PeerConnection_setRemoteDescription)(
3260 JNIEnv* jni, jobject j_pc,
3261 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003262 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3263 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003264 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3265 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3266 observer, JavaSdpToNativeSdp(jni, j_sdp));
3267}
3268
3269JOW(jboolean, PeerConnection_updateIce)(
3270 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3271 PeerConnectionInterface::IceServers ice_servers;
3272 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003273 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003274 new ConstraintsWrapper(jni, j_constraints));
3275 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3276}
3277
3278JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3279 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3280 jint j_sdp_mline_index, jstring j_candidate_sdp) {
3281 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3282 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003283 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003284 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3285 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3286}
3287
3288JOW(jboolean, PeerConnection_nativeAddLocalStream)(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003289 JNIEnv* jni, jobject j_pc, jlong native_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003290 return ExtractNativePC(jni, j_pc)->AddStream(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003291 reinterpret_cast<MediaStreamInterface*>(native_stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003292}
3293
3294JOW(void, PeerConnection_nativeRemoveLocalStream)(
3295 JNIEnv* jni, jobject j_pc, jlong native_stream) {
3296 ExtractNativePC(jni, j_pc)->RemoveStream(
3297 reinterpret_cast<MediaStreamInterface*>(native_stream));
3298}
3299
3300JOW(bool, PeerConnection_nativeGetStats)(
3301 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003302 rtc::scoped_refptr<StatsObserverWrapper> observer(
3303 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003304 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00003305 observer,
3306 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3307 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003308}
3309
3310JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3311 PeerConnectionInterface::SignalingState state =
3312 ExtractNativePC(jni, j_pc)->signaling_state();
3313 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3314}
3315
3316JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3317 PeerConnectionInterface::IceConnectionState state =
3318 ExtractNativePC(jni, j_pc)->ice_connection_state();
3319 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3320}
3321
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00003322JOW(jobject, PeerConnection_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003323 PeerConnectionInterface::IceGatheringState state =
3324 ExtractNativePC(jni, j_pc)->ice_gathering_state();
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00003325 return JavaEnumFromIndex(jni, "PeerConnection$IceGatheringState", state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003326}
3327
3328JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3329 ExtractNativePC(jni, j_pc)->Close();
3330 return;
3331}
3332
3333JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003334 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003335 reinterpret_cast<MediaSourceInterface*>(j_p));
3336 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3337}
3338
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00003339JOW(jobject, VideoCapturer_nativeCreateVideoCapturer)(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003340 JNIEnv* jni, jclass, jstring j_device_name) {
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00003341// Since we can't create platform specific java implementations in Java, we
3342// defer the creation to C land.
3343#if defined(ANDROID)
3344 jclass j_video_capturer_class(
3345 FindClass(jni, "org/webrtc/VideoCapturerAndroid"));
3346 const jmethodID j_videocapturer_ctor(GetMethodID(
3347 jni, j_video_capturer_class, "<init>", "()V"));
3348 jobject j_video_capturer = jni->NewObject(j_video_capturer_class,
3349 j_videocapturer_ctor);
3350 CHECK_EXCEPTION(jni) << "error during NewObject";
3351
3352 const jmethodID m(GetMethodID(
3353 jni, j_video_capturer_class, "Init", "(Ljava/lang/String;)Z"));
3354 if (!jni->CallBooleanMethod(j_video_capturer, m, j_device_name)) {
3355 return nullptr;
3356 }
3357 CHECK_EXCEPTION(jni) << "error during CallVoidMethod";
3358
3359 rtc::scoped_ptr<webrtc::AndroidVideoCapturerDelegate> delegate(
3360 new AndroidVideoCapturerJni(jni, j_video_capturer));
3361 rtc::scoped_ptr<webrtc::AndroidVideoCapturer> capturer(
3362 new webrtc::AndroidVideoCapturer(delegate.Pass()));
3363
3364#else
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003365 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003366 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003367 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003368 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003369 cricket::Device device;
3370 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003371 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003372 return 0;
3373 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003374 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003375 device_manager->CreateVideoCapturer(device));
perkj@webrtc.org83bc7212015-02-11 11:26:56 +00003376
3377 jclass j_video_capturer_class(
3378 FindClass(jni, "org/webrtc/VideoCapturer"));
3379 const jmethodID j_videocapturer_ctor(GetMethodID(
3380 jni, j_video_capturer_class, "<init>", "()V"));
3381 jobject j_video_capturer =
3382 jni->NewObject(j_video_capturer_class,
3383 j_videocapturer_ctor);
3384 CHECK_EXCEPTION(jni) << "error during creation of VideoCapturer";
3385
3386#endif
3387 const jmethodID j_videocapturer_set_native_capturer(GetMethodID(
3388 jni, j_video_capturer_class, "setNativeCapturer", "(J)V"));
3389 jni->CallVoidMethod(j_video_capturer,
3390 j_videocapturer_set_native_capturer,
3391 (jlong)capturer.release());
3392 CHECK_EXCEPTION(jni) << "error during setNativeCapturer";
3393 return j_video_capturer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003394}
3395
3396JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3397 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003398 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3399 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003400 return (jlong)renderer.release();
3401}
3402
3403JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3404 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003405 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003406 new JavaVideoRendererWrapper(jni, j_callbacks));
3407 return (jlong)renderer.release();
3408}
3409
glaznev@webrtc.orgf6932292015-02-05 17:29:59 +00003410JOW(void, VideoRenderer_nativeCopyPlane)(
3411 JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height,
3412 jint src_stride, jobject j_dst_buffer, jint dst_stride) {
3413 size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer);
3414 size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer);
3415 CHECK(src_stride >= width) << "Wrong source stride " << src_stride;
3416 CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride;
3417 CHECK(src_size >= src_stride * height)
3418 << "Insufficient source buffer capacity " << src_size;
3419 CHECK(dst_size >= dst_stride * height)
3420 << "Isufficient destination buffer capacity " << dst_size;
3421 uint8_t *src =
3422 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
3423 uint8_t *dst =
3424 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_buffer));
3425 if (src_stride == dst_stride) {
3426 memcpy(dst, src, src_stride * height);
3427 } else {
3428 for (int i = 0; i < height; i++) {
3429 memcpy(dst, src, width);
3430 src += src_stride;
3431 dst += dst_stride;
3432 }
3433 }
3434}
3435
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003436JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3437 cricket::VideoCapturer* capturer =
3438 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003439 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003440 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3441 capturer->Stop();
3442 return jlongFromPointer(format.release());
3443}
3444
3445JOW(void, VideoSource_restart)(
3446 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003447 CHECK(j_p_source);
3448 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003449 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003450 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3451 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3452 StartCapturing(cricket::VideoFormat(*format));
3453}
3454
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00003455JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003456 JNIEnv* jni, jclass, jlong j_p) {
3457 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3458}
3459
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003460JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003461 return JavaStringFromStdString(
3462 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003463}
3464
3465JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003466 return JavaStringFromStdString(
3467 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003468}
3469
3470JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003471 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003472}
3473
3474JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003475 return JavaEnumFromIndex(
3476 jni,
3477 "MediaStreamTrack$State",
3478 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003479}
3480
3481JOW(jboolean, MediaStreamTrack_nativeSetState)(
3482 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003483 MediaStreamTrackInterface::TrackState new_state =
3484 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003485 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3486 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003487}
3488
3489JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3490 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003491 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3492 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003493}
3494
3495JOW(void, VideoTrack_nativeAddRenderer)(
3496 JNIEnv* jni, jclass,
3497 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003498 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003499 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3500}
3501
3502JOW(void, VideoTrack_nativeRemoveRenderer)(
3503 JNIEnv* jni, jclass,
3504 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003505 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003506 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3507}