blob: c15d28f71b7cccb45bfd7ceefaaf16a0d5561a07 [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.org99678452014-09-15 17:52:42 +000084#include "webrtc/common_video/interface/texture_video_frame.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000085#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000086#include "webrtc/system_wrappers/interface/trace.h"
87#include "webrtc/video_engine/include/vie_base.h"
88#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089
glaznev@webrtc.org99678452014-09-15 17:52:42 +000090#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
91#include <android/log.h>
andresp@webrtc.org85ef7702014-09-17 11:44:51 +000092#include "webrtc/modules/video_capture/video_capture_internal.h"
93#include "webrtc/modules/video_render/video_render_internal.h"
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000094#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000095#include "webrtc/system_wrappers/interface/tick_util.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000096using webrtc::CodecSpecificInfo;
97using webrtc::DecodedImageCallback;
98using webrtc::EncodedImage;
99using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000100using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000101using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000102using webrtc::TextureVideoFrame;
103using webrtc::TickTime;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000104using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000105#endif
106
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107using icu::UnicodeString;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000108using rtc::Bind;
109using rtc::Thread;
110using rtc::ThreadManager;
111using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112using webrtc::AudioSourceInterface;
113using webrtc::AudioTrackInterface;
114using webrtc::AudioTrackVector;
115using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000116using webrtc::DataBuffer;
117using webrtc::DataChannelInit;
118using webrtc::DataChannelInterface;
119using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120using webrtc::IceCandidateInterface;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000121using webrtc::NativeHandle;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000122using webrtc::MediaConstraintsInterface;
123using webrtc::MediaSourceInterface;
124using webrtc::MediaStreamInterface;
125using webrtc::MediaStreamTrackInterface;
126using webrtc::PeerConnectionFactoryInterface;
127using webrtc::PeerConnectionInterface;
128using webrtc::PeerConnectionObserver;
129using webrtc::SessionDescriptionInterface;
130using webrtc::SetSessionDescriptionObserver;
131using webrtc::StatsObserver;
132using webrtc::StatsReport;
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000133using webrtc::StatsReports;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134using webrtc::VideoRendererInterface;
135using webrtc::VideoSourceInterface;
136using webrtc::VideoTrackInterface;
137using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000138using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000140// Abort the process if |jni| has a Java exception pending.
141// This macros uses the comma operator to execute ExceptionDescribe
142// and ExceptionClear ignoring their return values and sending ""
143// to the error stream.
144#define CHECK_EXCEPTION(jni) \
145 CHECK(!jni->ExceptionCheck()) \
146 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000148// Helper that calls ptr->Release() and aborts the process with a useful
149// message if that didn't actually delete *ptr because of extra refcounts.
150#define CHECK_RELEASE(ptr) \
151 CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000152
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153namespace {
154
155static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
156
157static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000158// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
159// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
160// were attached by the JVM because of a Java->native call.
161static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000163#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
164// Set in PeerConnectionFactory_initializeAndroidGlobals().
165static bool factory_static_initialized = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +0000166static bool vp8_hw_acceleration_enabled = true;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000167#endif
168
169
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000170// Return thread ID as a string.
171static std::string GetThreadId() {
172 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000173 CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
174 sizeof(buf))
175 << "Thread id is bigger than uint64??";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000176 return std::string(buf);
177}
178
179// Return the current thread's name.
180static std::string GetThreadName() {
181 char name[17];
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000182 CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000183 name[16] = '\0';
184 return std::string(name);
185}
186
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000187// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
188static JNIEnv* GetEnv() {
189 void* env = NULL;
190 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
191 CHECK(((env != NULL) && (status == JNI_OK)) ||
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000192 ((env == NULL) && (status == JNI_EDETACHED)))
193 << "Unexpected GetEnv return: " << status << ":" << env;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000194 return reinterpret_cast<JNIEnv*>(env);
195}
196
197static void ThreadDestructor(void* prev_jni_ptr) {
198 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
199 // we were responsible for originally attaching the thread, so are responsible
200 // for detaching it now. However, because some JVM implementations (notably
201 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
202 // the JVMs accounting info for this thread may already be wiped out by the
203 // time this is called. Thus it may appear we are already detached even though
204 // it was our responsibility to detach! Oh well.
205 if (!GetEnv())
206 return;
207
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000208 CHECK(GetEnv() == prev_jni_ptr)
209 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210 jint status = g_jvm->DetachCurrentThread();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000211 CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
212 CHECK(!GetEnv()) << "Detaching was a successful no-op???";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000213}
214
215static void CreateJNIPtrKey() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000216 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
217 << "pthread_key_create";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218}
219
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000220// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000221static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000222 JNIEnv* jni = GetEnv();
223 if (jni)
224 return jni;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000225 CHECK(!pthread_getspecific(g_jni_ptr))
226 << "TLS has a JNIEnv* but not attached?";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000227
228 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
229 JavaVMAttachArgs args;
230 args.version = JNI_VERSION_1_6;
231 args.name = name;
232 args.group = NULL;
233 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000234#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000235 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000236#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000237 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000238#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000239 CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000240 free(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000241 CHECK(env) << "AttachCurrentThread handed back NULL!";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000242 jni = reinterpret_cast<JNIEnv*>(env);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000243 CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 return jni;
245}
246
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000247// Return a |jlong| that will correctly convert back to |ptr|. This is needed
248// because the alternative (of silently passing a 32-bit pointer to a vararg
249// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000250static jlong jlongFromPointer(void* ptr) {
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +0000251 static_assert(sizeof(intptr_t) <= sizeof(jlong),
252 "Time to rethink the use of jlongs");
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000253 // Going through intptr_t to be obvious about the definedness of the
254 // conversion from pointer to integral type. intptr_t to jlong is a standard
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +0000255 // widening by the static_assert above.
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000256 jlong ret = reinterpret_cast<intptr_t>(ptr);
257 assert(reinterpret_cast<void*>(ret) == ptr);
258 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000259}
260
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261// Android's FindClass() is trickier than usual because the app-specific
262// ClassLoader is not consulted when there is no app-specific frame on the
263// stack. Consequently, we only look up classes once in JNI_OnLoad.
264// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
265class ClassReferenceHolder {
266 public:
267 explicit ClassReferenceHolder(JNIEnv* jni) {
268 LoadClass(jni, "java/nio/ByteBuffer");
269 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000270 LoadClass(jni, "org/webrtc/DataChannel");
271 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
272 LoadClass(jni, "org/webrtc/DataChannel$Init");
273 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 LoadClass(jni, "org/webrtc/IceCandidate");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000275#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
276 LoadClass(jni, "android/graphics/SurfaceTexture");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000277 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
278 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000279 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000280 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
glaznev@webrtc.orga8c0edd2014-10-20 19:08:05 +0000281 jclass j_decoder_class = GetClass("org/webrtc/MediaCodecVideoDecoder");
282 jmethodID j_is_egl14_supported_method = jni->GetStaticMethodID(
283 j_decoder_class, "isEGL14Supported", "()Z");
284 bool is_egl14_supported = jni->CallStaticBooleanMethod(
285 j_decoder_class, j_is_egl14_supported_method);
286 CHECK_EXCEPTION(jni);
287 if (is_egl14_supported) {
288 LoadClass(jni, "android/opengl/EGLContext");
289 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000290#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291 LoadClass(jni, "org/webrtc/MediaSource$State");
292 LoadClass(jni, "org/webrtc/MediaStream");
293 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
295 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000296 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000297 LoadClass(jni, "org/webrtc/SessionDescription");
298 LoadClass(jni, "org/webrtc/SessionDescription$Type");
299 LoadClass(jni, "org/webrtc/StatsReport");
300 LoadClass(jni, "org/webrtc/StatsReport$Value");
301 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
302 LoadClass(jni, "org/webrtc/VideoTrack");
303 }
304
305 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000306 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 }
308
309 void FreeReferences(JNIEnv* jni) {
310 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
311 it != classes_.end(); ++it) {
312 jni->DeleteGlobalRef(it->second);
313 }
314 classes_.clear();
315 }
316
317 jclass GetClass(const std::string& name) {
318 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000319 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320 return it->second;
321 }
322
323 private:
324 void LoadClass(JNIEnv* jni, const std::string& name) {
325 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000326 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
327 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000328 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000329 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
330 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000332 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333 }
334
335 std::map<std::string, jclass> classes_;
336};
337
338// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
339static ClassReferenceHolder* g_class_reference_holder = NULL;
340
341// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
342// object/class/method/field is non-null.
343jmethodID GetMethodID(
344 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
345 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000346 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
347 << signature;
348 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 return m;
350}
351
352jmethodID GetStaticMethodID(
353 JNIEnv* jni, jclass c, const char* name, const char* signature) {
354 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000355 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
356 << signature;
357 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000358 return m;
359}
360
361jfieldID GetFieldID(
362 JNIEnv* jni, jclass c, const char* name, const char* signature) {
363 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000364 CHECK_EXCEPTION(jni) << "error during GetFieldID";
365 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000366 return f;
367}
368
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000369// Returns a global reference guaranteed to be valid for the lifetime of the
370// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000371jclass FindClass(JNIEnv* jni, const char* name) {
372 return g_class_reference_holder->GetClass(name);
373}
374
375jclass GetObjectClass(JNIEnv* jni, jobject object) {
376 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000377 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000378 CHECK(c) << "GetObjectClass returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000379 return c;
380}
381
382jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
383 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000384 CHECK_EXCEPTION(jni) << "error during GetObjectField";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000385 CHECK(o) << "GetObjectField returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000386 return o;
387}
388
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000389jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
390 return static_cast<jstring>(GetObjectField(jni, object, id));
391}
392
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
394 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000395 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 return l;
397}
398
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000399jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
400 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000401 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000402 return i;
403}
404
405bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
406 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000407 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000408 return b;
409}
410
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000411jobject NewGlobalRef(JNIEnv* jni, jobject o) {
412 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000413 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
414 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 return ret;
416}
417
418void DeleteGlobalRef(JNIEnv* jni, jobject o) {
419 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000420 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421}
422
423// Given a jweak reference, allocate a (strong) local reference scoped to the
424// lifetime of this object if the weak reference is still valid, or NULL
425// otherwise.
426class WeakRef {
427 public:
428 WeakRef(JNIEnv* jni, jweak ref)
429 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000430 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431 }
432 ~WeakRef() {
433 if (obj_) {
434 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000435 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 }
437 }
438 jobject obj() { return obj_; }
439
440 private:
441 JNIEnv* const jni_;
442 jobject const obj_;
443};
444
fischman@webrtc.org41776152014-01-09 00:31:17 +0000445// Scope Java local references to the lifetime of this object. Use in all C++
446// callbacks (i.e. entry points that don't originate in a Java callstack
447// through a "native" method call).
448class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000450 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000451 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000453 ~ScopedLocalRefFrame() {
454 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000455 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000456
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 private:
458 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000459};
460
461// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000462template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463class ScopedGlobalRef {
464 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000465 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000466 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000467 ~ScopedGlobalRef() {
468 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
469 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000470 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 return obj_;
472 }
473 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000474 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475};
476
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000477// Java references to "null" can only be distinguished as such in C++ by
478// creating a local reference, so this helper wraps that logic.
479static bool IsNull(JNIEnv* jni, jobject obj) {
480 ScopedLocalRefFrame local_ref_frame(jni);
481 return jni->NewLocalRef(obj) == NULL;
482}
483
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484// Return the (singleton) Java Enum object corresponding to |index|;
485// |state_class_fragment| is something like "MediaSource$State".
486jobject JavaEnumFromIndex(
487 JNIEnv* jni, const std::string& state_class_fragment, int index) {
488 std::string state_class_name = "org/webrtc/" + state_class_fragment;
489 jclass state_class = FindClass(jni, state_class_name.c_str());
490 jmethodID state_values_id = GetStaticMethodID(
491 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000492 jobjectArray state_values = static_cast<jobjectArray>(
493 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000494 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000495 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000496 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000497 return ret;
498}
499
500// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
501static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
502 UnicodeString ustr(UnicodeString::fromUTF8(native));
503 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000504 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 return jstr;
506}
507
508// Given a (UTF-16) jstring return a new UTF-8 native string.
509static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
510 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000511 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000512 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000513 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000515 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 std::string ret;
517 return ustr.toUTF8String(ret);
518}
519
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000520static DataChannelInit JavaDataChannelInitToNative(
521 JNIEnv* jni, jobject j_init) {
522 DataChannelInit init;
523
524 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
525 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
526 jfieldID max_retransmit_time_id =
527 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
528 jfieldID max_retransmits_id =
529 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
530 jfieldID protocol_id =
531 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
532 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
533 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
534
535 init.ordered = GetBooleanField(jni, j_init, ordered_id);
536 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
537 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
538 init.protocol = JavaToStdString(
539 jni, GetStringField(jni, j_init, protocol_id));
540 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
541 init.id = GetIntField(jni, j_init, id_id);
542
543 return init;
544}
545
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000546class ConstraintsWrapper;
547
548// Adapter between the C++ PeerConnectionObserver interface and the Java
549// PeerConnection.Observer interface. Wraps an instance of the Java interface
550// and dispatches C++ callbacks to Java.
551class PCOJava : public PeerConnectionObserver {
552 public:
553 PCOJava(JNIEnv* jni, jobject j_observer)
554 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000555 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
556 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
557 j_media_stream_ctor_(GetMethodID(
558 jni, *j_media_stream_class_, "<init>", "(J)V")),
559 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000561 jni, *j_audio_track_class_, "<init>", "(J)V")),
562 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
563 j_video_track_ctor_(GetMethodID(
564 jni, *j_video_track_class_, "<init>", "(J)V")),
565 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
566 j_data_channel_ctor_(GetMethodID(
567 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 }
569
570 virtual ~PCOJava() {}
571
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000572 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000573 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000575 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
577 jmethodID ctor = GetMethodID(jni(), candidate_class,
578 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000579 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
580 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
581 jobject j_candidate = jni()->NewObject(
582 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000583 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000584 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000586 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000587 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 }
589
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000591 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000592 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000594 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000596 jobject new_state_enum =
597 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
598 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000599 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600 }
601
602 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000603 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000604 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000606 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000607 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000608 jobject new_state_enum = JavaEnumFromIndex(
609 jni(), "PeerConnection$IceConnectionState", new_state);
610 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000611 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 }
613
614 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000615 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000616 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000618 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000620 jobject new_state_enum = JavaEnumFromIndex(
621 jni(), "PeerConnection$IceGatheringState", new_state);
622 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000623 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624 }
625
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000626 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000627 ScopedLocalRefFrame local_ref_frame(jni());
628 jobject j_stream = jni()->NewObject(
629 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000630 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631
632 AudioTrackVector audio_tracks = stream->GetAudioTracks();
633 for (size_t i = 0; i < audio_tracks.size(); ++i) {
634 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000635 jstring id = JavaStringFromStdString(jni(), track->id());
636 jobject j_track = jni()->NewObject(
637 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000638 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000639 jfieldID audio_tracks_id = GetFieldID(jni(),
640 *j_media_stream_class_,
641 "audioTracks",
642 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000643 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000645 GetObjectClass(jni(), audio_tracks),
646 "add",
647 "(Ljava/lang/Object;)Z");
648 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000649 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
650 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 }
652
653 VideoTrackVector video_tracks = stream->GetVideoTracks();
654 for (size_t i = 0; i < video_tracks.size(); ++i) {
655 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000656 jstring id = JavaStringFromStdString(jni(), track->id());
657 jobject j_track = jni()->NewObject(
658 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000659 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000660 jfieldID video_tracks_id = GetFieldID(jni(),
661 *j_media_stream_class_,
662 "videoTracks",
663 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000664 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000666 GetObjectClass(jni(), video_tracks),
667 "add",
668 "(Ljava/lang/Object;)Z");
669 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000670 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
671 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000672 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000673 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000674 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000676 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
677 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000678 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000679 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 }
681
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000682 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000683 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000685 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000686
687 WeakRef s(jni(), it->second);
688 streams_.erase(it);
689 if (!s.obj())
690 return;
691
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000692 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
693 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000695 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696 }
697
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000698 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000699 ScopedLocalRefFrame local_ref_frame(jni());
700 jobject j_channel = jni()->NewObject(
701 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000702 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000703
704 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
705 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000706 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000707
708 // Channel is now owned by Java object, and will be freed from
709 // DataChannel.dispose(). Important that this be done _after_ the
710 // CallVoidMethod above as Java code might call back into native code and be
711 // surprised to see a refcount of 2.
712 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000713 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000714
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000715 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000716 }
717
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000718 virtual void OnRenegotiationNeeded() OVERRIDE {
719 ScopedLocalRefFrame local_ref_frame(jni());
720 jmethodID m =
721 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
722 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000723 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000724 }
725
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000727 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728 constraints_.reset(constraints);
729 }
730
731 const ConstraintsWrapper* constraints() { return constraints_.get(); }
732
733 private:
734 JNIEnv* jni() {
735 return AttachCurrentThreadIfNeeded();
736 }
737
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000738 const ScopedGlobalRef<jobject> j_observer_global_;
739 const ScopedGlobalRef<jclass> j_observer_class_;
740 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000742 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000744 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000746 const ScopedGlobalRef<jclass> j_data_channel_class_;
747 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
749 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000750 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751};
752
753// Wrapper for a Java MediaConstraints object. Copies all needed data so when
754// the constructor returns the Java object is no longer needed.
755class ConstraintsWrapper : public MediaConstraintsInterface {
756 public:
757 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
758 PopulateConstraintsFromJavaPairList(
759 jni, j_constraints, "mandatory", &mandatory_);
760 PopulateConstraintsFromJavaPairList(
761 jni, j_constraints, "optional", &optional_);
762 }
763
764 virtual ~ConstraintsWrapper() {}
765
766 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000767 virtual const Constraints& GetMandatory() const OVERRIDE {
768 return mandatory_;
769 }
770
771 virtual const Constraints& GetOptional() const OVERRIDE {
772 return optional_;
773 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774
775 private:
776 // Helper for translating a List<Pair<String, String>> to a Constraints.
777 static void PopulateConstraintsFromJavaPairList(
778 JNIEnv* jni, jobject j_constraints,
779 const char* field_name, Constraints* field) {
780 jfieldID j_id = GetFieldID(jni,
781 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
782 jobject j_list = GetObjectField(jni, j_constraints, j_id);
783 jmethodID j_iterator_id = GetMethodID(jni,
784 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
785 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000786 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 jmethodID j_has_next = GetMethodID(jni,
788 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
789 jmethodID j_next = GetMethodID(jni,
790 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
791 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000792 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000794 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 jmethodID get_key = GetMethodID(jni,
796 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
797 jstring j_key = reinterpret_cast<jstring>(
798 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000799 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 jmethodID get_value = GetMethodID(jni,
801 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
802 jstring j_value = reinterpret_cast<jstring>(
803 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000804 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 field->push_back(Constraint(JavaToStdString(jni, j_key),
806 JavaToStdString(jni, j_value)));
807 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000808 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809 }
810
811 Constraints mandatory_;
812 Constraints optional_;
813};
814
815static jobject JavaSdpFromNativeSdp(
816 JNIEnv* jni, const SessionDescriptionInterface* desc) {
817 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000818 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000819 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820
821 jclass j_type_class = FindClass(
822 jni, "org/webrtc/SessionDescription$Type");
823 jmethodID j_type_from_canonical = GetStaticMethodID(
824 jni, j_type_class, "fromCanonicalForm",
825 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000826 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000828 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000829 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830
831 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
832 jmethodID j_sdp_ctor = GetMethodID(
833 jni, j_sdp_class, "<init>",
834 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
835 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000836 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000837 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 return j_sdp;
839}
840
841template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
842class SdpObserverWrapper : public T {
843 public:
844 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
845 ConstraintsWrapper* constraints)
846 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000847 j_observer_global_(jni, j_observer),
848 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 }
850
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000851 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000853 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000855 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000856 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
857 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000858 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 }
860
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000861 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000863 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000865 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000867 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
868 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000869 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 }
871
872 protected:
873 // Common implementation for failure of Set & Create types, distinguished by
874 // |op| being "Set" or "Create".
875 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000876 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
877 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000878 jstring j_error_string = JavaStringFromStdString(jni(), error);
879 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000880 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 }
882
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883 JNIEnv* jni() {
884 return AttachCurrentThreadIfNeeded();
885 }
886
fischman@webrtc.org41776152014-01-09 00:31:17 +0000887 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000888 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000889 const ScopedGlobalRef<jobject> j_observer_global_;
890 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891};
892
893class CreateSdpObserverWrapper
894 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
895 public:
896 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
897 ConstraintsWrapper* constraints)
898 : SdpObserverWrapper(jni, j_observer, constraints) {}
899
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000900 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000901 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902 SdpObserverWrapper::OnFailure(std::string("Create"), error);
903 }
904};
905
906class SetSdpObserverWrapper
907 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
908 public:
909 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
910 ConstraintsWrapper* constraints)
911 : SdpObserverWrapper(jni, j_observer, constraints) {}
912
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000913 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000914 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000915 SdpObserverWrapper::OnFailure(std::string("Set"), error);
916 }
917};
918
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000919// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
920// and dispatching the callback from C++ back to Java.
921class DataChannelObserverWrapper : public DataChannelObserver {
922 public:
923 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
924 : j_observer_global_(jni, j_observer),
925 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000926 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000927 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
928 "onStateChange", "()V")),
929 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
930 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000931 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
932 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
933 }
934
935 virtual ~DataChannelObserverWrapper() {}
936
937 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000938 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000939 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000940 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000941 }
942
943 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000944 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000945 jobject byte_buffer =
946 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
947 buffer.data.length());
948 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
949 byte_buffer, buffer.binary);
950 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000951 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000952 }
953
954 private:
955 JNIEnv* jni() {
956 return AttachCurrentThreadIfNeeded();
957 }
958
959 const ScopedGlobalRef<jobject> j_observer_global_;
960 const ScopedGlobalRef<jclass> j_observer_class_;
961 const ScopedGlobalRef<jclass> j_buffer_class_;
962 const jmethodID j_on_state_change_mid_;
963 const jmethodID j_on_message_mid_;
964 const jmethodID j_buffer_ctor_;
965};
966
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000967// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
968// dispatching the callback from C++ back to Java.
969class StatsObserverWrapper : public StatsObserver {
970 public:
971 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000972 : j_observer_global_(jni, j_observer),
973 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
974 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000975 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000976 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000977 "(Ljava/lang/String;Ljava/lang/String;D"
978 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000979 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980 jni, "org/webrtc/StatsReport$Value")),
981 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000982 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983 "(Ljava/lang/String;Ljava/lang/String;)V")) {
984 }
985
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000986 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000988 virtual void OnComplete(const StatsReports& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000989 ScopedLocalRefFrame local_ref_frame(jni());
990 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000991 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
992 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000993 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000994 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000995 }
996
997 private:
998 jobjectArray ReportsToJava(
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +0000999 JNIEnv* jni, const StatsReports& reports) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001001 reports.size(), *j_stats_report_class_, NULL);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001002 int i = 0;
1003 for (const auto* report : reports) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001004 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001005 jstring j_id = JavaStringFromStdString(jni, report->id().ToString());
1006 jstring j_type = JavaStringFromStdString(jni, report->TypeToString());
1007 jobjectArray j_values = ValuesToJava(jni, report->values());
fischman@webrtc.org41776152014-01-09 00:31:17 +00001008 jobject j_report = jni->NewObject(*j_stats_report_class_,
1009 j_stats_report_ctor_,
1010 j_id,
1011 j_type,
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001012 report->timestamp(),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001013 j_values);
tommi@webrtc.orge2e199b2014-12-15 13:22:54 +00001014 jni->SetObjectArrayElement(reports_array, i++, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001015 }
1016 return reports_array;
1017 }
1018
1019 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1020 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001021 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001023 ScopedLocalRefFrame local_ref_frame(jni);
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001024 const auto& value = values[i];
tommi@webrtc.orgc57310b2014-12-12 17:41:28 +00001025 // Should we use the '.name' enum value here instead of converting the
1026 // name to a string?
tommi@webrtc.org8e327c42015-01-19 20:41:26 +00001027 jstring j_name = JavaStringFromStdString(jni, value->display_name());
1028 jstring j_value = JavaStringFromStdString(jni, value->value);
fischman@webrtc.org41776152014-01-09 00:31:17 +00001029 jobject j_element_value =
1030 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1031 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001032 }
1033 return j_values;
1034 }
1035
1036 JNIEnv* jni() {
1037 return AttachCurrentThreadIfNeeded();
1038 }
1039
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001040 const ScopedGlobalRef<jobject> j_observer_global_;
1041 const ScopedGlobalRef<jclass> j_observer_class_;
1042 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001043 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001044 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 const jmethodID j_value_ctor_;
1046};
1047
1048// Adapter presenting a cricket::VideoRenderer as a
1049// webrtc::VideoRendererInterface.
1050class VideoRendererWrapper : public VideoRendererInterface {
1051 public:
1052 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1053 if (renderer)
1054 return new VideoRendererWrapper(renderer);
1055 return NULL;
1056 }
1057
1058 virtual ~VideoRendererWrapper() {}
1059
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001060 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001061 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062 const bool kNotReserved = false; // What does this param mean??
1063 renderer_->SetSize(width, height, kNotReserved);
1064 }
1065
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001066 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001067 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001068 renderer_->RenderFrame(frame);
1069 }
1070
1071 private:
1072 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1073 : renderer_(renderer) {}
1074
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001075 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076};
1077
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001078// Wrapper for texture object in TextureVideoFrame.
1079class NativeHandleImpl : public NativeHandle {
1080 public:
1081 NativeHandleImpl() :
1082 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1083 virtual ~NativeHandleImpl() {}
1084 virtual int32_t AddRef() {
1085 return ++ref_count_;
1086 }
1087 virtual int32_t Release() {
1088 return --ref_count_;
1089 }
1090 virtual void* GetHandle() {
1091 return texture_object_;
1092 }
1093 int GetTextureId() {
1094 return texture_id_;
1095 }
1096 void SetTextureObject(void *texture_object, int texture_id) {
1097 texture_object_ = reinterpret_cast<jobject>(texture_object);
1098 texture_id_ = texture_id;
1099 }
1100 int32_t ref_count() {
1101 return ref_count_;
1102 }
1103
1104 private:
1105 int32_t ref_count_;
1106 jobject texture_object_;
1107 int32_t texture_id_;
1108};
1109
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001110// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1111// instance.
1112class JavaVideoRendererWrapper : public VideoRendererInterface {
1113 public:
1114 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001115 : j_callbacks_(jni, j_callbacks),
1116 j_set_size_id_(GetMethodID(
1117 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1118 j_render_frame_id_(GetMethodID(
1119 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1120 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1121 j_frame_class_(jni,
1122 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001123 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001124 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001125 j_texture_frame_ctor_id_(GetMethodID(
1126 jni, *j_frame_class_, "<init>",
1127 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001128 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001129 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130 }
1131
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001132 virtual ~JavaVideoRendererWrapper() {}
1133
1134 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001135 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001136 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001137 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001138 }
1139
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001140 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001141 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001142 if (frame->GetNativeHandle() != NULL) {
1143 jobject j_frame = CricketToJavaTextureFrame(frame);
1144 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1145 CHECK_EXCEPTION(jni());
1146 } else {
1147 jobject j_frame = CricketToJavaI420Frame(frame);
1148 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1149 CHECK_EXCEPTION(jni());
1150 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001151 }
1152
1153 private:
1154 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001155 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001156 jintArray strides = jni()->NewIntArray(3);
1157 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001158 strides_array[0] = frame->GetYPitch();
1159 strides_array[1] = frame->GetUPitch();
1160 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001161 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1162 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1163 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001164 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001165 frame->GetYPitch() * frame->GetHeight());
1166 jobject u_buffer = jni()->NewDirectByteBuffer(
1167 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1168 jobject v_buffer = jni()->NewDirectByteBuffer(
1169 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1170 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1171 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1172 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001173 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001174 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001175 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001176 }
1177
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001178 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1179 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1180 NativeHandleImpl* handle =
1181 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1182 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1183 int texture_id = handle->GetTextureId();
1184 return jni()->NewObject(
1185 *j_frame_class_, j_texture_frame_ctor_id_,
1186 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1187 }
1188
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189 JNIEnv* jni() {
1190 return AttachCurrentThreadIfNeeded();
1191 }
1192
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001193 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194 jmethodID j_set_size_id_;
1195 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001196 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001197 jmethodID j_i420_frame_ctor_id_;
1198 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001199 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200};
1201
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001202#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001203// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1204// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1205// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001207//#define TRACK_BUFFER_TIMING
1208#define TAG "MediaCodecVideo"
1209#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001210#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1211#else
1212#define ALOGV(...)
1213#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001214#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1215#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001216
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001217// Color formats supported by encoder - should mirror supportedColorList
1218// from MediaCodecVideoEncoder.java
1219enum COLOR_FORMATTYPE {
1220 COLOR_FormatYUV420Planar = 0x13,
1221 COLOR_FormatYUV420SemiPlanar = 0x15,
1222 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1223 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1224 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1225 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1226 // but requires some (16, 32?) byte alignment.
1227 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1228};
1229
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001230// Arbitrary interval to poll the codec for new outputs.
1231enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001232// Media codec maximum output buffer ready timeout.
1233enum { kMediaCodecTimeoutMs = 500 };
1234// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1235enum { kMediaCodecStatisticsIntervalMs = 3000 };
1236
1237static int64_t GetCurrentTimeMs() {
1238 return TickTime::Now().Ticks() / 1000000LL;
1239}
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001240
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001241// Allow Invoke() calls from from current thread.
1242static void AllowBlockingCalls() {
1243 Thread* current_thread = Thread::Current();
1244 if (current_thread != NULL)
1245 current_thread->SetAllowBlockingCalls(true);
1246}
1247
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001248// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1249// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1250// HW-backed video encode. This C++ class is implemented as a very thin shim,
1251// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1252// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1253// thread, currently the libjingle Worker thread.
1254class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001255 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001256 public:
1257 virtual ~MediaCodecVideoEncoder();
1258 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1259
1260 // webrtc::VideoEncoder implementation. Everything trampolines to
1261 // |codec_thread_| for execution.
1262 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1263 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001264 size_t /* max_payload_size */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001265 virtual int32_t Encode(
1266 const webrtc::I420VideoFrame& input_image,
1267 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1268 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1269 virtual int32_t RegisterEncodeCompleteCallback(
1270 webrtc::EncodedImageCallback* callback) OVERRIDE;
1271 virtual int32_t Release() OVERRIDE;
1272 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001273 int64_t /* rtt */) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001274 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1275
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001276 // rtc::MessageHandler implementation.
1277 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001278
1279 private:
1280 // CHECK-fail if not running on |codec_thread_|.
1281 void CheckOnCodecThread();
1282
1283 // Release() and InitEncode() in an attempt to restore the codec to an
1284 // operable state. Necessary after all manner of OMX-layer errors.
1285 void ResetCodec();
1286
1287 // Implementation of webrtc::VideoEncoder methods above, all running on the
1288 // codec thread exclusively.
1289 //
1290 // If width==0 then this is assumed to be a re-initialization and the
1291 // previously-current values are reused instead of the passed parameters
1292 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001293 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001294 int32_t EncodeOnCodecThread(
1295 const webrtc::I420VideoFrame& input_image,
1296 const std::vector<webrtc::VideoFrameType>* frame_types);
1297 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1298 webrtc::EncodedImageCallback* callback);
1299 int32_t ReleaseOnCodecThread();
1300 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1301
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001302 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1303 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1304 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1305 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1306 jlong GetOutputBufferInfoPresentationTimestampUs(
1307 JNIEnv* jni,
1308 jobject j_output_buffer_info);
1309
1310 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1311 // true on success.
1312 bool DeliverPendingOutputs(JNIEnv* jni);
1313
1314 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1315 // |codec_thread_| synchronously.
1316 webrtc::EncodedImageCallback* callback_;
1317
1318 // State that is constant for the lifetime of this object once the ctor
1319 // returns.
1320 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1321 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1322 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1323 jmethodID j_init_encode_method_;
1324 jmethodID j_dequeue_input_buffer_method_;
1325 jmethodID j_encode_method_;
1326 jmethodID j_release_method_;
1327 jmethodID j_set_rates_method_;
1328 jmethodID j_dequeue_output_buffer_method_;
1329 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001330 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001331 jfieldID j_info_index_field_;
1332 jfieldID j_info_buffer_field_;
1333 jfieldID j_info_is_key_frame_field_;
1334 jfieldID j_info_presentation_timestamp_us_field_;
1335
1336 // State that is valid only between InitEncode() and the next Release().
1337 // Touched only on codec_thread_ so no explicit synchronization necessary.
1338 int width_; // Frame width in pixels.
1339 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001340 bool inited_;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001341 uint16_t picture_id_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001342 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001343 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001344 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001345 int64_t current_timestamp_us_; // Current frame timestamps in us.
1346 int frames_received_; // Number of frames received by encoder.
1347 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001348 int frames_resolution_update_; // Number of frames with new codec resolution.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001349 int frames_in_queue_; // Number of frames in encoder queue.
1350 int64_t start_time_ms_; // Start time for statistics.
1351 int current_frames_; // Number of frames in the current statistics interval.
1352 int current_bytes_; // Encoded bytes in the current statistics interval.
1353 int current_encoding_time_ms_; // Overall encoding time in the current second
1354 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1355 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
1356 std::vector<int32_t> timestamps_; // Video frames timestamp queue.
1357 std::vector<int64_t> render_times_ms_; // Video frames render time queue.
1358 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1359 // encoder input.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001360 // Frame size in bytes fed to MediaCodec.
1361 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001362 // True only when between a callback_->Encoded() call return a positive value
1363 // and the next Encode() call being ignored.
1364 bool drop_next_input_frame_;
1365 // Global references; must be deleted in Release().
1366 std::vector<jobject> input_buffers_;
1367};
1368
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001369MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001370 // Call Release() to ensure no more callbacks to us after we are deleted.
1371 Release();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001372}
1373
1374MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001375 : callback_(NULL),
1376 inited_(false),
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001377 picture_id_(0),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001378 codec_thread_(new Thread()),
1379 j_media_codec_video_encoder_class_(
1380 jni,
1381 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1382 j_media_codec_video_encoder_(
1383 jni,
1384 jni->NewObject(*j_media_codec_video_encoder_class_,
1385 GetMethodID(jni,
1386 *j_media_codec_video_encoder_class_,
1387 "<init>",
1388 "()V"))) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001389 ScopedLocalRefFrame local_ref_frame(jni);
1390 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1391 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1392 // 2732 means that deadlocks abound. This class synchronously trampolines
1393 // to |codec_thread_|, so if anything else can be coming to _us_ from
1394 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1395 // in the bug, we have a problem. For now work around that with a dedicated
1396 // thread.
1397 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001398 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001399
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001400 jclass j_output_buffer_info_class =
1401 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1402 j_init_encode_method_ = GetMethodID(jni,
1403 *j_media_codec_video_encoder_class_,
1404 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001405 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001406 j_dequeue_input_buffer_method_ = GetMethodID(
1407 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1408 j_encode_method_ = GetMethodID(
1409 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1410 j_release_method_ =
1411 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1412 j_set_rates_method_ = GetMethodID(
1413 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1414 j_dequeue_output_buffer_method_ =
1415 GetMethodID(jni,
1416 *j_media_codec_video_encoder_class_,
1417 "dequeueOutputBuffer",
1418 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1419 j_release_output_buffer_method_ = GetMethodID(
1420 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1421
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001422 j_color_format_field_ =
1423 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001424 j_info_index_field_ =
1425 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1426 j_info_buffer_field_ = GetFieldID(
1427 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1428 j_info_is_key_frame_field_ =
1429 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1430 j_info_presentation_timestamp_us_field_ = GetFieldID(
1431 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001432 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00001433 AllowBlockingCalls();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001434}
1435
1436int32_t MediaCodecVideoEncoder::InitEncode(
1437 const webrtc::VideoCodec* codec_settings,
1438 int32_t /* number_of_cores */,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001439 size_t /* max_payload_size */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001440 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001441 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001442
1443 return codec_thread_->Invoke<int32_t>(
1444 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1445 this,
1446 codec_settings->width,
1447 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001448 codec_settings->startBitrate,
1449 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001450}
1451
1452int32_t MediaCodecVideoEncoder::Encode(
1453 const webrtc::I420VideoFrame& frame,
1454 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1455 const std::vector<webrtc::VideoFrameType>* frame_types) {
1456 return codec_thread_->Invoke<int32_t>(Bind(
1457 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1458}
1459
1460int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1461 webrtc::EncodedImageCallback* callback) {
1462 return codec_thread_->Invoke<int32_t>(
1463 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1464 this,
1465 callback));
1466}
1467
1468int32_t MediaCodecVideoEncoder::Release() {
1469 return codec_thread_->Invoke<int32_t>(
1470 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1471}
1472
1473int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001474 int64_t /* rtt */) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001475 return WEBRTC_VIDEO_CODEC_OK;
1476}
1477
1478int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1479 uint32_t frame_rate) {
1480 return codec_thread_->Invoke<int32_t>(
1481 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1482 this,
1483 new_bit_rate,
1484 frame_rate));
1485}
1486
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001487void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001488 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1489 ScopedLocalRefFrame local_ref_frame(jni);
1490
1491 // We only ever send one message to |this| directly (not through a Bind()'d
1492 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001493 CHECK(!msg->message_id) << "Unexpected message!";
1494 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001495 CheckOnCodecThread();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001496 if (!inited_) {
1497 return;
1498 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001499
1500 // It would be nice to recover from a failure here if one happened, but it's
1501 // unclear how to signal such a failure to the app, so instead we stay silent
1502 // about it and let the next app-called API method reveal the borkedness.
1503 DeliverPendingOutputs(jni);
1504 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1505}
1506
1507void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001508 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1509 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001510}
1511
1512void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001513 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001514 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1515 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001516 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1517 width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001518 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1519 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1520 // https://code.google.com/p/webrtc/issues/detail?id=2920
1521 }
1522}
1523
1524int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001525 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001526 CheckOnCodecThread();
1527 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1528 ScopedLocalRefFrame local_ref_frame(jni);
1529
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001530 ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1531 width, height, kbps, fps);
1532 if (kbps == 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001533 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001534 }
1535 if (fps == 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001536 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001537 }
1538
1539 width_ = width;
1540 height_ = height;
1541 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001542 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001543 yuv_size_ = width_ * height_ * 3 / 2;
1544 frames_received_ = 0;
1545 frames_dropped_ = 0;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001546 frames_resolution_update_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001547 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001548 current_timestamp_us_ = 0;
1549 start_time_ms_ = GetCurrentTimeMs();
1550 current_frames_ = 0;
1551 current_bytes_ = 0;
1552 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001553 last_input_timestamp_ms_ = -1;
1554 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001555 timestamps_.clear();
1556 render_times_ms_.clear();
1557 frame_rtc_times_ms_.clear();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001558 drop_next_input_frame_ = false;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001559 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001560 // We enforce no extra stride/padding in the format creation step.
1561 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1562 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1563 j_init_encode_method_,
1564 width_,
1565 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001566 kbps,
1567 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001568 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001569 if (IsNull(jni, input_buffers))
1570 return WEBRTC_VIDEO_CODEC_ERROR;
1571
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001572 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001573 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1574 j_color_format_field_)) {
1575 case COLOR_FormatYUV420Planar:
1576 encoder_fourcc_ = libyuv::FOURCC_YU12;
1577 break;
1578 case COLOR_FormatYUV420SemiPlanar:
1579 case COLOR_QCOM_FormatYUV420SemiPlanar:
1580 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1581 encoder_fourcc_ = libyuv::FOURCC_NV12;
1582 break;
1583 default:
1584 LOG(LS_ERROR) << "Wrong color format.";
1585 return WEBRTC_VIDEO_CODEC_ERROR;
1586 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001587 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001588 CHECK(input_buffers_.empty())
1589 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001590 input_buffers_.resize(num_input_buffers);
1591 for (size_t i = 0; i < num_input_buffers; ++i) {
1592 input_buffers_[i] =
1593 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001594 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001595 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001596 CHECK_EXCEPTION(jni);
1597 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001598 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001599 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001600
1601 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1602 return WEBRTC_VIDEO_CODEC_OK;
1603}
1604
1605int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1606 const webrtc::I420VideoFrame& frame,
1607 const std::vector<webrtc::VideoFrameType>* frame_types) {
1608 CheckOnCodecThread();
1609 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1610 ScopedLocalRefFrame local_ref_frame(jni);
1611
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001612 if (!inited_) {
1613 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1614 }
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001615 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001616 if (!DeliverPendingOutputs(jni)) {
1617 ResetCodec();
1618 // Continue as if everything's fine.
1619 }
1620
1621 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001622 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001623 drop_next_input_frame_ = false;
1624 return WEBRTC_VIDEO_CODEC_OK;
1625 }
1626
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001627 CHECK(frame_types->size() == 1) << "Unexpected stream count";
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001628 if (frame.width() != width_ || frame.height() != height_) {
1629 frames_resolution_update_++;
1630 ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1631 width_, height_, frame.width(), frame.height());
1632 if (frames_resolution_update_ > 3) {
1633 // Reset codec if we received more than 3 frames with new resolution.
1634 width_ = frame.width();
1635 height_ = frame.height();
1636 frames_resolution_update_ = 0;
1637 ResetCodec();
1638 }
1639 return WEBRTC_VIDEO_CODEC_OK;
1640 }
1641 frames_resolution_update_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001642
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001643 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1644
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001645 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001646 // or the encoder latency exceeds 70 ms and drop frame if so.
1647 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001648 int encoder_latency_ms = last_input_timestamp_ms_ -
1649 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001650 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001651 ALOGD("Drop frame - encoder is behind by %d ms. Q size: %d",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001652 encoder_latency_ms, frames_in_queue_);
1653 frames_dropped_++;
1654 return WEBRTC_VIDEO_CODEC_OK;
1655 }
1656 }
1657
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001658 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1659 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001660 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001661 if (j_input_buffer_index == -1) {
1662 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001663 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001664 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001665 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001666 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001667 if (j_input_buffer_index == -2) {
1668 ResetCodec();
1669 return WEBRTC_VIDEO_CODEC_ERROR;
1670 }
1671
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001672 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001673 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001674
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001675 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001676 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001677 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001678 CHECK_EXCEPTION(jni);
1679 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001680 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001681 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1682 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1683 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1684 yuv_buffer, width_,
1685 width_, height_,
1686 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001687 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001688 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001689 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001690
1691 // Save input image timestamps for later output
1692 timestamps_.push_back(frame.timestamp());
1693 render_times_ms_.push_back(frame.render_time_ms());
1694 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1695
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001696 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1697 j_encode_method_,
1698 key_frame,
1699 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001700 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001701 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001702 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001703 current_timestamp_us_ += 1000000 / last_set_fps_;
1704
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001705 if (!encode_status || !DeliverPendingOutputs(jni)) {
1706 ResetCodec();
1707 return WEBRTC_VIDEO_CODEC_ERROR;
1708 }
1709
1710 return WEBRTC_VIDEO_CODEC_OK;
1711}
1712
1713int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1714 webrtc::EncodedImageCallback* callback) {
1715 CheckOnCodecThread();
1716 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1717 ScopedLocalRefFrame local_ref_frame(jni);
1718 callback_ = callback;
1719 return WEBRTC_VIDEO_CODEC_OK;
1720}
1721
1722int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001723 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001724 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001725 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001726 CheckOnCodecThread();
1727 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001728 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1729 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001730 ScopedLocalRefFrame local_ref_frame(jni);
1731 for (size_t i = 0; i < input_buffers_.size(); ++i)
1732 jni->DeleteGlobalRef(input_buffers_[i]);
1733 input_buffers_.clear();
1734 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001735 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001736 rtc::MessageQueueManager::Clear(this);
1737 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001738 return WEBRTC_VIDEO_CODEC_OK;
1739}
1740
1741int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1742 uint32_t frame_rate) {
1743 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001744 if (last_set_bitrate_kbps_ == new_bit_rate &&
1745 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001746 return WEBRTC_VIDEO_CODEC_OK;
1747 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001748 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1749 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001750 if (new_bit_rate > 0) {
1751 last_set_bitrate_kbps_ = new_bit_rate;
1752 }
1753 if (frame_rate > 0) {
1754 last_set_fps_ = frame_rate;
1755 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001756 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1757 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001758 last_set_bitrate_kbps_,
1759 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001760 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001761 if (!ret) {
1762 ResetCodec();
1763 return WEBRTC_VIDEO_CODEC_ERROR;
1764 }
1765 return WEBRTC_VIDEO_CODEC_OK;
1766}
1767
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001768int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1769 JNIEnv* jni,
1770 jobject j_output_buffer_info) {
1771 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1772}
1773
1774jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1775 JNIEnv* jni,
1776 jobject j_output_buffer_info) {
1777 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1778}
1779
1780bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1781 JNIEnv* jni,
1782 jobject j_output_buffer_info) {
1783 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1784}
1785
1786jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1787 JNIEnv* jni,
1788 jobject j_output_buffer_info) {
1789 return GetLongField(
1790 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1791}
1792
1793bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1794 while (true) {
1795 jobject j_output_buffer_info = jni->CallObjectMethod(
1796 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001797 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001798 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001799 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001800 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001801
1802 int output_buffer_index =
1803 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1804 if (output_buffer_index == -1) {
1805 ResetCodec();
1806 return false;
1807 }
1808
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001809 // Get frame timestamps from a queue.
1810 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001811 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1812 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001813 int32_t timestamp = timestamps_.front();
1814 timestamps_.erase(timestamps_.begin());
1815 int64_t render_time_ms = render_times_ms_.front();
1816 render_times_ms_.erase(render_times_ms_.begin());
1817 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1818 frame_rtc_times_ms_.front();
1819 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001820 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001821
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001822 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001823 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001824 jobject j_output_buffer =
1825 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1826 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1827 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1828 uint8* payload = reinterpret_cast<uint8_t*>(
1829 jni->GetDirectBufferAddress(j_output_buffer));
1830 CHECK_EXCEPTION(jni);
1831
1832 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1833 " EncTime: %lld",
1834 output_buffer_index, payload_size, last_output_timestamp_ms_,
1835 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1836 frame_encoding_time_ms);
1837
1838 // Calculate and print encoding statistics - every 3 seconds.
1839 current_frames_++;
1840 current_bytes_ += payload_size;
1841 current_encoding_time_ms_ += frame_encoding_time_ms;
1842 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1843 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1844 current_frames_ > 0) {
1845 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1846 " encTime: %d for last %d ms",
1847 current_bytes_ * 8 / statistic_time_ms,
1848 last_set_bitrate_kbps_,
1849 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1850 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1851 start_time_ms_ = GetCurrentTimeMs();
1852 current_frames_ = 0;
1853 current_bytes_= 0;
1854 current_encoding_time_ms_ = 0;
1855 }
1856
1857 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001858 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001859 scoped_ptr<webrtc::EncodedImage> image(
1860 new webrtc::EncodedImage(payload, payload_size, payload_size));
1861 image->_encodedWidth = width_;
1862 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001863 image->_timeStamp = timestamp;
1864 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001865 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1866 image->_completeFrame = true;
1867
1868 webrtc::CodecSpecificInfo info;
1869 memset(&info, 0, sizeof(info));
1870 info.codecType = kVideoCodecVP8;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001871 info.codecSpecific.VP8.pictureId = picture_id_;
1872 info.codecSpecific.VP8.nonReference = false;
1873 info.codecSpecific.VP8.simulcastIdx = 0;
1874 info.codecSpecific.VP8.temporalIdx = webrtc::kNoTemporalIdx;
1875 info.codecSpecific.VP8.layerSync = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001876 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1877 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
glaznev@webrtc.orgdae40dc2014-10-09 17:53:09 +00001878 picture_id_ = (picture_id_ + 1) & 0x7FFF;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001879
1880 // Generate a header describing a single fragment.
1881 webrtc::RTPFragmentationHeader header;
1882 memset(&header, 0, sizeof(header));
1883 header.VerifyAndAllocateFragmentationHeader(1);
1884 header.fragmentationOffset[0] = 0;
1885 header.fragmentationLength[0] = image->_length;
1886 header.fragmentationPlType[0] = 0;
1887 header.fragmentationTimeDiff[0] = 0;
1888
1889 callback_status = callback_->Encoded(*image, &info, &header);
1890 }
1891
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001892 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001893 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1894 j_release_output_buffer_method_,
1895 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001896 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001897 if (!success) {
1898 ResetCodec();
1899 return false;
1900 }
1901
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001902 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001903 drop_next_input_frame_ = true;
1904 // Theoretically could handle callback_status<0 here, but unclear what that
1905 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001906 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001907 }
1908
1909 return true;
1910}
1911
1912// Simplest-possible implementation of an encoder factory, churns out
1913// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1914class MediaCodecVideoEncoderFactory
1915 : public cricket::WebRtcVideoEncoderFactory {
1916 public:
1917 MediaCodecVideoEncoderFactory();
1918 virtual ~MediaCodecVideoEncoderFactory();
1919
1920 // WebRtcVideoEncoderFactory implementation.
1921 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1922 OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001923 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1924 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1925
1926 private:
1927 // Empty if platform support is lacking, const after ctor returns.
1928 std::vector<VideoCodec> supported_codecs_;
1929};
1930
1931MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1932 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1933 ScopedLocalRefFrame local_ref_frame(jni);
1934 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1935 bool is_platform_supported = jni->CallStaticBooleanMethod(
1936 j_encoder_class,
1937 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001938 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001939 if (!is_platform_supported)
1940 return;
1941
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001942 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1943 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1944 // reasonable defaults.
1945 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001946 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001947}
1948
1949MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1950
1951webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1952 webrtc::VideoCodecType type) {
1953 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1954 return NULL;
1955 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1956}
1957
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001958const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1959MediaCodecVideoEncoderFactory::codecs() const {
1960 return supported_codecs_;
1961}
1962
1963void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1964 webrtc::VideoEncoder* encoder) {
1965 delete encoder;
1966}
1967
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001968class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001969 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001970 public:
1971 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1972 virtual ~MediaCodecVideoDecoder();
1973
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001974 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1975
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001976 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1977 int32_t numberOfCores) OVERRIDE;
1978
1979 virtual int32_t
1980 Decode(const EncodedImage& inputImage, bool missingFrames,
1981 const RTPFragmentationHeader* fragmentation,
1982 const CodecSpecificInfo* codecSpecificInfo = NULL,
1983 int64_t renderTimeMs = -1) OVERRIDE;
1984
1985 virtual int32_t RegisterDecodeCompleteCallback(
1986 DecodedImageCallback* callback) OVERRIDE;
1987
1988 virtual int32_t Release() OVERRIDE;
1989
1990 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001991 // rtc::MessageHandler implementation.
1992 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001993
1994 private:
1995 // CHECK-fail if not running on |codec_thread_|.
1996 void CheckOnCodecThread();
1997
1998 int32_t InitDecodeOnCodecThread();
1999 int32_t ReleaseOnCodecThread();
2000 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002001 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
2002 // true on success.
2003 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
2004
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002005
2006 bool key_frame_required_;
2007 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002008 bool use_surface_;
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002009 int error_count_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002010 VideoCodec codec_;
2011 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002012 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002013 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002014 int frames_received_; // Number of frames received by decoder.
2015 int frames_decoded_; // Number of frames decoded by decoder
2016 int64_t start_time_ms_; // Start time for statistics.
2017 int current_frames_; // Number of frames in the current statistics interval.
2018 int current_bytes_; // Encoded bytes in the current statistics interval.
2019 int current_decoding_time_ms_; // Overall decoding time in the current second
2020 uint32_t max_pending_frames_; // Maximum number of pending input frames
2021 std::vector<int32_t> timestamps_;
2022 std::vector<int64_t> ntp_times_ms_;
2023 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
2024 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002025
2026 // State that is constant for the lifetime of this object once the ctor
2027 // returns.
2028 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
2029 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2030 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2031 jmethodID j_init_decode_method_;
2032 jmethodID j_release_method_;
2033 jmethodID j_dequeue_input_buffer_method_;
2034 jmethodID j_queue_input_buffer_method_;
2035 jmethodID j_dequeue_output_buffer_method_;
2036 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002037 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002038 jfieldID j_input_buffers_field_;
2039 jfieldID j_output_buffers_field_;
2040 jfieldID j_color_format_field_;
2041 jfieldID j_width_field_;
2042 jfieldID j_height_field_;
2043 jfieldID j_stride_field_;
2044 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002045 jfieldID j_surface_texture_field_;
2046 jfieldID j_textureID_field_;
2047 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2048 jfieldID j_info_index_field_;
2049 jfieldID j_info_offset_field_;
2050 jfieldID j_info_size_field_;
2051 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002052
2053 // Global references; must be deleted in Release().
2054 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002055 jobject surface_texture_;
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002056 jobject previous_surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002057
2058 // Render EGL context.
2059 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002060};
2061
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002062jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2063
2064int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2065 jobject render_egl_context) {
2066 if (render_egl_context_) {
2067 jni->DeleteGlobalRef(render_egl_context_);
2068 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002069 if (IsNull(jni, render_egl_context)) {
2070 render_egl_context_ = NULL;
2071 } else {
2072 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002073 CHECK_EXCEPTION(jni) << "error calling NewGlobalRef for EGL Context.";
2074 jclass j_egl_context_class = FindClass(jni, "android/opengl/EGLContext");
2075 if (!jni->IsInstanceOf(render_egl_context_, j_egl_context_class)) {
2076 ALOGE("Wrong EGL Context.");
2077 jni->DeleteGlobalRef(render_egl_context_);
2078 render_egl_context_ = NULL;
2079 }
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002080 }
glaznev@webrtc.org359d7202014-09-29 23:07:08 +00002081 if (render_egl_context_ == NULL) {
2082 ALOGD("NULL VideoDecoder EGL context - HW surface decoding is disabled.");
2083 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002084 return 0;
2085}
2086
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002087MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
2088 : key_frame_required_(true),
2089 inited_(false),
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002090 error_count_(0),
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002091 surface_texture_(NULL),
2092 previous_surface_texture_(NULL),
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002093 codec_thread_(new Thread()),
2094 j_media_codec_video_decoder_class_(
2095 jni,
2096 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2097 j_media_codec_video_decoder_(
2098 jni,
2099 jni->NewObject(*j_media_codec_video_decoder_class_,
2100 GetMethodID(jni,
2101 *j_media_codec_video_decoder_class_,
2102 "<init>",
2103 "()V"))) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002104 ScopedLocalRefFrame local_ref_frame(jni);
2105 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002106 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002107
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002108 j_init_decode_method_ = GetMethodID(
2109 jni, *j_media_codec_video_decoder_class_, "initDecode",
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002110 "(IIZZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002111 j_release_method_ =
2112 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2113 j_dequeue_input_buffer_method_ = GetMethodID(
2114 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2115 j_queue_input_buffer_method_ = GetMethodID(
2116 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2117 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002118 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2119 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002120 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002121 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002122
2123 j_input_buffers_field_ = GetFieldID(
2124 jni, *j_media_codec_video_decoder_class_,
2125 "inputBuffers", "[Ljava/nio/ByteBuffer;");
2126 j_output_buffers_field_ = GetFieldID(
2127 jni, *j_media_codec_video_decoder_class_,
2128 "outputBuffers", "[Ljava/nio/ByteBuffer;");
2129 j_color_format_field_ = GetFieldID(
2130 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2131 j_width_field_ = GetFieldID(
2132 jni, *j_media_codec_video_decoder_class_, "width", "I");
2133 j_height_field_ = GetFieldID(
2134 jni, *j_media_codec_video_decoder_class_, "height", "I");
2135 j_stride_field_ = GetFieldID(
2136 jni, *j_media_codec_video_decoder_class_, "stride", "I");
2137 j_slice_height_field_ = GetFieldID(
2138 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002139 j_textureID_field_ = GetFieldID(
2140 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2141 j_surface_texture_field_ = GetFieldID(
2142 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2143 "Landroid/graphics/SurfaceTexture;");
2144
2145 jclass j_decoder_output_buffer_info_class = FindClass(jni,
2146 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2147 j_info_index_field_ = GetFieldID(
2148 jni, j_decoder_output_buffer_info_class, "index", "I");
2149 j_info_offset_field_ = GetFieldID(
2150 jni, j_decoder_output_buffer_info_class, "offset", "I");
2151 j_info_size_field_ = GetFieldID(
2152 jni, j_decoder_output_buffer_info_class, "size", "I");
2153 j_info_presentation_timestamp_us_field_ = GetFieldID(
2154 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002155
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002156 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.org90668b12014-09-23 21:42:15 +00002157 use_surface_ = true;
2158 if (render_egl_context_ == NULL)
2159 use_surface_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002160 memset(&codec_, 0, sizeof(codec_));
glaznev@webrtc.org46ffc702014-10-07 17:11:36 +00002161 AllowBlockingCalls();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002162}
2163
2164MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002165 // Call Release() to ensure no more callbacks to us after we are deleted.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002166 Release();
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002167 // Delete global references.
2168 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2169 if (previous_surface_texture_ != NULL)
2170 jni->DeleteGlobalRef(previous_surface_texture_);
2171 if (surface_texture_ != NULL)
2172 jni->DeleteGlobalRef(surface_texture_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002173}
2174
2175int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2176 int32_t numberOfCores) {
2177 if (inst == NULL) {
2178 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2179 }
2180 int ret_val = Release();
2181 if (ret_val < 0) {
2182 return ret_val;
2183 }
2184 // Save VideoCodec instance for later.
2185 if (&codec_ != inst) {
2186 codec_ = *inst;
2187 }
2188 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2189
2190 // Always start with a complete key frame.
2191 key_frame_required_ = true;
2192 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002193 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002194
2195 // Call Java init.
2196 return codec_thread_->Invoke<int32_t>(
2197 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2198}
2199
2200int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2201 CheckOnCodecThread();
2202 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2203 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002204 ALOGD("InitDecodeOnCodecThread: %d x %d. Fps: %d. Errors: %d",
2205 codec_.width, codec_.height, codec_.maxFramerate, error_count_);
2206 bool use_sw_codec = false;
2207 if (error_count_ > 1) {
2208 // If more than one critical errors happen for HW codec, switch to SW codec.
2209 use_sw_codec = true;
2210 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002211
2212 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2213 j_init_decode_method_,
2214 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002215 codec_.height,
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002216 use_sw_codec,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002217 use_surface_,
2218 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002219 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002220 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002221 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002222 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002223 inited_ = true;
2224
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002225 max_pending_frames_ = 0;
2226 if (use_surface_) {
2227 max_pending_frames_ = 1;
2228 }
2229 start_time_ms_ = GetCurrentTimeMs();
2230 current_frames_ = 0;
2231 current_bytes_ = 0;
2232 current_decoding_time_ms_ = 0;
2233 timestamps_.clear();
2234 ntp_times_ms_.clear();
2235 frame_rtc_times_ms_.clear();
2236
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002237 jobjectArray input_buffers = (jobjectArray)GetObjectField(
2238 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2239 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002240 input_buffers_.resize(num_input_buffers);
2241 for (size_t i = 0; i < num_input_buffers; ++i) {
2242 input_buffers_[i] =
2243 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002244 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002245 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002246
2247 if (use_surface_) {
2248 jobject surface_texture = GetObjectField(
2249 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
glaznev@webrtc.org95bacfe2014-10-09 00:00:11 +00002250 if (previous_surface_texture_ != NULL) {
2251 jni->DeleteGlobalRef(previous_surface_texture_);
2252 }
2253 previous_surface_texture_ = surface_texture_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002254 surface_texture_ = jni->NewGlobalRef(surface_texture);
2255 }
2256 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2257
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002258 return WEBRTC_VIDEO_CODEC_OK;
2259}
2260
2261int32_t MediaCodecVideoDecoder::Release() {
2262 return codec_thread_->Invoke<int32_t>(
2263 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2264}
2265
2266int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002267 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002268 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002269 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002270 CheckOnCodecThread();
2271 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2272 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2273 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002274 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002275 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002276 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002277 input_buffers_.clear();
2278 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002279 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002280 rtc::MessageQueueManager::Clear(this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002281 inited_ = false;
2282 return WEBRTC_VIDEO_CODEC_OK;
2283}
2284
2285
2286void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002287 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2288 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002289}
2290
2291int32_t MediaCodecVideoDecoder::Decode(
2292 const EncodedImage& inputImage,
2293 bool missingFrames,
2294 const RTPFragmentationHeader* fragmentation,
2295 const CodecSpecificInfo* codecSpecificInfo,
2296 int64_t renderTimeMs) {
2297 if (!inited_) {
2298 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2299 }
2300 if (callback_ == NULL) {
2301 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2302 }
2303 if (inputImage._buffer == NULL && inputImage._length > 0) {
2304 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2305 }
2306 // Check if encoded frame dimension has changed.
2307 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2308 (inputImage._encodedWidth != codec_.width ||
2309 inputImage._encodedHeight != codec_.height)) {
2310 codec_.width = inputImage._encodedWidth;
2311 codec_.height = inputImage._encodedHeight;
2312 InitDecode(&codec_, 1);
2313 }
2314
2315 // Always start with a complete key frame.
2316 if (key_frame_required_) {
2317 if (inputImage._frameType != webrtc::kKeyFrame) {
2318 return WEBRTC_VIDEO_CODEC_ERROR;
2319 }
2320 if (!inputImage._completeFrame) {
2321 return WEBRTC_VIDEO_CODEC_ERROR;
2322 }
2323 key_frame_required_ = false;
2324 }
2325 if (inputImage._length == 0) {
2326 return WEBRTC_VIDEO_CODEC_ERROR;
2327 }
2328
2329 return codec_thread_->Invoke<int32_t>(Bind(
2330 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2331}
2332
2333int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2334 const EncodedImage& inputImage) {
2335 static uint8_t yVal_ = 0x7f;
2336
2337 CheckOnCodecThread();
2338 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2339 ScopedLocalRefFrame local_ref_frame(jni);
2340
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002341 // Try to drain the decoder and wait until output is not too
2342 // much behind the input.
2343 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2344 ALOGV("Wait for output...");
2345 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002346 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002347 Reset();
2348 return WEBRTC_VIDEO_CODEC_ERROR;
2349 }
2350 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2351 ALOGE("Output buffer dequeue timeout");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002352 error_count_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002353 Reset();
2354 return WEBRTC_VIDEO_CODEC_ERROR;
2355 }
2356 }
2357
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002358 // Get input buffer.
2359 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2360 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002361 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002362 if (j_input_buffer_index < 0) {
2363 ALOGE("dequeueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002364 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002365 Reset();
2366 return WEBRTC_VIDEO_CODEC_ERROR;
2367 }
2368
2369 // Copy encoded data to Java ByteBuffer.
2370 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2371 uint8* buffer =
2372 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002373 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002374 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002375 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002376 if (buffer_capacity < inputImage._length) {
2377 ALOGE("Input frame size %d is bigger than buffer size %d.",
2378 inputImage._length, buffer_capacity);
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002379 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002380 Reset();
2381 return WEBRTC_VIDEO_CODEC_ERROR;
2382 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002383 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002384 frames_received_, j_input_buffer_index, inputImage._length);
2385 memcpy(buffer, inputImage._buffer, inputImage._length);
2386
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002387 // Save input image timestamps for later output.
2388 frames_received_++;
2389 current_bytes_ += inputImage._length;
2390 timestamps_.push_back(inputImage._timeStamp);
2391 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2392 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2393
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002394 // Feed input to decoder.
2395 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2396 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2397 j_queue_input_buffer_method_,
2398 j_input_buffer_index,
2399 inputImage._length,
2400 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002401 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002402 if (!success) {
2403 ALOGE("queueInputBuffer error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002404 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002405 Reset();
2406 return WEBRTC_VIDEO_CODEC_ERROR;
2407 }
2408
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002409 // Try to drain the decoder
2410 if (!DeliverPendingOutputs(jni, 0)) {
2411 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002412 error_count_++;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002413 Reset();
2414 return WEBRTC_VIDEO_CODEC_ERROR;
2415 }
2416
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002417 return WEBRTC_VIDEO_CODEC_OK;
2418}
2419
2420bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2421 JNIEnv* jni, int dequeue_timeout_us) {
2422 if (frames_received_ <= frames_decoded_) {
2423 // No need to query for output buffers - decoder is drained.
2424 return true;
2425 }
2426 // Get decoder output.
2427 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2428 *j_media_codec_video_decoder_,
2429 j_dequeue_output_buffer_method_,
2430 dequeue_timeout_us);
2431
2432 CHECK_EXCEPTION(jni);
2433 if (IsNull(jni, j_decoder_output_buffer_info)) {
2434 return true;
2435 }
2436
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002437 // Extract output buffer info from Java DecoderOutputBufferInfo.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002438 int output_buffer_index =
2439 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2440 if (output_buffer_index < 0) {
2441 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002442 return false;
2443 }
2444 int output_buffer_offset =
2445 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2446 int output_buffer_size =
2447 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2448 CHECK_EXCEPTION(jni);
2449
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002450 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002451 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2452 j_color_format_field_);
2453 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2454 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2455 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2456 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2457 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002458 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2459 j_textureID_field_);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002460
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002461 // Extract data from Java ByteBuffer and create output yuv420 frame -
2462 // for non surface decoding only.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002463 if (!use_surface_) {
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002464 if (output_buffer_size < width * height * 3 / 2) {
2465 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002466 return false;
2467 }
2468 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2469 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2470 jobject output_buffer =
2471 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
2472 uint8_t* payload = reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(
2473 output_buffer));
2474 CHECK_EXCEPTION(jni);
2475 payload += output_buffer_offset;
2476
2477 // Create yuv420 frame.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002478 if (color_format == COLOR_FormatYUV420Planar) {
2479 decoded_image_.CreateFrame(
2480 stride * slice_height, payload,
2481 (stride * slice_height) / 4, payload + (stride * slice_height),
2482 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2483 width, height,
2484 stride, stride / 2, stride / 2);
2485 } else {
2486 // All other supported formats are nv12.
2487 decoded_image_.CreateEmptyFrame(width, height, width,
2488 width / 2, width / 2);
2489 libyuv::NV12ToI420(
2490 payload, stride,
2491 payload + stride * slice_height, stride,
2492 decoded_image_.buffer(webrtc::kYPlane),
2493 decoded_image_.stride(webrtc::kYPlane),
2494 decoded_image_.buffer(webrtc::kUPlane),
2495 decoded_image_.stride(webrtc::kUPlane),
2496 decoded_image_.buffer(webrtc::kVPlane),
2497 decoded_image_.stride(webrtc::kVPlane),
2498 width, height);
2499 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002500 }
2501
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002502 // Get frame timestamps from a queue.
2503 int32_t timestamp = timestamps_.front();
2504 timestamps_.erase(timestamps_.begin());
2505 int64_t ntp_time_ms = ntp_times_ms_.front();
2506 ntp_times_ms_.erase(ntp_times_ms_.begin());
2507 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2508 frame_rtc_times_ms_.front();
2509 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2510
2511 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2512 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2513 color_format, output_buffer_size, frame_decoding_time_ms);
2514
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002515 // Return output buffer back to codec.
glaznev@webrtc.orgebf27572014-09-19 19:36:13 +00002516 bool success = jni->CallBooleanMethod(
2517 *j_media_codec_video_decoder_,
2518 j_release_output_buffer_method_,
2519 output_buffer_index,
2520 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002521 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002522 if (!success) {
2523 ALOGE("releaseOutputBuffer error");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002524 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002525 }
2526
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002527 // Calculate and print decoding statistics - every 3 seconds.
2528 frames_decoded_++;
2529 current_frames_++;
2530 current_decoding_time_ms_ += frame_decoding_time_ms;
2531 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2532 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2533 current_frames_ > 0) {
2534 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2535 current_bytes_ * 8 / statistic_time_ms,
2536 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2537 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2538 start_time_ms_ = GetCurrentTimeMs();
2539 current_frames_ = 0;
2540 current_bytes_= 0;
2541 current_decoding_time_ms_ = 0;
2542 }
2543
2544 // Callback - output decoded frame.
2545 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2546 if (use_surface_) {
2547 native_handle_.SetTextureObject(surface_texture_, texture_id);
2548 TextureVideoFrame texture_image(
2549 &native_handle_, width, height, timestamp, 0);
2550 texture_image.set_ntp_time_ms(ntp_time_ms);
2551 callback_status = callback_->Decoded(texture_image);
2552 } else {
2553 decoded_image_.set_timestamp(timestamp);
2554 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2555 callback_status = callback_->Decoded(decoded_image_);
2556 }
2557 if (callback_status > 0) {
2558 ALOGE("callback error");
2559 }
2560
2561 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002562}
2563
2564int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2565 DecodedImageCallback* callback) {
2566 callback_ = callback;
2567 return WEBRTC_VIDEO_CODEC_OK;
2568}
2569
2570int32_t MediaCodecVideoDecoder::Reset() {
2571 ALOGD("DecoderReset");
2572 if (!inited_) {
2573 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2574 }
2575 return InitDecode(&codec_, 1);
2576}
2577
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002578void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002579 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2580 ScopedLocalRefFrame local_ref_frame(jni);
2581 if (!inited_) {
2582 return;
2583 }
2584 // We only ever send one message to |this| directly (not through a Bind()'d
2585 // functor), so expect no ID/data.
2586 CHECK(!msg->message_id) << "Unexpected message!";
2587 CHECK(!msg->pdata) << "Unexpected message!";
2588 CheckOnCodecThread();
2589
glaznev@webrtc.org25cc7452014-10-02 16:58:05 +00002590 if (!DeliverPendingOutputs(jni, 0)) {
2591 error_count_++;
2592 Reset();
2593 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002594 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002595}
2596
2597class MediaCodecVideoDecoderFactory
2598 : public cricket::WebRtcVideoDecoderFactory {
2599 public:
2600 MediaCodecVideoDecoderFactory();
2601 virtual ~MediaCodecVideoDecoderFactory();
2602 // WebRtcVideoDecoderFactory implementation.
2603 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2604 webrtc::VideoCodecType type) OVERRIDE;
2605
2606 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2607
2608 private:
2609 bool is_platform_supported_;
2610};
2611
2612MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2613 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2614 ScopedLocalRefFrame local_ref_frame(jni);
2615 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2616 is_platform_supported_ = jni->CallStaticBooleanMethod(
2617 j_decoder_class,
2618 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002619 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002620}
2621
2622MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2623
2624webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2625 webrtc::VideoCodecType type) {
2626 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2627 return NULL;
2628 }
2629 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2630}
2631
2632
2633void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2634 webrtc::VideoDecoder* decoder) {
2635 delete decoder;
2636}
2637
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002638#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002639
2640} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002641
2642// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2643// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2644#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2645 Java_org_webrtc_##name
2646
2647extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002648 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002649 g_jvm = jvm;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002650 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002651
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002652 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002653
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002654 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002655
2656 JNIEnv* jni;
2657 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2658 return -1;
2659 g_class_reference_holder = new ClassReferenceHolder(jni);
2660
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002661 return JNI_VERSION_1_6;
2662}
2663
2664extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002665 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002666 delete g_class_reference_holder;
2667 g_class_reference_holder = NULL;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002668 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002669 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002670}
2671
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002672static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002673 jfieldID native_dc_id = GetFieldID(jni,
2674 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2675 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002676 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002677}
2678
2679JOW(jlong, DataChannel_registerObserverNative)(
2680 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002681 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002682 new DataChannelObserverWrapper(jni, j_observer));
2683 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002684 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002685}
2686
2687JOW(void, DataChannel_unregisterObserverNative)(
2688 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2689 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2690 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2691}
2692
2693JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2694 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2695}
2696
2697JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2698 return JavaEnumFromIndex(
2699 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2700}
2701
2702JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2703 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002704 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2705 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002706 return static_cast<jlong>(buffered_amount);
2707}
2708
2709JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2710 ExtractNativeDC(jni, j_dc)->Close();
2711}
2712
2713JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2714 jbyteArray data, jboolean binary) {
2715 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2716 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002717 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002718 binary));
2719 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2720 return ret;
2721}
2722
2723JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002724 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002725}
2726
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002727JOW(void, Logging_nativeEnableTracing)(
2728 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2729 jint nativeSeverity) {
2730 std::string path = JavaToStdString(jni, j_path);
2731 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002732 webrtc::Trace::set_level_filter(nativeLevels);
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002733#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002734 if (path != "logcat:") {
2735#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002736 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2737 << "SetTraceFile failed";
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002738#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002739 } else {
2740 // Intentionally leak this to avoid needing to reason about its lifecycle.
2741 // It keeps no state and functions only as a dispatch point.
2742 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2743 }
2744#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002745 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002746 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002747}
2748
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002749JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002750 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002751}
2752
2753JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2754 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2755 delete p;
2756}
2757
2758JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002759 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002760}
2761
2762JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2763 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2764}
2765
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002766JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002767 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2768}
2769
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002770JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2771 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2772}
2773
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002774JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002775 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002776}
2777
2778JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2779 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002780 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002781 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002782}
2783
2784JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2785 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002786 return reinterpret_cast<MediaStreamInterface*>(pointer)
2787 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002788}
2789
2790JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2791 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002792 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002793 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002794}
2795
2796JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2797 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002798 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002799 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002800}
2801
2802JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2803 return JavaStringFromStdString(
2804 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2805}
2806
2807JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002808 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002809}
2810
2811JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2812 JNIEnv * jni, jclass, jobject j_observer) {
2813 return (jlong)new PCOJava(jni, j_observer);
2814}
2815
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002816#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002817JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002818 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002819 jboolean initialize_audio, jboolean initialize_video,
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002820 jboolean vp8_hw_acceleration, jobject render_egl_context) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002821 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002822 bool failure = false;
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002823 vp8_hw_acceleration_enabled = vp8_hw_acceleration;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002824 if (!factory_static_initialized) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002825 if (initialize_video) {
2826 failure |= webrtc::SetCaptureAndroidVM(g_jvm, context);
2827 failure |= webrtc::SetRenderAndroidVM(g_jvm);
2828 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002829 if (initialize_audio)
2830 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2831 factory_static_initialized = true;
2832 }
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002833 if (initialize_video)
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002834 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2835 render_egl_context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002836 return !failure;
2837}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002838#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002839
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002840// Helper struct for working around the fact that CreatePeerConnectionFactory()
2841// comes in two flavors: either entirely automagical (constructing its own
2842// threads and deleting them on teardown, but no external codec factory support)
2843// or entirely manual (requires caller to delete threads after factory
2844// teardown). This struct takes ownership of its ctor's arguments to present a
2845// single thing for Java to hold and eventually free.
2846class OwnedFactoryAndThreads {
2847 public:
2848 OwnedFactoryAndThreads(Thread* worker_thread,
2849 Thread* signaling_thread,
2850 PeerConnectionFactoryInterface* factory)
2851 : worker_thread_(worker_thread),
2852 signaling_thread_(signaling_thread),
2853 factory_(factory) {}
2854
2855 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2856
2857 PeerConnectionFactoryInterface* factory() { return factory_; }
2858
2859 private:
2860 const scoped_ptr<Thread> worker_thread_;
2861 const scoped_ptr<Thread> signaling_thread_;
2862 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2863};
2864
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002865JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2866 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002867 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2868 // ThreadManager only WrapCurrentThread()s the thread where it is first
2869 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002870 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002871 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002872 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002873 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002874 Thread* worker_thread = new Thread();
2875 worker_thread->SetName("worker_thread", NULL);
2876 Thread* signaling_thread = new Thread();
2877 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002878 CHECK(worker_thread->Start() && signaling_thread->Start())
2879 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002880 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002881 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002882#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
glaznev@webrtc.orgdea51732014-12-01 20:02:13 +00002883 if (vp8_hw_acceleration_enabled) {
2884 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
2885 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
2886 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002887#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002888 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002889 webrtc::CreatePeerConnectionFactory(worker_thread,
2890 signaling_thread,
2891 NULL,
2892 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002893 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002894 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2895 worker_thread, signaling_thread, factory.release());
2896 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002897}
2898
2899JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002900 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002901 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002902}
2903
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002904static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2905 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2906}
2907
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002908JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2909 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002910 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002911 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002912 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002913 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2914 return (jlong)stream.release();
2915}
2916
2917JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2918 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2919 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002920 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002921 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002922 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002923 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002924 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002925 factory->CreateVideoSource(
2926 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2927 constraints.get()));
2928 return (jlong)source.release();
2929}
2930
2931JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2932 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2933 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002934 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002935 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002936 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002937 factory->CreateVideoTrack(
2938 JavaToStdString(jni, id),
2939 reinterpret_cast<VideoSourceInterface*>(native_source)));
2940 return (jlong)track.release();
2941}
2942
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002943JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2944 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2945 scoped_ptr<ConstraintsWrapper> constraints(
2946 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002947 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002948 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002949 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002950 factory->CreateAudioSource(constraints.get()));
2951 return (jlong)source.release();
2952}
2953
2954JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2955 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2956 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002957 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002958 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002959 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002960 JavaToStdString(jni, id),
2961 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002962 return (jlong)track.release();
2963}
2964
2965static void JavaIceServersToJsepIceServers(
2966 JNIEnv* jni, jobject j_ice_servers,
2967 PeerConnectionInterface::IceServers* ice_servers) {
2968 jclass list_class = GetObjectClass(jni, j_ice_servers);
2969 jmethodID iterator_id = GetMethodID(
2970 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2971 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002972 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002973 jmethodID iterator_has_next = GetMethodID(
2974 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2975 jmethodID iterator_next = GetMethodID(
2976 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2977 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002978 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002979 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002980 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002981 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2982 jfieldID j_ice_server_uri_id =
2983 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2984 jfieldID j_ice_server_username_id =
2985 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2986 jfieldID j_ice_server_password_id =
2987 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2988 jstring uri = reinterpret_cast<jstring>(
2989 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2990 jstring username = reinterpret_cast<jstring>(
2991 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2992 jstring password = reinterpret_cast<jstring>(
2993 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2994 PeerConnectionInterface::IceServer server;
2995 server.uri = JavaToStdString(jni, uri);
2996 server.username = JavaToStdString(jni, username);
2997 server.password = JavaToStdString(jni, password);
2998 ice_servers->push_back(server);
2999 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003000 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003001}
3002
3003JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
3004 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
3005 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003006 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003007 reinterpret_cast<PeerConnectionFactoryInterface*>(
3008 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003009 PeerConnectionInterface::IceServers servers;
3010 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
3011 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
3012 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003013 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00003014 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003015 return (jlong)pc.release();
3016}
3017
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003018static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003019 JNIEnv* jni, jobject j_pc) {
3020 jfieldID native_pc_id = GetFieldID(jni,
3021 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
3022 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003023 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003024 reinterpret_cast<PeerConnectionInterface*>(j_p));
3025}
3026
3027JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
3028 const SessionDescriptionInterface* sdp =
3029 ExtractNativePC(jni, j_pc)->local_description();
3030 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3031}
3032
3033JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
3034 const SessionDescriptionInterface* sdp =
3035 ExtractNativePC(jni, j_pc)->remote_description();
3036 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
3037}
3038
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003039JOW(jobject, PeerConnection_createDataChannel)(
3040 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
3041 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003042 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003043 ExtractNativePC(jni, j_pc)->CreateDataChannel(
3044 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00003045 // Mustn't pass channel.get() directly through NewObject to avoid reading its
3046 // vararg parameter as 64-bit and reading memory that doesn't belong to the
3047 // 32-bit parameter.
3048 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003049 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003050 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
3051 jmethodID j_data_channel_ctor = GetMethodID(
3052 jni, j_data_channel_class, "<init>", "(J)V");
3053 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00003054 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003055 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003056 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003057 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003058 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003059 return j_channel;
3060}
3061
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003062JOW(void, PeerConnection_createOffer)(
3063 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3064 ConstraintsWrapper* constraints =
3065 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003066 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3067 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003068 jni, j_observer, constraints));
3069 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3070}
3071
3072JOW(void, PeerConnection_createAnswer)(
3073 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3074 ConstraintsWrapper* constraints =
3075 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003076 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3077 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003078 jni, j_observer, constraints));
3079 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3080}
3081
3082// Helper to create a SessionDescriptionInterface from a SessionDescription.
3083static SessionDescriptionInterface* JavaSdpToNativeSdp(
3084 JNIEnv* jni, jobject j_sdp) {
3085 jfieldID j_type_id = GetFieldID(
3086 jni, GetObjectClass(jni, j_sdp), "type",
3087 "Lorg/webrtc/SessionDescription$Type;");
3088 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3089 jmethodID j_canonical_form_id = GetMethodID(
3090 jni, GetObjectClass(jni, j_type), "canonicalForm",
3091 "()Ljava/lang/String;");
3092 jstring j_type_string = (jstring)jni->CallObjectMethod(
3093 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003094 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003095 std::string std_type = JavaToStdString(jni, j_type_string);
3096
3097 jfieldID j_description_id = GetFieldID(
3098 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3099 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3100 std::string std_description = JavaToStdString(jni, j_description);
3101
3102 return webrtc::CreateSessionDescription(
3103 std_type, std_description, NULL);
3104}
3105
3106JOW(void, PeerConnection_setLocalDescription)(
3107 JNIEnv* jni, jobject j_pc,
3108 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003109 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3110 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003111 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3112 ExtractNativePC(jni, j_pc)->SetLocalDescription(
3113 observer, JavaSdpToNativeSdp(jni, j_sdp));
3114}
3115
3116JOW(void, PeerConnection_setRemoteDescription)(
3117 JNIEnv* jni, jobject j_pc,
3118 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003119 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3120 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003121 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3122 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3123 observer, JavaSdpToNativeSdp(jni, j_sdp));
3124}
3125
3126JOW(jboolean, PeerConnection_updateIce)(
3127 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3128 PeerConnectionInterface::IceServers ice_servers;
3129 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003130 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003131 new ConstraintsWrapper(jni, j_constraints));
3132 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3133}
3134
3135JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3136 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3137 jint j_sdp_mline_index, jstring j_candidate_sdp) {
3138 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3139 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003140 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003141 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3142 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3143}
3144
3145JOW(jboolean, PeerConnection_nativeAddLocalStream)(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003146 JNIEnv* jni, jobject j_pc, jlong native_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003147 return ExtractNativePC(jni, j_pc)->AddStream(
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00003148 reinterpret_cast<MediaStreamInterface*>(native_stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003149}
3150
3151JOW(void, PeerConnection_nativeRemoveLocalStream)(
3152 JNIEnv* jni, jobject j_pc, jlong native_stream) {
3153 ExtractNativePC(jni, j_pc)->RemoveStream(
3154 reinterpret_cast<MediaStreamInterface*>(native_stream));
3155}
3156
3157JOW(bool, PeerConnection_nativeGetStats)(
3158 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003159 rtc::scoped_refptr<StatsObserverWrapper> observer(
3160 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003161 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00003162 observer,
3163 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3164 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003165}
3166
3167JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3168 PeerConnectionInterface::SignalingState state =
3169 ExtractNativePC(jni, j_pc)->signaling_state();
3170 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3171}
3172
3173JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3174 PeerConnectionInterface::IceConnectionState state =
3175 ExtractNativePC(jni, j_pc)->ice_connection_state();
3176 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3177}
3178
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00003179JOW(jobject, PeerConnection_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003180 PeerConnectionInterface::IceGatheringState state =
3181 ExtractNativePC(jni, j_pc)->ice_gathering_state();
braveyao@webrtc.orgfedb9ea2015-01-21 07:57:06 +00003182 return JavaEnumFromIndex(jni, "PeerConnection$IceGatheringState", state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003183}
3184
3185JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3186 ExtractNativePC(jni, j_pc)->Close();
3187 return;
3188}
3189
3190JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003191 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003192 reinterpret_cast<MediaSourceInterface*>(j_p));
3193 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3194}
3195
3196JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
3197 JNIEnv* jni, jclass, jstring j_device_name) {
3198 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003199 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003200 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003201 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003202 cricket::Device device;
3203 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003204 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003205 return 0;
3206 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003207 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003208 device_manager->CreateVideoCapturer(device));
3209 return (jlong)capturer.release();
3210}
3211
3212JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3213 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003214 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3215 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003216 return (jlong)renderer.release();
3217}
3218
3219JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3220 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003221 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003222 new JavaVideoRendererWrapper(jni, j_callbacks));
3223 return (jlong)renderer.release();
3224}
3225
glaznev@webrtc.orgf6932292015-02-05 17:29:59 +00003226JOW(void, VideoRenderer_nativeCopyPlane)(
3227 JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height,
3228 jint src_stride, jobject j_dst_buffer, jint dst_stride) {
3229 size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer);
3230 size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer);
3231 CHECK(src_stride >= width) << "Wrong source stride " << src_stride;
3232 CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride;
3233 CHECK(src_size >= src_stride * height)
3234 << "Insufficient source buffer capacity " << src_size;
3235 CHECK(dst_size >= dst_stride * height)
3236 << "Isufficient destination buffer capacity " << dst_size;
3237 uint8_t *src =
3238 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer));
3239 uint8_t *dst =
3240 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_buffer));
3241 if (src_stride == dst_stride) {
3242 memcpy(dst, src, src_stride * height);
3243 } else {
3244 for (int i = 0; i < height; i++) {
3245 memcpy(dst, src, width);
3246 src += src_stride;
3247 dst += dst_stride;
3248 }
3249 }
3250}
3251
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003252JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3253 cricket::VideoCapturer* capturer =
3254 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003255 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003256 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3257 capturer->Stop();
3258 return jlongFromPointer(format.release());
3259}
3260
3261JOW(void, VideoSource_restart)(
3262 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003263 CHECK(j_p_source);
3264 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003265 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003266 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3267 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3268 StartCapturing(cricket::VideoFormat(*format));
3269}
3270
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00003271JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003272 JNIEnv* jni, jclass, jlong j_p) {
3273 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3274}
3275
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003276JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003277 return JavaStringFromStdString(
3278 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003279}
3280
3281JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003282 return JavaStringFromStdString(
3283 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003284}
3285
3286JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003287 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003288}
3289
3290JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003291 return JavaEnumFromIndex(
3292 jni,
3293 "MediaStreamTrack$State",
3294 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003295}
3296
3297JOW(jboolean, MediaStreamTrack_nativeSetState)(
3298 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003299 MediaStreamTrackInterface::TrackState new_state =
3300 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003301 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3302 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003303}
3304
3305JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3306 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003307 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3308 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003309}
3310
3311JOW(void, VideoTrack_nativeAddRenderer)(
3312 JNIEnv* jni, jclass,
3313 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003314 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003315 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3316}
3317
3318JOW(void, VideoTrack_nativeRemoveRenderer)(
3319 JNIEnv* jni, jclass,
3320 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003321 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003322 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3323}