blob: de1836d9d3e12b41f08920522da017f8b97d9568 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
fischman@webrtc.org33584f92013-07-25 16:43:30 +00003 * Copyright 2013, Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Hints for future visitors:
29// This entire file is an implementation detail of the org.webrtc Java package,
30// the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31// The layout of this file is roughly:
32// - various helper C++ functions & classes that wrap Java counterparts and
33// expose a C++ interface that can be passed to the C++ PeerConnection APIs
34// - implementations of methods declared "static" in the Java package (named
35// things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36// the JNI spec).
37//
38// Lifecycle notes: objects are owned where they will be called; in other words
39// FooObservers are owned by C++-land, and user-callable objects (e.g.
40// PeerConnection and VideoTrack) are owned by Java-land.
41// When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42// ref simulating the jlong held in Java-land, and then Release()s the ref in
43// the respective free call. Sometimes this AddRef is implicit in the
44// construction of a scoped_refptr<> which is then .release()d.
45// Any persistent (non-local) references from C++ to Java must be global or weak
46// (in which case they must be checked before use)!
47//
48// Exception notes: pretty much all JNI calls can throw Java exceptions, so each
49// call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50// call. In this file this is done in CHECK_EXCEPTION, making for much easier
51// debugging in case of failure (the alternative is to wait for control to
52// return to the Java frame that called code in this file, at which point it's
53// impossible to tell which JNI call broke).
54
55#include <jni.h>
56#undef JNIEXPORT
57#define JNIEXPORT __attribute__((visibility("default")))
58
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000059#include <asm/unistd.h>
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000060#include <sys/prctl.h>
61#include <sys/syscall.h>
fischman@webrtc.orgeb7def22013-12-09 21:34:30 +000062#include <unistd.h>
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000063#include <limits>
64#include <map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66#include "talk/app/webrtc/mediaconstraintsinterface.h"
67#include "talk/app/webrtc/peerconnectioninterface.h"
68#include "talk/app/webrtc/videosourceinterface.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069#include "talk/media/base/videocapturer.h"
70#include "talk/media/base/videorenderer.h"
71#include "talk/media/devices/videorendererfactory.h"
72#include "talk/media/webrtc/webrtcvideocapturer.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000073#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000074#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000075#include "third_party/icu/source/common/unicode/unistr.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000076#include "third_party/libyuv/include/libyuv/convert.h"
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +000077#include "third_party/libyuv/include/libyuv/convert_from.h"
78#include "third_party/libyuv/include/libyuv/video_common.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000079#include "webrtc/base/bind.h"
andresp@webrtc.org4d19e052014-09-09 11:45:44 +000080#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000081#include "webrtc/base/logging.h"
82#include "webrtc/base/messagequeue.h"
83#include "webrtc/base/ssladapter.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000084#include "webrtc/common_video/interface/texture_video_frame.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000085#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000086#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000087#include "webrtc/system_wrappers/interface/trace.h"
88#include "webrtc/video_engine/include/vie_base.h"
89#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090
glaznev@webrtc.org99678452014-09-15 17:52:42 +000091#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
92#include <android/log.h>
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000093#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000094#include "webrtc/system_wrappers/interface/tick_util.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000095using webrtc::CodecSpecificInfo;
96using webrtc::DecodedImageCallback;
97using webrtc::EncodedImage;
98using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000099using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000100using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000101using webrtc::TextureVideoFrame;
102using webrtc::TickTime;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000103using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000104#endif
105
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106using icu::UnicodeString;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000107using rtc::Bind;
108using rtc::Thread;
109using rtc::ThreadManager;
110using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111using webrtc::AudioSourceInterface;
112using webrtc::AudioTrackInterface;
113using webrtc::AudioTrackVector;
114using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000115using webrtc::DataBuffer;
116using webrtc::DataChannelInit;
117using webrtc::DataChannelInterface;
118using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119using webrtc::IceCandidateInterface;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000120using webrtc::NativeHandle;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121using webrtc::MediaConstraintsInterface;
122using webrtc::MediaSourceInterface;
123using webrtc::MediaStreamInterface;
124using webrtc::MediaStreamTrackInterface;
125using webrtc::PeerConnectionFactoryInterface;
126using webrtc::PeerConnectionInterface;
127using webrtc::PeerConnectionObserver;
128using webrtc::SessionDescriptionInterface;
129using webrtc::SetSessionDescriptionObserver;
130using webrtc::StatsObserver;
131using webrtc::StatsReport;
132using webrtc::VideoRendererInterface;
133using webrtc::VideoSourceInterface;
134using webrtc::VideoTrackInterface;
135using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000136using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000138// Abort the process if |jni| has a Java exception pending.
139// This macros uses the comma operator to execute ExceptionDescribe
140// and ExceptionClear ignoring their return values and sending ""
141// to the error stream.
142#define CHECK_EXCEPTION(jni) \
143 CHECK(!jni->ExceptionCheck()) \
144 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000146// Helper that calls ptr->Release() and aborts the process with a useful
147// message if that didn't actually delete *ptr because of extra refcounts.
148#define CHECK_RELEASE(ptr) \
149 CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000150
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151namespace {
152
153static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
154
155static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000156// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
157// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
158// were attached by the JVM because of a Java->native call.
159static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000160
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000161#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
162// Set in PeerConnectionFactory_initializeAndroidGlobals().
163static bool factory_static_initialized = false;
164#endif
165
166
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000167// Return thread ID as a string.
168static std::string GetThreadId() {
169 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000170 CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
171 sizeof(buf))
172 << "Thread id is bigger than uint64??";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000173 return std::string(buf);
174}
175
176// Return the current thread's name.
177static std::string GetThreadName() {
178 char name[17];
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000179 CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000180 name[16] = '\0';
181 return std::string(name);
182}
183
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000184// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
185static JNIEnv* GetEnv() {
186 void* env = NULL;
187 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
188 CHECK(((env != NULL) && (status == JNI_OK)) ||
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000189 ((env == NULL) && (status == JNI_EDETACHED)))
190 << "Unexpected GetEnv return: " << status << ":" << env;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000191 return reinterpret_cast<JNIEnv*>(env);
192}
193
194static void ThreadDestructor(void* prev_jni_ptr) {
195 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
196 // we were responsible for originally attaching the thread, so are responsible
197 // for detaching it now. However, because some JVM implementations (notably
198 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
199 // the JVMs accounting info for this thread may already be wiped out by the
200 // time this is called. Thus it may appear we are already detached even though
201 // it was our responsibility to detach! Oh well.
202 if (!GetEnv())
203 return;
204
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000205 CHECK(GetEnv() == prev_jni_ptr)
206 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000207 jint status = g_jvm->DetachCurrentThread();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000208 CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
209 CHECK(!GetEnv()) << "Detaching was a successful no-op???";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210}
211
212static void CreateJNIPtrKey() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000213 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
214 << "pthread_key_create";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215}
216
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000217// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000219 JNIEnv* jni = GetEnv();
220 if (jni)
221 return jni;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000222 CHECK(!pthread_getspecific(g_jni_ptr))
223 << "TLS has a JNIEnv* but not attached?";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000224
225 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
226 JavaVMAttachArgs args;
227 args.version = JNI_VERSION_1_6;
228 args.name = name;
229 args.group = NULL;
230 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000231#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000232 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000233#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000234 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000235#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000236 CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000237 free(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000238 CHECK(env) << "AttachCurrentThread handed back NULL!";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000239 jni = reinterpret_cast<JNIEnv*>(env);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000240 CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000241 return jni;
242}
243
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000244// Return a |jlong| that will correctly convert back to |ptr|. This is needed
245// because the alternative (of silently passing a 32-bit pointer to a vararg
246// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000247static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000248 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000249 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000250 // Going through intptr_t to be obvious about the definedness of the
251 // conversion from pointer to integral type. intptr_t to jlong is a standard
252 // widening by the COMPILE_ASSERT above.
253 jlong ret = reinterpret_cast<intptr_t>(ptr);
254 assert(reinterpret_cast<void*>(ret) == ptr);
255 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000256}
257
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000258// Android's FindClass() is trickier than usual because the app-specific
259// ClassLoader is not consulted when there is no app-specific frame on the
260// stack. Consequently, we only look up classes once in JNI_OnLoad.
261// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
262class ClassReferenceHolder {
263 public:
264 explicit ClassReferenceHolder(JNIEnv* jni) {
265 LoadClass(jni, "java/nio/ByteBuffer");
266 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000267 LoadClass(jni, "org/webrtc/DataChannel");
268 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
269 LoadClass(jni, "org/webrtc/DataChannel$Init");
270 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 LoadClass(jni, "org/webrtc/IceCandidate");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000272#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
273 LoadClass(jni, "android/graphics/SurfaceTexture");
274 LoadClass(jni, "android/opengl/EGLContext");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000275 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
276 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000277 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000278 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000279#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 LoadClass(jni, "org/webrtc/MediaSource$State");
281 LoadClass(jni, "org/webrtc/MediaStream");
282 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000283 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
284 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000285 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 LoadClass(jni, "org/webrtc/SessionDescription");
287 LoadClass(jni, "org/webrtc/SessionDescription$Type");
288 LoadClass(jni, "org/webrtc/StatsReport");
289 LoadClass(jni, "org/webrtc/StatsReport$Value");
290 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
291 LoadClass(jni, "org/webrtc/VideoTrack");
292 }
293
294 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000295 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 }
297
298 void FreeReferences(JNIEnv* jni) {
299 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
300 it != classes_.end(); ++it) {
301 jni->DeleteGlobalRef(it->second);
302 }
303 classes_.clear();
304 }
305
306 jclass GetClass(const std::string& name) {
307 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000308 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309 return it->second;
310 }
311
312 private:
313 void LoadClass(JNIEnv* jni, const std::string& name) {
314 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000315 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
316 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000317 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000318 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
319 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000321 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322 }
323
324 std::map<std::string, jclass> classes_;
325};
326
327// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
328static ClassReferenceHolder* g_class_reference_holder = NULL;
329
330// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
331// object/class/method/field is non-null.
332jmethodID GetMethodID(
333 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
334 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000335 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
336 << signature;
337 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338 return m;
339}
340
341jmethodID GetStaticMethodID(
342 JNIEnv* jni, jclass c, const char* name, const char* signature) {
343 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000344 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
345 << signature;
346 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347 return m;
348}
349
350jfieldID GetFieldID(
351 JNIEnv* jni, jclass c, const char* name, const char* signature) {
352 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000353 CHECK_EXCEPTION(jni) << "error during GetFieldID";
354 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000355 return f;
356}
357
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000358// Returns a global reference guaranteed to be valid for the lifetime of the
359// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000360jclass FindClass(JNIEnv* jni, const char* name) {
361 return g_class_reference_holder->GetClass(name);
362}
363
364jclass GetObjectClass(JNIEnv* jni, jobject object) {
365 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000366 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000367 CHECK(c) << "GetObjectClass returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000368 return c;
369}
370
371jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
372 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000373 CHECK_EXCEPTION(jni) << "error during GetObjectField";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000374 CHECK(o) << "GetObjectField returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000375 return o;
376}
377
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000378jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
379 return static_cast<jstring>(GetObjectField(jni, object, id));
380}
381
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000382jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
383 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000384 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385 return l;
386}
387
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000388jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
389 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000390 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000391 return i;
392}
393
394bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
395 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000396 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000397 return b;
398}
399
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000400jobject NewGlobalRef(JNIEnv* jni, jobject o) {
401 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000402 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
403 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000404 return ret;
405}
406
407void DeleteGlobalRef(JNIEnv* jni, jobject o) {
408 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000409 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410}
411
412// Given a jweak reference, allocate a (strong) local reference scoped to the
413// lifetime of this object if the weak reference is still valid, or NULL
414// otherwise.
415class WeakRef {
416 public:
417 WeakRef(JNIEnv* jni, jweak ref)
418 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000419 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000420 }
421 ~WeakRef() {
422 if (obj_) {
423 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000424 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 }
426 }
427 jobject obj() { return obj_; }
428
429 private:
430 JNIEnv* const jni_;
431 jobject const obj_;
432};
433
fischman@webrtc.org41776152014-01-09 00:31:17 +0000434// Scope Java local references to the lifetime of this object. Use in all C++
435// callbacks (i.e. entry points that don't originate in a Java callstack
436// through a "native" method call).
437class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000439 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000440 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000442 ~ScopedLocalRefFrame() {
443 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000445
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 private:
447 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448};
449
450// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000451template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452class ScopedGlobalRef {
453 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000454 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000455 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456 ~ScopedGlobalRef() {
457 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
458 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000459 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460 return obj_;
461 }
462 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000463 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464};
465
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000466// Java references to "null" can only be distinguished as such in C++ by
467// creating a local reference, so this helper wraps that logic.
468static bool IsNull(JNIEnv* jni, jobject obj) {
469 ScopedLocalRefFrame local_ref_frame(jni);
470 return jni->NewLocalRef(obj) == NULL;
471}
472
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473// Return the (singleton) Java Enum object corresponding to |index|;
474// |state_class_fragment| is something like "MediaSource$State".
475jobject JavaEnumFromIndex(
476 JNIEnv* jni, const std::string& state_class_fragment, int index) {
477 std::string state_class_name = "org/webrtc/" + state_class_fragment;
478 jclass state_class = FindClass(jni, state_class_name.c_str());
479 jmethodID state_values_id = GetStaticMethodID(
480 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000481 jobjectArray state_values = static_cast<jobjectArray>(
482 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000483 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000484 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000485 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000486 return ret;
487}
488
489// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
490static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
491 UnicodeString ustr(UnicodeString::fromUTF8(native));
492 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000493 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000494 return jstr;
495}
496
497// Given a (UTF-16) jstring return a new UTF-8 native string.
498static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
499 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000500 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000502 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000504 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 std::string ret;
506 return ustr.toUTF8String(ret);
507}
508
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000509static DataChannelInit JavaDataChannelInitToNative(
510 JNIEnv* jni, jobject j_init) {
511 DataChannelInit init;
512
513 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
514 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
515 jfieldID max_retransmit_time_id =
516 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
517 jfieldID max_retransmits_id =
518 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
519 jfieldID protocol_id =
520 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
521 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
522 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
523
524 init.ordered = GetBooleanField(jni, j_init, ordered_id);
525 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
526 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
527 init.protocol = JavaToStdString(
528 jni, GetStringField(jni, j_init, protocol_id));
529 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
530 init.id = GetIntField(jni, j_init, id_id);
531
532 return init;
533}
534
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535class ConstraintsWrapper;
536
537// Adapter between the C++ PeerConnectionObserver interface and the Java
538// PeerConnection.Observer interface. Wraps an instance of the Java interface
539// and dispatches C++ callbacks to Java.
540class PCOJava : public PeerConnectionObserver {
541 public:
542 PCOJava(JNIEnv* jni, jobject j_observer)
543 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000544 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
545 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
546 j_media_stream_ctor_(GetMethodID(
547 jni, *j_media_stream_class_, "<init>", "(J)V")),
548 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000550 jni, *j_audio_track_class_, "<init>", "(J)V")),
551 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
552 j_video_track_ctor_(GetMethodID(
553 jni, *j_video_track_class_, "<init>", "(J)V")),
554 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
555 j_data_channel_ctor_(GetMethodID(
556 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 }
558
559 virtual ~PCOJava() {}
560
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000561 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000562 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000563 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000564 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
566 jmethodID ctor = GetMethodID(jni(), candidate_class,
567 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000568 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
569 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
570 jobject j_candidate = jni()->NewObject(
571 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000572 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000573 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000575 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000576 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000577 }
578
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000579 virtual void OnError() OVERRIDE {
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000580 ScopedLocalRefFrame local_ref_frame(jni());
581 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000583 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 }
585
586 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000587 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000588 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000590 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000592 jobject new_state_enum =
593 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
594 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000595 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 }
597
598 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000599 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000600 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000602 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000604 jobject new_state_enum = JavaEnumFromIndex(
605 jni(), "PeerConnection$IceConnectionState", new_state);
606 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000607 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000608 }
609
610 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000611 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000612 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000614 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000616 jobject new_state_enum = JavaEnumFromIndex(
617 jni(), "PeerConnection$IceGatheringState", new_state);
618 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000619 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620 }
621
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000622 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000623 ScopedLocalRefFrame local_ref_frame(jni());
624 jobject j_stream = jni()->NewObject(
625 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000626 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627
628 AudioTrackVector audio_tracks = stream->GetAudioTracks();
629 for (size_t i = 0; i < audio_tracks.size(); ++i) {
630 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000631 jstring id = JavaStringFromStdString(jni(), track->id());
632 jobject j_track = jni()->NewObject(
633 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000634 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000635 jfieldID audio_tracks_id = GetFieldID(jni(),
636 *j_media_stream_class_,
637 "audioTracks",
638 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000639 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000641 GetObjectClass(jni(), audio_tracks),
642 "add",
643 "(Ljava/lang/Object;)Z");
644 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000645 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
646 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000647 }
648
649 VideoTrackVector video_tracks = stream->GetVideoTracks();
650 for (size_t i = 0; i < video_tracks.size(); ++i) {
651 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000652 jstring id = JavaStringFromStdString(jni(), track->id());
653 jobject j_track = jni()->NewObject(
654 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000655 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000656 jfieldID video_tracks_id = GetFieldID(jni(),
657 *j_media_stream_class_,
658 "videoTracks",
659 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000660 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000662 GetObjectClass(jni(), video_tracks),
663 "add",
664 "(Ljava/lang/Object;)Z");
665 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000666 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
667 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000669 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000670 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000672 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
673 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000674 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000675 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000676 }
677
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000678 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000679 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000681 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000682
683 WeakRef s(jni(), it->second);
684 streams_.erase(it);
685 if (!s.obj())
686 return;
687
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000688 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
689 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000691 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 }
693
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000694 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000695 ScopedLocalRefFrame local_ref_frame(jni());
696 jobject j_channel = jni()->NewObject(
697 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000698 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000699
700 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
701 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000702 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000703
704 // Channel is now owned by Java object, and will be freed from
705 // DataChannel.dispose(). Important that this be done _after_ the
706 // CallVoidMethod above as Java code might call back into native code and be
707 // surprised to see a refcount of 2.
708 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000709 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000710
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000711 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000712 }
713
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000714 virtual void OnRenegotiationNeeded() OVERRIDE {
715 ScopedLocalRefFrame local_ref_frame(jni());
716 jmethodID m =
717 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
718 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000719 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000720 }
721
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000723 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 constraints_.reset(constraints);
725 }
726
727 const ConstraintsWrapper* constraints() { return constraints_.get(); }
728
729 private:
730 JNIEnv* jni() {
731 return AttachCurrentThreadIfNeeded();
732 }
733
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000734 const ScopedGlobalRef<jobject> j_observer_global_;
735 const ScopedGlobalRef<jclass> j_observer_class_;
736 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000738 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000740 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000742 const ScopedGlobalRef<jclass> j_data_channel_class_;
743 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
745 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000746 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747};
748
749// Wrapper for a Java MediaConstraints object. Copies all needed data so when
750// the constructor returns the Java object is no longer needed.
751class ConstraintsWrapper : public MediaConstraintsInterface {
752 public:
753 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
754 PopulateConstraintsFromJavaPairList(
755 jni, j_constraints, "mandatory", &mandatory_);
756 PopulateConstraintsFromJavaPairList(
757 jni, j_constraints, "optional", &optional_);
758 }
759
760 virtual ~ConstraintsWrapper() {}
761
762 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000763 virtual const Constraints& GetMandatory() const OVERRIDE {
764 return mandatory_;
765 }
766
767 virtual const Constraints& GetOptional() const OVERRIDE {
768 return optional_;
769 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000770
771 private:
772 // Helper for translating a List<Pair<String, String>> to a Constraints.
773 static void PopulateConstraintsFromJavaPairList(
774 JNIEnv* jni, jobject j_constraints,
775 const char* field_name, Constraints* field) {
776 jfieldID j_id = GetFieldID(jni,
777 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
778 jobject j_list = GetObjectField(jni, j_constraints, j_id);
779 jmethodID j_iterator_id = GetMethodID(jni,
780 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
781 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000782 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000783 jmethodID j_has_next = GetMethodID(jni,
784 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
785 jmethodID j_next = GetMethodID(jni,
786 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
787 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000788 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000790 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 jmethodID get_key = GetMethodID(jni,
792 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
793 jstring j_key = reinterpret_cast<jstring>(
794 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000795 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000796 jmethodID get_value = GetMethodID(jni,
797 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
798 jstring j_value = reinterpret_cast<jstring>(
799 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000800 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000801 field->push_back(Constraint(JavaToStdString(jni, j_key),
802 JavaToStdString(jni, j_value)));
803 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000804 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000805 }
806
807 Constraints mandatory_;
808 Constraints optional_;
809};
810
811static jobject JavaSdpFromNativeSdp(
812 JNIEnv* jni, const SessionDescriptionInterface* desc) {
813 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000814 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000815 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816
817 jclass j_type_class = FindClass(
818 jni, "org/webrtc/SessionDescription$Type");
819 jmethodID j_type_from_canonical = GetStaticMethodID(
820 jni, j_type_class, "fromCanonicalForm",
821 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000822 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000824 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000825 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826
827 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
828 jmethodID j_sdp_ctor = GetMethodID(
829 jni, j_sdp_class, "<init>",
830 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
831 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000832 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000833 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 return j_sdp;
835}
836
837template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
838class SdpObserverWrapper : public T {
839 public:
840 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
841 ConstraintsWrapper* constraints)
842 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000843 j_observer_global_(jni, j_observer),
844 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 }
846
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000847 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000849 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000851 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000852 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
853 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000854 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 }
856
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000857 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000859 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000861 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000863 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
864 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000865 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000866 }
867
868 protected:
869 // Common implementation for failure of Set & Create types, distinguished by
870 // |op| being "Set" or "Create".
871 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000872 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
873 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000874 jstring j_error_string = JavaStringFromStdString(jni(), error);
875 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000876 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 }
878
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879 JNIEnv* jni() {
880 return AttachCurrentThreadIfNeeded();
881 }
882
fischman@webrtc.org41776152014-01-09 00:31:17 +0000883 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000884 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000885 const ScopedGlobalRef<jobject> j_observer_global_;
886 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887};
888
889class CreateSdpObserverWrapper
890 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
891 public:
892 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
893 ConstraintsWrapper* constraints)
894 : SdpObserverWrapper(jni, j_observer, constraints) {}
895
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000896 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000897 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000898 SdpObserverWrapper::OnFailure(std::string("Create"), error);
899 }
900};
901
902class SetSdpObserverWrapper
903 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
904 public:
905 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
906 ConstraintsWrapper* constraints)
907 : SdpObserverWrapper(jni, j_observer, constraints) {}
908
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000909 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000910 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 SdpObserverWrapper::OnFailure(std::string("Set"), error);
912 }
913};
914
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000915// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
916// and dispatching the callback from C++ back to Java.
917class DataChannelObserverWrapper : public DataChannelObserver {
918 public:
919 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
920 : j_observer_global_(jni, j_observer),
921 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000922 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000923 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
924 "onStateChange", "()V")),
925 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
926 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000927 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
928 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
929 }
930
931 virtual ~DataChannelObserverWrapper() {}
932
933 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000934 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000935 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000936 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000937 }
938
939 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000940 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000941 jobject byte_buffer =
942 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
943 buffer.data.length());
944 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
945 byte_buffer, buffer.binary);
946 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000947 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000948 }
949
950 private:
951 JNIEnv* jni() {
952 return AttachCurrentThreadIfNeeded();
953 }
954
955 const ScopedGlobalRef<jobject> j_observer_global_;
956 const ScopedGlobalRef<jclass> j_observer_class_;
957 const ScopedGlobalRef<jclass> j_buffer_class_;
958 const jmethodID j_on_state_change_mid_;
959 const jmethodID j_on_message_mid_;
960 const jmethodID j_buffer_ctor_;
961};
962
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000963// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
964// dispatching the callback from C++ back to Java.
965class StatsObserverWrapper : public StatsObserver {
966 public:
967 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000968 : j_observer_global_(jni, j_observer),
969 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
970 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000971 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000972 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000973 "(Ljava/lang/String;Ljava/lang/String;D"
974 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000975 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000976 jni, "org/webrtc/StatsReport$Value")),
977 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000978 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979 "(Ljava/lang/String;Ljava/lang/String;)V")) {
980 }
981
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000982 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000984 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000985 ScopedLocalRefFrame local_ref_frame(jni());
986 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000987 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
988 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000989 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000990 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000991 }
992
993 private:
994 jobjectArray ReportsToJava(
995 JNIEnv* jni, const std::vector<StatsReport>& reports) {
996 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000997 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000999 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001001 jstring j_id = JavaStringFromStdString(jni, report.id);
1002 jstring j_type = JavaStringFromStdString(jni, report.type);
1003 jobjectArray j_values = ValuesToJava(jni, report.values);
1004 jobject j_report = jni->NewObject(*j_stats_report_class_,
1005 j_stats_report_ctor_,
1006 j_id,
1007 j_type,
1008 report.timestamp,
1009 j_values);
1010 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001011 }
1012 return reports_array;
1013 }
1014
1015 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1016 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001017 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001019 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001021 jstring j_name = JavaStringFromStdString(jni, value.name);
1022 jstring j_value = JavaStringFromStdString(jni, value.value);
1023 jobject j_element_value =
1024 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1025 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001026 }
1027 return j_values;
1028 }
1029
1030 JNIEnv* jni() {
1031 return AttachCurrentThreadIfNeeded();
1032 }
1033
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001034 const ScopedGlobalRef<jobject> j_observer_global_;
1035 const ScopedGlobalRef<jclass> j_observer_class_;
1036 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001038 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 const jmethodID j_value_ctor_;
1040};
1041
1042// Adapter presenting a cricket::VideoRenderer as a
1043// webrtc::VideoRendererInterface.
1044class VideoRendererWrapper : public VideoRendererInterface {
1045 public:
1046 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1047 if (renderer)
1048 return new VideoRendererWrapper(renderer);
1049 return NULL;
1050 }
1051
1052 virtual ~VideoRendererWrapper() {}
1053
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001054 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001055 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001056 const bool kNotReserved = false; // What does this param mean??
1057 renderer_->SetSize(width, height, kNotReserved);
1058 }
1059
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001060 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001061 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001062 renderer_->RenderFrame(frame);
1063 }
1064
1065 private:
1066 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1067 : renderer_(renderer) {}
1068
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001069 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001070};
1071
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001072// Wrapper for texture object in TextureVideoFrame.
1073class NativeHandleImpl : public NativeHandle {
1074 public:
1075 NativeHandleImpl() :
1076 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1077 virtual ~NativeHandleImpl() {}
1078 virtual int32_t AddRef() {
1079 return ++ref_count_;
1080 }
1081 virtual int32_t Release() {
1082 return --ref_count_;
1083 }
1084 virtual void* GetHandle() {
1085 return texture_object_;
1086 }
1087 int GetTextureId() {
1088 return texture_id_;
1089 }
1090 void SetTextureObject(void *texture_object, int texture_id) {
1091 texture_object_ = reinterpret_cast<jobject>(texture_object);
1092 texture_id_ = texture_id;
1093 }
1094 int32_t ref_count() {
1095 return ref_count_;
1096 }
1097
1098 private:
1099 int32_t ref_count_;
1100 jobject texture_object_;
1101 int32_t texture_id_;
1102};
1103
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001104// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1105// instance.
1106class JavaVideoRendererWrapper : public VideoRendererInterface {
1107 public:
1108 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001109 : j_callbacks_(jni, j_callbacks),
1110 j_set_size_id_(GetMethodID(
1111 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1112 j_render_frame_id_(GetMethodID(
1113 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1114 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1115 j_frame_class_(jni,
1116 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001117 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001118 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001119 j_texture_frame_ctor_id_(GetMethodID(
1120 jni, *j_frame_class_, "<init>",
1121 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001122 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001123 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001124 }
1125
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001126 virtual ~JavaVideoRendererWrapper() {}
1127
1128 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001129 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001130 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001131 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 }
1133
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001134 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001135 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001136 if (frame->GetNativeHandle() != NULL) {
1137 jobject j_frame = CricketToJavaTextureFrame(frame);
1138 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1139 CHECK_EXCEPTION(jni());
1140 } else {
1141 jobject j_frame = CricketToJavaI420Frame(frame);
1142 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1143 CHECK_EXCEPTION(jni());
1144 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001145 }
1146
1147 private:
1148 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001149 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001150 jintArray strides = jni()->NewIntArray(3);
1151 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001152 strides_array[0] = frame->GetYPitch();
1153 strides_array[1] = frame->GetUPitch();
1154 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001155 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1156 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1157 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001158 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001159 frame->GetYPitch() * frame->GetHeight());
1160 jobject u_buffer = jni()->NewDirectByteBuffer(
1161 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1162 jobject v_buffer = jni()->NewDirectByteBuffer(
1163 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1164 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1165 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1166 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001167 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001168 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001169 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001170 }
1171
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001172 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1173 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1174 NativeHandleImpl* handle =
1175 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1176 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1177 int texture_id = handle->GetTextureId();
1178 return jni()->NewObject(
1179 *j_frame_class_, j_texture_frame_ctor_id_,
1180 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1181 }
1182
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 JNIEnv* jni() {
1184 return AttachCurrentThreadIfNeeded();
1185 }
1186
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001187 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001188 jmethodID j_set_size_id_;
1189 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001190 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001191 jmethodID j_i420_frame_ctor_id_;
1192 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001193 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194};
1195
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001196#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001197// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1198// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1199// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001200
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001201//#define TRACK_BUFFER_TIMING
1202#define TAG "MediaCodecVideo"
1203#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001204#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1205#else
1206#define ALOGV(...)
1207#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001208#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1209#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001210
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001211// Set to false to switch HW video decoder back to byte buffer output.
1212#define HW_DECODER_USE_SURFACE true
1213
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001214// Color formats supported by encoder - should mirror supportedColorList
1215// from MediaCodecVideoEncoder.java
1216enum COLOR_FORMATTYPE {
1217 COLOR_FormatYUV420Planar = 0x13,
1218 COLOR_FormatYUV420SemiPlanar = 0x15,
1219 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1220 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1221 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1222 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1223 // but requires some (16, 32?) byte alignment.
1224 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1225};
1226
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001227// Arbitrary interval to poll the codec for new outputs.
1228enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001229// Media codec maximum output buffer ready timeout.
1230enum { kMediaCodecTimeoutMs = 500 };
1231// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1232enum { kMediaCodecStatisticsIntervalMs = 3000 };
1233
1234static int64_t GetCurrentTimeMs() {
1235 return TickTime::Now().Ticks() / 1000000LL;
1236}
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001237
1238// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1239// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1240// HW-backed video encode. This C++ class is implemented as a very thin shim,
1241// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1242// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1243// thread, currently the libjingle Worker thread.
1244class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001245 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001246 public:
1247 virtual ~MediaCodecVideoEncoder();
1248 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1249
1250 // webrtc::VideoEncoder implementation. Everything trampolines to
1251 // |codec_thread_| for execution.
1252 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1253 int32_t /* number_of_cores */,
1254 uint32_t /* max_payload_size */) OVERRIDE;
1255 virtual int32_t Encode(
1256 const webrtc::I420VideoFrame& input_image,
1257 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1258 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1259 virtual int32_t RegisterEncodeCompleteCallback(
1260 webrtc::EncodedImageCallback* callback) OVERRIDE;
1261 virtual int32_t Release() OVERRIDE;
1262 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1263 int /* rtt */) OVERRIDE;
1264 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1265
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001266 // rtc::MessageHandler implementation.
1267 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001268
1269 private:
1270 // CHECK-fail if not running on |codec_thread_|.
1271 void CheckOnCodecThread();
1272
1273 // Release() and InitEncode() in an attempt to restore the codec to an
1274 // operable state. Necessary after all manner of OMX-layer errors.
1275 void ResetCodec();
1276
1277 // Implementation of webrtc::VideoEncoder methods above, all running on the
1278 // codec thread exclusively.
1279 //
1280 // If width==0 then this is assumed to be a re-initialization and the
1281 // previously-current values are reused instead of the passed parameters
1282 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001283 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001284 int32_t EncodeOnCodecThread(
1285 const webrtc::I420VideoFrame& input_image,
1286 const std::vector<webrtc::VideoFrameType>* frame_types);
1287 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1288 webrtc::EncodedImageCallback* callback);
1289 int32_t ReleaseOnCodecThread();
1290 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1291
1292 // Reset parameters valid between InitEncode() & Release() (see below).
1293 void ResetParameters(JNIEnv* jni);
1294
1295 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1296 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1297 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1298 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1299 jlong GetOutputBufferInfoPresentationTimestampUs(
1300 JNIEnv* jni,
1301 jobject j_output_buffer_info);
1302
1303 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1304 // true on success.
1305 bool DeliverPendingOutputs(JNIEnv* jni);
1306
1307 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1308 // |codec_thread_| synchronously.
1309 webrtc::EncodedImageCallback* callback_;
1310
1311 // State that is constant for the lifetime of this object once the ctor
1312 // returns.
1313 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1314 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1315 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1316 jmethodID j_init_encode_method_;
1317 jmethodID j_dequeue_input_buffer_method_;
1318 jmethodID j_encode_method_;
1319 jmethodID j_release_method_;
1320 jmethodID j_set_rates_method_;
1321 jmethodID j_dequeue_output_buffer_method_;
1322 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001323 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001324 jfieldID j_info_index_field_;
1325 jfieldID j_info_buffer_field_;
1326 jfieldID j_info_is_key_frame_field_;
1327 jfieldID j_info_presentation_timestamp_us_field_;
1328
1329 // State that is valid only between InitEncode() and the next Release().
1330 // Touched only on codec_thread_ so no explicit synchronization necessary.
1331 int width_; // Frame width in pixels.
1332 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001333 bool inited_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001334 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001335 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001336 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001337 int64_t current_timestamp_us_; // Current frame timestamps in us.
1338 int frames_received_; // Number of frames received by encoder.
1339 int frames_dropped_; // Number of frames dropped by encoder.
1340 int frames_in_queue_; // Number of frames in encoder queue.
1341 int64_t start_time_ms_; // Start time for statistics.
1342 int current_frames_; // Number of frames in the current statistics interval.
1343 int current_bytes_; // Encoded bytes in the current statistics interval.
1344 int current_encoding_time_ms_; // Overall encoding time in the current second
1345 int64_t last_input_timestamp_ms_; // Timestamp of last received yuv frame.
1346 int64_t last_output_timestamp_ms_; // Timestamp of last encoded frame.
1347 std::vector<int32_t> timestamps_; // Video frames timestamp queue.
1348 std::vector<int64_t> render_times_ms_; // Video frames render time queue.
1349 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
1350 // encoder input.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001351 // Frame size in bytes fed to MediaCodec.
1352 int yuv_size_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001353 // True only when between a callback_->Encoded() call return a positive value
1354 // and the next Encode() call being ignored.
1355 bool drop_next_input_frame_;
1356 // Global references; must be deleted in Release().
1357 std::vector<jobject> input_buffers_;
1358};
1359
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001360MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1361 // We depend on ResetParameters() to ensure no more callbacks to us after we
1362 // are deleted, so assert it here.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001363 CHECK(width_ == 0) << "Release() should have been called";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001364}
1365
1366MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1367 : callback_(NULL),
1368 codec_thread_(new Thread()),
1369 j_media_codec_video_encoder_class_(
1370 jni,
1371 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1372 j_media_codec_video_encoder_(
1373 jni,
1374 jni->NewObject(*j_media_codec_video_encoder_class_,
1375 GetMethodID(jni,
1376 *j_media_codec_video_encoder_class_,
1377 "<init>",
1378 "()V"))) {
1379 ScopedLocalRefFrame local_ref_frame(jni);
1380 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1381 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1382 // 2732 means that deadlocks abound. This class synchronously trampolines
1383 // to |codec_thread_|, so if anything else can be coming to _us_ from
1384 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1385 // in the bug, we have a problem. For now work around that with a dedicated
1386 // thread.
1387 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001388 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoEncoder";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001389
1390 ResetParameters(jni);
1391
1392 jclass j_output_buffer_info_class =
1393 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1394 j_init_encode_method_ = GetMethodID(jni,
1395 *j_media_codec_video_encoder_class_,
1396 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001397 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001398 j_dequeue_input_buffer_method_ = GetMethodID(
1399 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1400 j_encode_method_ = GetMethodID(
1401 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1402 j_release_method_ =
1403 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1404 j_set_rates_method_ = GetMethodID(
1405 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1406 j_dequeue_output_buffer_method_ =
1407 GetMethodID(jni,
1408 *j_media_codec_video_encoder_class_,
1409 "dequeueOutputBuffer",
1410 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1411 j_release_output_buffer_method_ = GetMethodID(
1412 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1413
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001414 j_color_format_field_ =
1415 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001416 j_info_index_field_ =
1417 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1418 j_info_buffer_field_ = GetFieldID(
1419 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1420 j_info_is_key_frame_field_ =
1421 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1422 j_info_presentation_timestamp_us_field_ = GetFieldID(
1423 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001424 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001425}
1426
1427int32_t MediaCodecVideoEncoder::InitEncode(
1428 const webrtc::VideoCodec* codec_settings,
1429 int32_t /* number_of_cores */,
1430 uint32_t /* max_payload_size */) {
1431 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001432 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001433
1434 return codec_thread_->Invoke<int32_t>(
1435 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1436 this,
1437 codec_settings->width,
1438 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001439 codec_settings->startBitrate,
1440 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001441}
1442
1443int32_t MediaCodecVideoEncoder::Encode(
1444 const webrtc::I420VideoFrame& frame,
1445 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1446 const std::vector<webrtc::VideoFrameType>* frame_types) {
1447 return codec_thread_->Invoke<int32_t>(Bind(
1448 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1449}
1450
1451int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1452 webrtc::EncodedImageCallback* callback) {
1453 return codec_thread_->Invoke<int32_t>(
1454 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1455 this,
1456 callback));
1457}
1458
1459int32_t MediaCodecVideoEncoder::Release() {
1460 return codec_thread_->Invoke<int32_t>(
1461 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1462}
1463
1464int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1465 int /* rtt */) {
1466 return WEBRTC_VIDEO_CODEC_OK;
1467}
1468
1469int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1470 uint32_t frame_rate) {
1471 return codec_thread_->Invoke<int32_t>(
1472 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1473 this,
1474 new_bit_rate,
1475 frame_rate));
1476}
1477
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001478void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001479 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1480 ScopedLocalRefFrame local_ref_frame(jni);
1481
1482 // We only ever send one message to |this| directly (not through a Bind()'d
1483 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001484 CHECK(!msg->message_id) << "Unexpected message!";
1485 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001486 CheckOnCodecThread();
1487
1488 // It would be nice to recover from a failure here if one happened, but it's
1489 // unclear how to signal such a failure to the app, so instead we stay silent
1490 // about it and let the next app-called API method reveal the borkedness.
1491 DeliverPendingOutputs(jni);
1492 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1493}
1494
1495void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001496 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1497 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001498}
1499
1500void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001501 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001502 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1503 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001504 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0, 0))
1505 != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001506 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1507 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1508 // https://code.google.com/p/webrtc/issues/detail?id=2920
1509 }
1510}
1511
1512int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001513 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001514 CheckOnCodecThread();
1515 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1516 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001517 ALOGD("InitEncodeOnCodecThread %d x %d. Fps: %d", width, height, fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001518
1519 if (width == 0) {
1520 width = width_;
1521 height = height_;
1522 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001523 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001524 }
1525
1526 width_ = width;
1527 height_ = height;
1528 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001529 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001530 yuv_size_ = width_ * height_ * 3 / 2;
1531 frames_received_ = 0;
1532 frames_dropped_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001533 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001534 current_timestamp_us_ = 0;
1535 start_time_ms_ = GetCurrentTimeMs();
1536 current_frames_ = 0;
1537 current_bytes_ = 0;
1538 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001539 last_input_timestamp_ms_ = -1;
1540 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001541 timestamps_.clear();
1542 render_times_ms_.clear();
1543 frame_rtc_times_ms_.clear();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001544 // We enforce no extra stride/padding in the format creation step.
1545 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1546 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1547 j_init_encode_method_,
1548 width_,
1549 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001550 kbps,
1551 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001552 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001553 if (IsNull(jni, input_buffers))
1554 return WEBRTC_VIDEO_CODEC_ERROR;
1555
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001556 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001557 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1558 j_color_format_field_)) {
1559 case COLOR_FormatYUV420Planar:
1560 encoder_fourcc_ = libyuv::FOURCC_YU12;
1561 break;
1562 case COLOR_FormatYUV420SemiPlanar:
1563 case COLOR_QCOM_FormatYUV420SemiPlanar:
1564 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1565 encoder_fourcc_ = libyuv::FOURCC_NV12;
1566 break;
1567 default:
1568 LOG(LS_ERROR) << "Wrong color format.";
1569 return WEBRTC_VIDEO_CODEC_ERROR;
1570 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001571 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001572 CHECK(input_buffers_.empty())
1573 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001574 input_buffers_.resize(num_input_buffers);
1575 for (size_t i = 0; i < num_input_buffers; ++i) {
1576 input_buffers_[i] =
1577 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001578 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001579 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001580 CHECK_EXCEPTION(jni);
1581 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001582 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001583 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001584
1585 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1586 return WEBRTC_VIDEO_CODEC_OK;
1587}
1588
1589int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1590 const webrtc::I420VideoFrame& frame,
1591 const std::vector<webrtc::VideoFrameType>* frame_types) {
1592 CheckOnCodecThread();
1593 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1594 ScopedLocalRefFrame local_ref_frame(jni);
1595
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001596 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001597 if (!DeliverPendingOutputs(jni)) {
1598 ResetCodec();
1599 // Continue as if everything's fine.
1600 }
1601
1602 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001603 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001604 drop_next_input_frame_ = false;
1605 return WEBRTC_VIDEO_CODEC_OK;
1606 }
1607
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001608 CHECK(frame_types->size() == 1) << "Unexpected stream count";
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001609 CHECK(frame.width() == width_) << "Unexpected resolution change";
1610 CHECK(frame.height() == height_) << "Unexpected resolution change";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001611
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001612 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1613
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001614 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001615 // or the encoder latency exceeds 70 ms and drop frame if so.
1616 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001617 int encoder_latency_ms = last_input_timestamp_ms_ -
1618 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001619 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001620 ALOGV("Drop frame - encoder is behind by %d ms. Q size: %d",
1621 encoder_latency_ms, frames_in_queue_);
1622 frames_dropped_++;
1623 return WEBRTC_VIDEO_CODEC_OK;
1624 }
1625 }
1626
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001627 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1628 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001629 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001630 if (j_input_buffer_index == -1) {
1631 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001632 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001633 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001634 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001635 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001636 if (j_input_buffer_index == -2) {
1637 ResetCodec();
1638 return WEBRTC_VIDEO_CODEC_ERROR;
1639 }
1640
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001641 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001642 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001643
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001644 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001645 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001646 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001647 CHECK_EXCEPTION(jni);
1648 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001649 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001650 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1651 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1652 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1653 yuv_buffer, width_,
1654 width_, height_,
1655 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001656 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001657 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001658 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001659
1660 // Save input image timestamps for later output
1661 timestamps_.push_back(frame.timestamp());
1662 render_times_ms_.push_back(frame.render_time_ms());
1663 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1664
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001665 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1666 j_encode_method_,
1667 key_frame,
1668 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001669 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001670 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001671 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001672 current_timestamp_us_ += 1000000 / last_set_fps_;
1673
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001674 if (!encode_status || !DeliverPendingOutputs(jni)) {
1675 ResetCodec();
1676 return WEBRTC_VIDEO_CODEC_ERROR;
1677 }
1678
1679 return WEBRTC_VIDEO_CODEC_OK;
1680}
1681
1682int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1683 webrtc::EncodedImageCallback* callback) {
1684 CheckOnCodecThread();
1685 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1686 ScopedLocalRefFrame local_ref_frame(jni);
1687 callback_ = callback;
1688 return WEBRTC_VIDEO_CODEC_OK;
1689}
1690
1691int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001692 if (!inited_)
1693 return WEBRTC_VIDEO_CODEC_OK;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001694 CheckOnCodecThread();
1695 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001696 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1697 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001698 ScopedLocalRefFrame local_ref_frame(jni);
1699 for (size_t i = 0; i < input_buffers_.size(); ++i)
1700 jni->DeleteGlobalRef(input_buffers_[i]);
1701 input_buffers_.clear();
1702 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1703 ResetParameters(jni);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001704 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001705 return WEBRTC_VIDEO_CODEC_OK;
1706}
1707
1708int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1709 uint32_t frame_rate) {
1710 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001711 if (last_set_bitrate_kbps_ == new_bit_rate &&
1712 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001713 return WEBRTC_VIDEO_CODEC_OK;
1714 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001715 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1716 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001717 if (new_bit_rate > 0) {
1718 last_set_bitrate_kbps_ = new_bit_rate;
1719 }
1720 if (frame_rate > 0) {
1721 last_set_fps_ = frame_rate;
1722 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001723 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1724 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001725 last_set_bitrate_kbps_,
1726 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001727 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001728 if (!ret) {
1729 ResetCodec();
1730 return WEBRTC_VIDEO_CODEC_ERROR;
1731 }
1732 return WEBRTC_VIDEO_CODEC_OK;
1733}
1734
1735void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001736 rtc::MessageQueueManager::Clear(this);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001737 width_ = 0;
1738 height_ = 0;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001739 yuv_size_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001740 drop_next_input_frame_ = false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001741 inited_ = false;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001742 CHECK(input_buffers_.empty())
1743 << "ResetParameters called while holding input_buffers_!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001744}
1745
1746int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1747 JNIEnv* jni,
1748 jobject j_output_buffer_info) {
1749 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1750}
1751
1752jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1753 JNIEnv* jni,
1754 jobject j_output_buffer_info) {
1755 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1756}
1757
1758bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1759 JNIEnv* jni,
1760 jobject j_output_buffer_info) {
1761 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1762}
1763
1764jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1765 JNIEnv* jni,
1766 jobject j_output_buffer_info) {
1767 return GetLongField(
1768 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1769}
1770
1771bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1772 while (true) {
1773 jobject j_output_buffer_info = jni->CallObjectMethod(
1774 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001775 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001776 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001777 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001778 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001779
1780 int output_buffer_index =
1781 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1782 if (output_buffer_index == -1) {
1783 ResetCodec();
1784 return false;
1785 }
1786
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001787 // Get frame timestamps from a queue.
1788 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001789 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1790 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001791 int32_t timestamp = timestamps_.front();
1792 timestamps_.erase(timestamps_.begin());
1793 int64_t render_time_ms = render_times_ms_.front();
1794 render_times_ms_.erase(render_times_ms_.begin());
1795 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1796 frame_rtc_times_ms_.front();
1797 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001798 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001799
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001800 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001801 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001802 jobject j_output_buffer =
1803 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1804 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1805 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1806 uint8* payload = reinterpret_cast<uint8_t*>(
1807 jni->GetDirectBufferAddress(j_output_buffer));
1808 CHECK_EXCEPTION(jni);
1809
1810 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1811 " EncTime: %lld",
1812 output_buffer_index, payload_size, last_output_timestamp_ms_,
1813 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1814 frame_encoding_time_ms);
1815
1816 // Calculate and print encoding statistics - every 3 seconds.
1817 current_frames_++;
1818 current_bytes_ += payload_size;
1819 current_encoding_time_ms_ += frame_encoding_time_ms;
1820 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1821 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1822 current_frames_ > 0) {
1823 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1824 " encTime: %d for last %d ms",
1825 current_bytes_ * 8 / statistic_time_ms,
1826 last_set_bitrate_kbps_,
1827 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1828 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1829 start_time_ms_ = GetCurrentTimeMs();
1830 current_frames_ = 0;
1831 current_bytes_= 0;
1832 current_encoding_time_ms_ = 0;
1833 }
1834
1835 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001836 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001837 scoped_ptr<webrtc::EncodedImage> image(
1838 new webrtc::EncodedImage(payload, payload_size, payload_size));
1839 image->_encodedWidth = width_;
1840 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001841 image->_timeStamp = timestamp;
1842 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001843 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1844 image->_completeFrame = true;
1845
1846 webrtc::CodecSpecificInfo info;
1847 memset(&info, 0, sizeof(info));
1848 info.codecType = kVideoCodecVP8;
1849 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1850 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1851 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1852
1853 // Generate a header describing a single fragment.
1854 webrtc::RTPFragmentationHeader header;
1855 memset(&header, 0, sizeof(header));
1856 header.VerifyAndAllocateFragmentationHeader(1);
1857 header.fragmentationOffset[0] = 0;
1858 header.fragmentationLength[0] = image->_length;
1859 header.fragmentationPlType[0] = 0;
1860 header.fragmentationTimeDiff[0] = 0;
1861
1862 callback_status = callback_->Encoded(*image, &info, &header);
1863 }
1864
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001865 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001866 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1867 j_release_output_buffer_method_,
1868 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001869 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001870 if (!success) {
1871 ResetCodec();
1872 return false;
1873 }
1874
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001875 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001876 drop_next_input_frame_ = true;
1877 // Theoretically could handle callback_status<0 here, but unclear what that
1878 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001879 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001880 }
1881
1882 return true;
1883}
1884
1885// Simplest-possible implementation of an encoder factory, churns out
1886// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1887class MediaCodecVideoEncoderFactory
1888 : public cricket::WebRtcVideoEncoderFactory {
1889 public:
1890 MediaCodecVideoEncoderFactory();
1891 virtual ~MediaCodecVideoEncoderFactory();
1892
1893 // WebRtcVideoEncoderFactory implementation.
1894 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1895 OVERRIDE;
1896 virtual void AddObserver(Observer* observer) OVERRIDE;
1897 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1898 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1899 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1900
1901 private:
1902 // Empty if platform support is lacking, const after ctor returns.
1903 std::vector<VideoCodec> supported_codecs_;
1904};
1905
1906MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1907 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1908 ScopedLocalRefFrame local_ref_frame(jni);
1909 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1910 bool is_platform_supported = jni->CallStaticBooleanMethod(
1911 j_encoder_class,
1912 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001913 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001914 if (!is_platform_supported)
1915 return;
1916
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001917 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1918 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1919 // reasonable defaults.
1920 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001921 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001922}
1923
1924MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1925
1926webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1927 webrtc::VideoCodecType type) {
1928 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1929 return NULL;
1930 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1931}
1932
1933// Since the available codec list is never going to change, we ignore the
1934// Observer-related interface here.
1935void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1936void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1937
1938const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1939MediaCodecVideoEncoderFactory::codecs() const {
1940 return supported_codecs_;
1941}
1942
1943void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1944 webrtc::VideoEncoder* encoder) {
1945 delete encoder;
1946}
1947
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001948class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001949 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001950 public:
1951 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1952 virtual ~MediaCodecVideoDecoder();
1953
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001954 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1955
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001956 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1957 int32_t numberOfCores) OVERRIDE;
1958
1959 virtual int32_t
1960 Decode(const EncodedImage& inputImage, bool missingFrames,
1961 const RTPFragmentationHeader* fragmentation,
1962 const CodecSpecificInfo* codecSpecificInfo = NULL,
1963 int64_t renderTimeMs = -1) OVERRIDE;
1964
1965 virtual int32_t RegisterDecodeCompleteCallback(
1966 DecodedImageCallback* callback) OVERRIDE;
1967
1968 virtual int32_t Release() OVERRIDE;
1969
1970 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001971 // rtc::MessageHandler implementation.
1972 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001973
1974 private:
1975 // CHECK-fail if not running on |codec_thread_|.
1976 void CheckOnCodecThread();
1977
1978 int32_t InitDecodeOnCodecThread();
1979 int32_t ReleaseOnCodecThread();
1980 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001981 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1982 // true on success.
1983 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
1984
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001985
1986 bool key_frame_required_;
1987 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001988 bool use_surface_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001989 VideoCodec codec_;
1990 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001991 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001992 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001993 int frames_received_; // Number of frames received by decoder.
1994 int frames_decoded_; // Number of frames decoded by decoder
1995 int64_t start_time_ms_; // Start time for statistics.
1996 int current_frames_; // Number of frames in the current statistics interval.
1997 int current_bytes_; // Encoded bytes in the current statistics interval.
1998 int current_decoding_time_ms_; // Overall decoding time in the current second
1999 uint32_t max_pending_frames_; // Maximum number of pending input frames
2000 std::vector<int32_t> timestamps_;
2001 std::vector<int64_t> ntp_times_ms_;
2002 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
2003 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002004
2005 // State that is constant for the lifetime of this object once the ctor
2006 // returns.
2007 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
2008 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2009 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2010 jmethodID j_init_decode_method_;
2011 jmethodID j_release_method_;
2012 jmethodID j_dequeue_input_buffer_method_;
2013 jmethodID j_queue_input_buffer_method_;
2014 jmethodID j_dequeue_output_buffer_method_;
2015 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002016 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002017 jfieldID j_input_buffers_field_;
2018 jfieldID j_output_buffers_field_;
2019 jfieldID j_color_format_field_;
2020 jfieldID j_width_field_;
2021 jfieldID j_height_field_;
2022 jfieldID j_stride_field_;
2023 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002024 jfieldID j_surface_texture_field_;
2025 jfieldID j_textureID_field_;
2026 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2027 jfieldID j_info_index_field_;
2028 jfieldID j_info_offset_field_;
2029 jfieldID j_info_size_field_;
2030 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002031
2032 // Global references; must be deleted in Release().
2033 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002034 jobject surface_texture_;
2035
2036 // Render EGL context.
2037 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002038};
2039
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002040jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2041
2042int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2043 jobject render_egl_context) {
2044 if (render_egl_context_) {
2045 jni->DeleteGlobalRef(render_egl_context_);
2046 }
2047 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
2048 ALOGD("VideoDecoder EGL context set");
2049 return 0;
2050}
2051
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002052MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni) :
2053 key_frame_required_(true),
2054 inited_(false),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002055 use_surface_(HW_DECODER_USE_SURFACE),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002056 codec_thread_(new Thread()),
2057 j_media_codec_video_decoder_class_(
2058 jni,
2059 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2060 j_media_codec_video_decoder_(
2061 jni,
2062 jni->NewObject(*j_media_codec_video_decoder_class_,
2063 GetMethodID(jni,
2064 *j_media_codec_video_decoder_class_,
2065 "<init>",
2066 "()V"))) {
2067 ScopedLocalRefFrame local_ref_frame(jni);
2068 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002069 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002070
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002071 j_init_decode_method_ = GetMethodID(
2072 jni, *j_media_codec_video_decoder_class_, "initDecode",
2073 "(IIZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002074 j_release_method_ =
2075 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2076 j_dequeue_input_buffer_method_ = GetMethodID(
2077 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2078 j_queue_input_buffer_method_ = GetMethodID(
2079 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2080 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002081 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2082 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002083 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002084 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002085
2086 j_input_buffers_field_ = GetFieldID(
2087 jni, *j_media_codec_video_decoder_class_,
2088 "inputBuffers", "[Ljava/nio/ByteBuffer;");
2089 j_output_buffers_field_ = GetFieldID(
2090 jni, *j_media_codec_video_decoder_class_,
2091 "outputBuffers", "[Ljava/nio/ByteBuffer;");
2092 j_color_format_field_ = GetFieldID(
2093 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2094 j_width_field_ = GetFieldID(
2095 jni, *j_media_codec_video_decoder_class_, "width", "I");
2096 j_height_field_ = GetFieldID(
2097 jni, *j_media_codec_video_decoder_class_, "height", "I");
2098 j_stride_field_ = GetFieldID(
2099 jni, *j_media_codec_video_decoder_class_, "stride", "I");
2100 j_slice_height_field_ = GetFieldID(
2101 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002102 j_textureID_field_ = GetFieldID(
2103 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2104 j_surface_texture_field_ = GetFieldID(
2105 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2106 "Landroid/graphics/SurfaceTexture;");
2107
2108 jclass j_decoder_output_buffer_info_class = FindClass(jni,
2109 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2110 j_info_index_field_ = GetFieldID(
2111 jni, j_decoder_output_buffer_info_class, "index", "I");
2112 j_info_offset_field_ = GetFieldID(
2113 jni, j_decoder_output_buffer_info_class, "offset", "I");
2114 j_info_size_field_ = GetFieldID(
2115 jni, j_decoder_output_buffer_info_class, "size", "I");
2116 j_info_presentation_timestamp_us_field_ = GetFieldID(
2117 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002118
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002119 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002120 memset(&codec_, 0, sizeof(codec_));
2121}
2122
2123MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
2124 Release();
2125}
2126
2127int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2128 int32_t numberOfCores) {
2129 if (inst == NULL) {
2130 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2131 }
2132 int ret_val = Release();
2133 if (ret_val < 0) {
2134 return ret_val;
2135 }
2136 // Save VideoCodec instance for later.
2137 if (&codec_ != inst) {
2138 codec_ = *inst;
2139 }
2140 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2141
2142 // Always start with a complete key frame.
2143 key_frame_required_ = true;
2144 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002145 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002146
2147 // Call Java init.
2148 return codec_thread_->Invoke<int32_t>(
2149 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2150}
2151
2152int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2153 CheckOnCodecThread();
2154 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2155 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002156 ALOGD("InitDecodeOnCodecThread: %d x %d. fps: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002157 codec_.width, codec_.height, codec_.maxFramerate);
2158
2159 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2160 j_init_decode_method_,
2161 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002162 codec_.height,
2163 use_surface_,
2164 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002165 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002166 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002167 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002168 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002169 inited_ = true;
2170
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002171 max_pending_frames_ = 0;
2172 if (use_surface_) {
2173 max_pending_frames_ = 1;
2174 }
2175 start_time_ms_ = GetCurrentTimeMs();
2176 current_frames_ = 0;
2177 current_bytes_ = 0;
2178 current_decoding_time_ms_ = 0;
2179 timestamps_.clear();
2180 ntp_times_ms_.clear();
2181 frame_rtc_times_ms_.clear();
2182
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002183 jobjectArray input_buffers = (jobjectArray)GetObjectField(
2184 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2185 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002186 input_buffers_.resize(num_input_buffers);
2187 for (size_t i = 0; i < num_input_buffers; ++i) {
2188 input_buffers_[i] =
2189 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002190 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002191 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002192
2193 if (use_surface_) {
2194 jobject surface_texture = GetObjectField(
2195 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
2196 surface_texture_ = jni->NewGlobalRef(surface_texture);
2197 }
2198 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2199
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002200 return WEBRTC_VIDEO_CODEC_OK;
2201}
2202
2203int32_t MediaCodecVideoDecoder::Release() {
2204 return codec_thread_->Invoke<int32_t>(
2205 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2206}
2207
2208int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002209 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002210 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002211 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002212 CheckOnCodecThread();
2213 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2214 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2215 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002216 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002217 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002218 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002219 input_buffers_.clear();
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002220 if (use_surface_) {
2221 // Before deleting texture object make sure it is no longer referenced
2222 // by any TextureVideoFrame.
2223 int32_t waitTimeoutUs = 3000000; // 3 second wait
2224 while (waitTimeoutUs > 0 && native_handle_.ref_count() > 0) {
2225 ALOGD("Current Texture RefCnt: %d", native_handle_.ref_count());
2226 usleep(30000);
2227 waitTimeoutUs -= 30000;
2228 }
2229 ALOGD("TextureRefCnt: %d", native_handle_.ref_count());
2230 jni->DeleteGlobalRef(surface_texture_);
2231 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002232 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002233 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002234 inited_ = false;
2235 return WEBRTC_VIDEO_CODEC_OK;
2236}
2237
2238
2239void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002240 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2241 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002242}
2243
2244int32_t MediaCodecVideoDecoder::Decode(
2245 const EncodedImage& inputImage,
2246 bool missingFrames,
2247 const RTPFragmentationHeader* fragmentation,
2248 const CodecSpecificInfo* codecSpecificInfo,
2249 int64_t renderTimeMs) {
2250 if (!inited_) {
2251 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2252 }
2253 if (callback_ == NULL) {
2254 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2255 }
2256 if (inputImage._buffer == NULL && inputImage._length > 0) {
2257 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2258 }
2259 // Check if encoded frame dimension has changed.
2260 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2261 (inputImage._encodedWidth != codec_.width ||
2262 inputImage._encodedHeight != codec_.height)) {
2263 codec_.width = inputImage._encodedWidth;
2264 codec_.height = inputImage._encodedHeight;
2265 InitDecode(&codec_, 1);
2266 }
2267
2268 // Always start with a complete key frame.
2269 if (key_frame_required_) {
2270 if (inputImage._frameType != webrtc::kKeyFrame) {
2271 return WEBRTC_VIDEO_CODEC_ERROR;
2272 }
2273 if (!inputImage._completeFrame) {
2274 return WEBRTC_VIDEO_CODEC_ERROR;
2275 }
2276 key_frame_required_ = false;
2277 }
2278 if (inputImage._length == 0) {
2279 return WEBRTC_VIDEO_CODEC_ERROR;
2280 }
2281
2282 return codec_thread_->Invoke<int32_t>(Bind(
2283 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2284}
2285
2286int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2287 const EncodedImage& inputImage) {
2288 static uint8_t yVal_ = 0x7f;
2289
2290 CheckOnCodecThread();
2291 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2292 ScopedLocalRefFrame local_ref_frame(jni);
2293
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002294 // Try to drain the decoder and wait until output is not too
2295 // much behind the input.
2296 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2297 ALOGV("Wait for output...");
2298 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
2299 Reset();
2300 return WEBRTC_VIDEO_CODEC_ERROR;
2301 }
2302 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2303 ALOGE("Output buffer dequeue timeout");
2304 Reset();
2305 return WEBRTC_VIDEO_CODEC_ERROR;
2306 }
2307 }
2308
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002309 // Get input buffer.
2310 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2311 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002312 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002313 if (j_input_buffer_index < 0) {
2314 ALOGE("dequeueInputBuffer error");
2315 Reset();
2316 return WEBRTC_VIDEO_CODEC_ERROR;
2317 }
2318
2319 // Copy encoded data to Java ByteBuffer.
2320 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2321 uint8* buffer =
2322 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002323 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002324 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002325 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002326 if (buffer_capacity < inputImage._length) {
2327 ALOGE("Input frame size %d is bigger than buffer size %d.",
2328 inputImage._length, buffer_capacity);
2329 Reset();
2330 return WEBRTC_VIDEO_CODEC_ERROR;
2331 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002332 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002333 frames_received_, j_input_buffer_index, inputImage._length);
2334 memcpy(buffer, inputImage._buffer, inputImage._length);
2335
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002336 // Save input image timestamps for later output.
2337 frames_received_++;
2338 current_bytes_ += inputImage._length;
2339 timestamps_.push_back(inputImage._timeStamp);
2340 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2341 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2342
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002343 // Feed input to decoder.
2344 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2345 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2346 j_queue_input_buffer_method_,
2347 j_input_buffer_index,
2348 inputImage._length,
2349 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002350 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002351 if (!success) {
2352 ALOGE("queueInputBuffer error");
2353 Reset();
2354 return WEBRTC_VIDEO_CODEC_ERROR;
2355 }
2356
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002357 // Try to drain the decoder
2358 if (!DeliverPendingOutputs(jni, 0)) {
2359 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002360 Reset();
2361 return WEBRTC_VIDEO_CODEC_ERROR;
2362 }
2363
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002364 return WEBRTC_VIDEO_CODEC_OK;
2365}
2366
2367bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2368 JNIEnv* jni, int dequeue_timeout_us) {
2369 if (frames_received_ <= frames_decoded_) {
2370 // No need to query for output buffers - decoder is drained.
2371 return true;
2372 }
2373 // Get decoder output.
2374 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2375 *j_media_codec_video_decoder_,
2376 j_dequeue_output_buffer_method_,
2377 dequeue_timeout_us);
2378
2379 CHECK_EXCEPTION(jni);
2380 if (IsNull(jni, j_decoder_output_buffer_info)) {
2381 return true;
2382 }
2383
2384 // Extract data from Java DecoderOutputBufferInfo.
2385 int output_buffer_index =
2386 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2387 if (output_buffer_index < 0) {
2388 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
2389 Reset();
2390 return false;
2391 }
2392 int output_buffer_offset =
2393 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2394 int output_buffer_size =
2395 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2396 CHECK_EXCEPTION(jni);
2397
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002398 // Extract data from Java ByteBuffer.
2399 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2400 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2401 jobject output_buffer =
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002402 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002403 uint8_t* payload =
2404 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(output_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002405 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002406 payload += output_buffer_offset;
2407 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002408 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2409 j_color_format_field_);
2410 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2411 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2412 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2413 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2414 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002415 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2416 j_textureID_field_);
2417 if (!use_surface_ && output_buffer_size < width * height * 3 / 2) {
2418 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002419 Reset();
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002420 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002421 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002422
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002423 // Get frame timestamps from a queue.
2424 int32_t timestamp = timestamps_.front();
2425 timestamps_.erase(timestamps_.begin());
2426 int64_t ntp_time_ms = ntp_times_ms_.front();
2427 ntp_times_ms_.erase(ntp_times_ms_.begin());
2428 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2429 frame_rtc_times_ms_.front();
2430 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2431
2432 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2433 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2434 color_format, output_buffer_size, frame_decoding_time_ms);
2435
2436 // Create yuv420 frame.
2437 if (!use_surface_) {
2438 if (color_format == COLOR_FormatYUV420Planar) {
2439 decoded_image_.CreateFrame(
2440 stride * slice_height, payload,
2441 (stride * slice_height) / 4, payload + (stride * slice_height),
2442 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2443 width, height,
2444 stride, stride / 2, stride / 2);
2445 } else {
2446 // All other supported formats are nv12.
2447 decoded_image_.CreateEmptyFrame(width, height, width,
2448 width / 2, width / 2);
2449 libyuv::NV12ToI420(
2450 payload, stride,
2451 payload + stride * slice_height, stride,
2452 decoded_image_.buffer(webrtc::kYPlane),
2453 decoded_image_.stride(webrtc::kYPlane),
2454 decoded_image_.buffer(webrtc::kUPlane),
2455 decoded_image_.stride(webrtc::kUPlane),
2456 decoded_image_.buffer(webrtc::kVPlane),
2457 decoded_image_.stride(webrtc::kVPlane),
2458 width, height);
2459 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002460 }
2461
2462 // Return output buffer back to codec.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002463 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002464 j_release_output_buffer_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002465 output_buffer_index,
2466 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002467 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002468 if (!success) {
2469 ALOGE("releaseOutputBuffer error");
2470 Reset();
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002471 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002472 }
2473
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002474 // Calculate and print decoding statistics - every 3 seconds.
2475 frames_decoded_++;
2476 current_frames_++;
2477 current_decoding_time_ms_ += frame_decoding_time_ms;
2478 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2479 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2480 current_frames_ > 0) {
2481 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2482 current_bytes_ * 8 / statistic_time_ms,
2483 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2484 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2485 start_time_ms_ = GetCurrentTimeMs();
2486 current_frames_ = 0;
2487 current_bytes_= 0;
2488 current_decoding_time_ms_ = 0;
2489 }
2490
2491 // Callback - output decoded frame.
2492 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2493 if (use_surface_) {
2494 native_handle_.SetTextureObject(surface_texture_, texture_id);
2495 TextureVideoFrame texture_image(
2496 &native_handle_, width, height, timestamp, 0);
2497 texture_image.set_ntp_time_ms(ntp_time_ms);
2498 callback_status = callback_->Decoded(texture_image);
2499 } else {
2500 decoded_image_.set_timestamp(timestamp);
2501 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2502 callback_status = callback_->Decoded(decoded_image_);
2503 }
2504 if (callback_status > 0) {
2505 ALOGE("callback error");
2506 }
2507
2508 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002509}
2510
2511int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2512 DecodedImageCallback* callback) {
2513 callback_ = callback;
2514 return WEBRTC_VIDEO_CODEC_OK;
2515}
2516
2517int32_t MediaCodecVideoDecoder::Reset() {
2518 ALOGD("DecoderReset");
2519 if (!inited_) {
2520 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2521 }
2522 return InitDecode(&codec_, 1);
2523}
2524
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002525void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002526 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2527 ScopedLocalRefFrame local_ref_frame(jni);
2528 if (!inited_) {
2529 return;
2530 }
2531 // We only ever send one message to |this| directly (not through a Bind()'d
2532 // functor), so expect no ID/data.
2533 CHECK(!msg->message_id) << "Unexpected message!";
2534 CHECK(!msg->pdata) << "Unexpected message!";
2535 CheckOnCodecThread();
2536
2537 DeliverPendingOutputs(jni, 0);
2538 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002539}
2540
2541class MediaCodecVideoDecoderFactory
2542 : public cricket::WebRtcVideoDecoderFactory {
2543 public:
2544 MediaCodecVideoDecoderFactory();
2545 virtual ~MediaCodecVideoDecoderFactory();
2546 // WebRtcVideoDecoderFactory implementation.
2547 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2548 webrtc::VideoCodecType type) OVERRIDE;
2549
2550 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2551
2552 private:
2553 bool is_platform_supported_;
2554};
2555
2556MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2557 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2558 ScopedLocalRefFrame local_ref_frame(jni);
2559 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2560 is_platform_supported_ = jni->CallStaticBooleanMethod(
2561 j_decoder_class,
2562 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002563 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002564}
2565
2566MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2567
2568webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2569 webrtc::VideoCodecType type) {
2570 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2571 return NULL;
2572 }
2573 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2574}
2575
2576
2577void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2578 webrtc::VideoDecoder* decoder) {
2579 delete decoder;
2580}
2581
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002582#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002583
2584} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002585
2586// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2587// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2588#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2589 Java_org_webrtc_##name
2590
2591extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002592 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002593 g_jvm = jvm;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002594 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002595
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002596 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002597
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002598 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002599
2600 JNIEnv* jni;
2601 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2602 return -1;
2603 g_class_reference_holder = new ClassReferenceHolder(jni);
2604
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002605 return JNI_VERSION_1_6;
2606}
2607
2608extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002609 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002610 delete g_class_reference_holder;
2611 g_class_reference_holder = NULL;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002612 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002613 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002614}
2615
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002616static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002617 jfieldID native_dc_id = GetFieldID(jni,
2618 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2619 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002620 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002621}
2622
2623JOW(jlong, DataChannel_registerObserverNative)(
2624 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002625 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002626 new DataChannelObserverWrapper(jni, j_observer));
2627 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002628 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002629}
2630
2631JOW(void, DataChannel_unregisterObserverNative)(
2632 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2633 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2634 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2635}
2636
2637JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2638 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2639}
2640
2641JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2642 return JavaEnumFromIndex(
2643 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2644}
2645
2646JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2647 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002648 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2649 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002650 return static_cast<jlong>(buffered_amount);
2651}
2652
2653JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2654 ExtractNativeDC(jni, j_dc)->Close();
2655}
2656
2657JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2658 jbyteArray data, jboolean binary) {
2659 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2660 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002661 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002662 binary));
2663 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2664 return ret;
2665}
2666
2667JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002668 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002669}
2670
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002671JOW(void, Logging_nativeEnableTracing)(
2672 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2673 jint nativeSeverity) {
2674 std::string path = JavaToStdString(jni, j_path);
2675 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002676 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002677#ifdef ANDROID
2678 if (path != "logcat:") {
2679#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002680 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2681 << "SetTraceFile failed";
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002682#ifdef ANDROID
2683 } else {
2684 // Intentionally leak this to avoid needing to reason about its lifecycle.
2685 // It keeps no state and functions only as a dispatch point.
2686 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2687 }
2688#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002689 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002690 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002691}
2692
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002693JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002694 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002695}
2696
2697JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2698 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2699 delete p;
2700}
2701
2702JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002703 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002704}
2705
2706JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2707 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2708}
2709
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002710JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002711 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2712}
2713
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002714JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2715 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2716}
2717
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002718JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002719 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002720}
2721
2722JOW(jboolean, MediaStream_nativeAddAudioTrack)(
2723 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002724 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002725 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002726}
2727
2728JOW(jboolean, MediaStream_nativeAddVideoTrack)(
2729 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002730 return reinterpret_cast<MediaStreamInterface*>(pointer)
2731 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002732}
2733
2734JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2735 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002736 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002737 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002738}
2739
2740JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2741 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002742 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002743 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002744}
2745
2746JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2747 return JavaStringFromStdString(
2748 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2749}
2750
2751JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002752 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002753}
2754
2755JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2756 JNIEnv * jni, jclass, jobject j_observer) {
2757 return (jlong)new PCOJava(jni, j_observer);
2758}
2759
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002760#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002761JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002762 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002763 jboolean initialize_audio, jboolean initialize_video,
2764 jobject render_egl_context) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002765 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002766 bool failure = false;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002767 if (!factory_static_initialized) {
2768 if (initialize_video)
2769 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
2770 if (initialize_audio)
2771 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2772 factory_static_initialized = true;
2773 }
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002774 if (initialize_video)
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002775 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2776 render_egl_context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002777 return !failure;
2778}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002779#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002780
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002781// Helper struct for working around the fact that CreatePeerConnectionFactory()
2782// comes in two flavors: either entirely automagical (constructing its own
2783// threads and deleting them on teardown, but no external codec factory support)
2784// or entirely manual (requires caller to delete threads after factory
2785// teardown). This struct takes ownership of its ctor's arguments to present a
2786// single thing for Java to hold and eventually free.
2787class OwnedFactoryAndThreads {
2788 public:
2789 OwnedFactoryAndThreads(Thread* worker_thread,
2790 Thread* signaling_thread,
2791 PeerConnectionFactoryInterface* factory)
2792 : worker_thread_(worker_thread),
2793 signaling_thread_(signaling_thread),
2794 factory_(factory) {}
2795
2796 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2797
2798 PeerConnectionFactoryInterface* factory() { return factory_; }
2799
2800 private:
2801 const scoped_ptr<Thread> worker_thread_;
2802 const scoped_ptr<Thread> signaling_thread_;
2803 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2804};
2805
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002806JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2807 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002808 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2809 // ThreadManager only WrapCurrentThread()s the thread where it is first
2810 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002811 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002812 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002813 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002814 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002815 Thread* worker_thread = new Thread();
2816 worker_thread->SetName("worker_thread", NULL);
2817 Thread* signaling_thread = new Thread();
2818 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002819 CHECK(worker_thread->Start() && signaling_thread->Start())
2820 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002821 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002822 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002823#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002824 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002825 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002826#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002827 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002828 webrtc::CreatePeerConnectionFactory(worker_thread,
2829 signaling_thread,
2830 NULL,
2831 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002832 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002833 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2834 worker_thread, signaling_thread, factory.release());
2835 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002836}
2837
2838JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002839 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002840 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002841}
2842
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002843static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2844 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2845}
2846
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002847JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2848 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002849 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002850 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002851 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002852 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2853 return (jlong)stream.release();
2854}
2855
2856JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2857 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2858 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002859 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002860 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002861 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002862 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002863 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002864 factory->CreateVideoSource(
2865 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2866 constraints.get()));
2867 return (jlong)source.release();
2868}
2869
2870JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2871 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2872 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002873 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002874 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002875 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002876 factory->CreateVideoTrack(
2877 JavaToStdString(jni, id),
2878 reinterpret_cast<VideoSourceInterface*>(native_source)));
2879 return (jlong)track.release();
2880}
2881
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002882JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2883 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2884 scoped_ptr<ConstraintsWrapper> constraints(
2885 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002886 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002887 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002888 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002889 factory->CreateAudioSource(constraints.get()));
2890 return (jlong)source.release();
2891}
2892
2893JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2894 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2895 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002896 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002897 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002898 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002899 JavaToStdString(jni, id),
2900 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002901 return (jlong)track.release();
2902}
2903
2904static void JavaIceServersToJsepIceServers(
2905 JNIEnv* jni, jobject j_ice_servers,
2906 PeerConnectionInterface::IceServers* ice_servers) {
2907 jclass list_class = GetObjectClass(jni, j_ice_servers);
2908 jmethodID iterator_id = GetMethodID(
2909 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2910 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002911 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002912 jmethodID iterator_has_next = GetMethodID(
2913 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2914 jmethodID iterator_next = GetMethodID(
2915 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2916 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002917 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002918 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002919 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002920 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2921 jfieldID j_ice_server_uri_id =
2922 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2923 jfieldID j_ice_server_username_id =
2924 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2925 jfieldID j_ice_server_password_id =
2926 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2927 jstring uri = reinterpret_cast<jstring>(
2928 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2929 jstring username = reinterpret_cast<jstring>(
2930 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2931 jstring password = reinterpret_cast<jstring>(
2932 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2933 PeerConnectionInterface::IceServer server;
2934 server.uri = JavaToStdString(jni, uri);
2935 server.username = JavaToStdString(jni, username);
2936 server.password = JavaToStdString(jni, password);
2937 ice_servers->push_back(server);
2938 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002939 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002940}
2941
2942JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2943 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2944 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002945 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002946 reinterpret_cast<PeerConnectionFactoryInterface*>(
2947 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002948 PeerConnectionInterface::IceServers servers;
2949 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2950 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2951 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002952 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002953 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002954 return (jlong)pc.release();
2955}
2956
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002957static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002958 JNIEnv* jni, jobject j_pc) {
2959 jfieldID native_pc_id = GetFieldID(jni,
2960 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2961 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002962 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002963 reinterpret_cast<PeerConnectionInterface*>(j_p));
2964}
2965
2966JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2967 const SessionDescriptionInterface* sdp =
2968 ExtractNativePC(jni, j_pc)->local_description();
2969 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2970}
2971
2972JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2973 const SessionDescriptionInterface* sdp =
2974 ExtractNativePC(jni, j_pc)->remote_description();
2975 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2976}
2977
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002978JOW(jobject, PeerConnection_createDataChannel)(
2979 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2980 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002981 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002982 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2983 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002984 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2985 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2986 // 32-bit parameter.
2987 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002988 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002989 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2990 jmethodID j_data_channel_ctor = GetMethodID(
2991 jni, j_data_channel_class, "<init>", "(J)V");
2992 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002993 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002994 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002995 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002996 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002997 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002998 return j_channel;
2999}
3000
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003001JOW(void, PeerConnection_createOffer)(
3002 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3003 ConstraintsWrapper* constraints =
3004 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003005 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3006 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003007 jni, j_observer, constraints));
3008 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3009}
3010
3011JOW(void, PeerConnection_createAnswer)(
3012 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3013 ConstraintsWrapper* constraints =
3014 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003015 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3016 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003017 jni, j_observer, constraints));
3018 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3019}
3020
3021// Helper to create a SessionDescriptionInterface from a SessionDescription.
3022static SessionDescriptionInterface* JavaSdpToNativeSdp(
3023 JNIEnv* jni, jobject j_sdp) {
3024 jfieldID j_type_id = GetFieldID(
3025 jni, GetObjectClass(jni, j_sdp), "type",
3026 "Lorg/webrtc/SessionDescription$Type;");
3027 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3028 jmethodID j_canonical_form_id = GetMethodID(
3029 jni, GetObjectClass(jni, j_type), "canonicalForm",
3030 "()Ljava/lang/String;");
3031 jstring j_type_string = (jstring)jni->CallObjectMethod(
3032 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003033 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003034 std::string std_type = JavaToStdString(jni, j_type_string);
3035
3036 jfieldID j_description_id = GetFieldID(
3037 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3038 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3039 std::string std_description = JavaToStdString(jni, j_description);
3040
3041 return webrtc::CreateSessionDescription(
3042 std_type, std_description, NULL);
3043}
3044
3045JOW(void, PeerConnection_setLocalDescription)(
3046 JNIEnv* jni, jobject j_pc,
3047 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003048 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3049 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003050 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3051 ExtractNativePC(jni, j_pc)->SetLocalDescription(
3052 observer, JavaSdpToNativeSdp(jni, j_sdp));
3053}
3054
3055JOW(void, PeerConnection_setRemoteDescription)(
3056 JNIEnv* jni, jobject j_pc,
3057 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003058 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3059 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003060 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3061 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3062 observer, JavaSdpToNativeSdp(jni, j_sdp));
3063}
3064
3065JOW(jboolean, PeerConnection_updateIce)(
3066 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3067 PeerConnectionInterface::IceServers ice_servers;
3068 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003069 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003070 new ConstraintsWrapper(jni, j_constraints));
3071 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3072}
3073
3074JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3075 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3076 jint j_sdp_mline_index, jstring j_candidate_sdp) {
3077 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3078 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003079 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003080 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3081 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3082}
3083
3084JOW(jboolean, PeerConnection_nativeAddLocalStream)(
3085 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003086 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003087 new ConstraintsWrapper(jni, j_constraints));
3088 return ExtractNativePC(jni, j_pc)->AddStream(
3089 reinterpret_cast<MediaStreamInterface*>(native_stream),
3090 constraints.get());
3091}
3092
3093JOW(void, PeerConnection_nativeRemoveLocalStream)(
3094 JNIEnv* jni, jobject j_pc, jlong native_stream) {
3095 ExtractNativePC(jni, j_pc)->RemoveStream(
3096 reinterpret_cast<MediaStreamInterface*>(native_stream));
3097}
3098
3099JOW(bool, PeerConnection_nativeGetStats)(
3100 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003101 rtc::scoped_refptr<StatsObserverWrapper> observer(
3102 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003103 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00003104 observer,
3105 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3106 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003107}
3108
3109JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3110 PeerConnectionInterface::SignalingState state =
3111 ExtractNativePC(jni, j_pc)->signaling_state();
3112 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3113}
3114
3115JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3116 PeerConnectionInterface::IceConnectionState state =
3117 ExtractNativePC(jni, j_pc)->ice_connection_state();
3118 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3119}
3120
3121JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
3122 PeerConnectionInterface::IceGatheringState state =
3123 ExtractNativePC(jni, j_pc)->ice_gathering_state();
3124 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
3125}
3126
3127JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3128 ExtractNativePC(jni, j_pc)->Close();
3129 return;
3130}
3131
3132JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003133 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003134 reinterpret_cast<MediaSourceInterface*>(j_p));
3135 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3136}
3137
3138JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
3139 JNIEnv* jni, jclass, jstring j_device_name) {
3140 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003141 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003142 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003143 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003144 cricket::Device device;
3145 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003146 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003147 return 0;
3148 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003149 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003150 device_manager->CreateVideoCapturer(device));
3151 return (jlong)capturer.release();
3152}
3153
3154JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3155 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003156 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3157 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003158 return (jlong)renderer.release();
3159}
3160
3161JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3162 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003163 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003164 new JavaVideoRendererWrapper(jni, j_callbacks));
3165 return (jlong)renderer.release();
3166}
3167
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003168JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3169 cricket::VideoCapturer* capturer =
3170 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003171 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003172 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3173 capturer->Stop();
3174 return jlongFromPointer(format.release());
3175}
3176
3177JOW(void, VideoSource_restart)(
3178 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003179 CHECK(j_p_source);
3180 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003181 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003182 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3183 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3184 StartCapturing(cricket::VideoFormat(*format));
3185}
3186
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00003187JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003188 JNIEnv* jni, jclass, jlong j_p) {
3189 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3190}
3191
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003192JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003193 return JavaStringFromStdString(
3194 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003195}
3196
3197JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003198 return JavaStringFromStdString(
3199 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003200}
3201
3202JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003203 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003204}
3205
3206JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003207 return JavaEnumFromIndex(
3208 jni,
3209 "MediaStreamTrack$State",
3210 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003211}
3212
3213JOW(jboolean, MediaStreamTrack_nativeSetState)(
3214 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003215 MediaStreamTrackInterface::TrackState new_state =
3216 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003217 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3218 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003219}
3220
3221JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3222 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003223 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3224 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003225}
3226
3227JOW(void, VideoTrack_nativeAddRenderer)(
3228 JNIEnv* jni, jclass,
3229 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003230 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003231 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3232}
3233
3234JOW(void, VideoTrack_nativeRemoveRenderer)(
3235 JNIEnv* jni, jclass,
3236 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003237 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003238 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3239}