blob: ba540710fa16c8abb7ad931d23b4a9a3eaec357d [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
fischman@webrtc.org33584f92013-07-25 16:43:30 +00003 * Copyright 2013, Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Hints for future visitors:
29// This entire file is an implementation detail of the org.webrtc Java package,
30// the most interesting bits of which are org.webrtc.PeerConnection{,Factory}.
31// The layout of this file is roughly:
32// - various helper C++ functions & classes that wrap Java counterparts and
33// expose a C++ interface that can be passed to the C++ PeerConnection APIs
34// - implementations of methods declared "static" in the Java package (named
35// things like Java_org_webrtc_OMG_Can_This_Name_Be_Any_Longer, prescribed by
36// the JNI spec).
37//
38// Lifecycle notes: objects are owned where they will be called; in other words
39// FooObservers are owned by C++-land, and user-callable objects (e.g.
40// PeerConnection and VideoTrack) are owned by Java-land.
41// When this file allocates C++ RefCountInterfaces it AddRef()s an artificial
42// ref simulating the jlong held in Java-land, and then Release()s the ref in
43// the respective free call. Sometimes this AddRef is implicit in the
44// construction of a scoped_refptr<> which is then .release()d.
45// Any persistent (non-local) references from C++ to Java must be global or weak
46// (in which case they must be checked before use)!
47//
48// Exception notes: pretty much all JNI calls can throw Java exceptions, so each
49// call through a JNIEnv* pointer needs to be followed by an ExceptionCheck()
50// call. In this file this is done in CHECK_EXCEPTION, making for much easier
51// debugging in case of failure (the alternative is to wait for control to
52// return to the Java frame that called code in this file, at which point it's
53// impossible to tell which JNI call broke).
54
55#include <jni.h>
56#undef JNIEXPORT
57#define JNIEXPORT __attribute__((visibility("default")))
58
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000059#include <asm/unistd.h>
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000060#include <sys/prctl.h>
61#include <sys/syscall.h>
fischman@webrtc.orgeb7def22013-12-09 21:34:30 +000062#include <unistd.h>
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000063#include <limits>
64#include <map>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66#include "talk/app/webrtc/mediaconstraintsinterface.h"
67#include "talk/app/webrtc/peerconnectioninterface.h"
68#include "talk/app/webrtc/videosourceinterface.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069#include "talk/media/base/videocapturer.h"
70#include "talk/media/base/videorenderer.h"
71#include "talk/media/devices/videorendererfactory.h"
72#include "talk/media/webrtc/webrtcvideocapturer.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000073#include "talk/media/webrtc/webrtcvideodecoderfactory.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000074#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000075#include "third_party/icu/source/common/unicode/unistr.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000076#include "third_party/libyuv/include/libyuv/convert.h"
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +000077#include "third_party/libyuv/include/libyuv/convert_from.h"
78#include "third_party/libyuv/include/libyuv/video_common.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000079#include "webrtc/base/bind.h"
andresp@webrtc.org4d19e052014-09-09 11:45:44 +000080#include "webrtc/base/checks.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000081#include "webrtc/base/logging.h"
82#include "webrtc/base/messagequeue.h"
83#include "webrtc/base/ssladapter.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000084#include "webrtc/common_video/interface/texture_video_frame.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000085#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000086#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000087#include "webrtc/system_wrappers/interface/trace.h"
88#include "webrtc/video_engine/include/vie_base.h"
89#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090
glaznev@webrtc.org99678452014-09-15 17:52:42 +000091#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
92#include <android/log.h>
andresp@webrtc.org85ef7702014-09-17 11:44:51 +000093#include "webrtc/modules/video_capture/video_capture_internal.h"
94#include "webrtc/modules/video_render/video_render_internal.h"
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000095#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
glaznev@webrtc.org99678452014-09-15 17:52:42 +000096#include "webrtc/system_wrappers/interface/tick_util.h"
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +000097using webrtc::CodecSpecificInfo;
98using webrtc::DecodedImageCallback;
99using webrtc::EncodedImage;
100using webrtc::I420VideoFrame;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000101using webrtc::LogcatTraceContext;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000102using webrtc::RTPFragmentationHeader;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000103using webrtc::TextureVideoFrame;
104using webrtc::TickTime;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000105using webrtc::VideoCodec;
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +0000106#endif
107
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108using icu::UnicodeString;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000109using rtc::Bind;
110using rtc::Thread;
111using rtc::ThreadManager;
112using rtc::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113using webrtc::AudioSourceInterface;
114using webrtc::AudioTrackInterface;
115using webrtc::AudioTrackVector;
116using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000117using webrtc::DataBuffer;
118using webrtc::DataChannelInit;
119using webrtc::DataChannelInterface;
120using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121using webrtc::IceCandidateInterface;
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000122using webrtc::NativeHandle;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123using webrtc::MediaConstraintsInterface;
124using webrtc::MediaSourceInterface;
125using webrtc::MediaStreamInterface;
126using webrtc::MediaStreamTrackInterface;
127using webrtc::PeerConnectionFactoryInterface;
128using webrtc::PeerConnectionInterface;
129using webrtc::PeerConnectionObserver;
130using webrtc::SessionDescriptionInterface;
131using webrtc::SetSessionDescriptionObserver;
132using webrtc::StatsObserver;
133using webrtc::StatsReport;
134using webrtc::VideoRendererInterface;
135using webrtc::VideoSourceInterface;
136using webrtc::VideoTrackInterface;
137using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000138using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000140// Abort the process if |jni| has a Java exception pending.
141// This macros uses the comma operator to execute ExceptionDescribe
142// and ExceptionClear ignoring their return values and sending ""
143// to the error stream.
144#define CHECK_EXCEPTION(jni) \
145 CHECK(!jni->ExceptionCheck()) \
146 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000147
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000148// Helper that calls ptr->Release() and aborts the process with a useful
149// message if that didn't actually delete *ptr because of extra refcounts.
150#define CHECK_RELEASE(ptr) \
151 CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000152
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153namespace {
154
155static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
156
157static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000158// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
159// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
160// were attached by the JVM because of a Java->native call.
161static pthread_key_t g_jni_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000163#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
164// Set in PeerConnectionFactory_initializeAndroidGlobals().
165static bool factory_static_initialized = false;
166#endif
167
168
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000169// Return thread ID as a string.
170static std::string GetThreadId() {
171 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000172 CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
173 sizeof(buf))
174 << "Thread id is bigger than uint64??";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000175 return std::string(buf);
176}
177
178// Return the current thread's name.
179static std::string GetThreadName() {
180 char name[17];
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000181 CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000182 name[16] = '\0';
183 return std::string(name);
184}
185
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000186// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
187static JNIEnv* GetEnv() {
188 void* env = NULL;
189 jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
190 CHECK(((env != NULL) && (status == JNI_OK)) ||
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000191 ((env == NULL) && (status == JNI_EDETACHED)))
192 << "Unexpected GetEnv return: " << status << ":" << env;
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000193 return reinterpret_cast<JNIEnv*>(env);
194}
195
196static void ThreadDestructor(void* prev_jni_ptr) {
197 // This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
198 // we were responsible for originally attaching the thread, so are responsible
199 // for detaching it now. However, because some JVM implementations (notably
200 // Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
201 // the JVMs accounting info for this thread may already be wiped out by the
202 // time this is called. Thus it may appear we are already detached even though
203 // it was our responsibility to detach! Oh well.
204 if (!GetEnv())
205 return;
206
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000207 CHECK(GetEnv() == prev_jni_ptr)
208 << "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209 jint status = g_jvm->DetachCurrentThread();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000210 CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
211 CHECK(!GetEnv()) << "Detaching was a successful no-op???";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212}
213
214static void CreateJNIPtrKey() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000215 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
216 << "pthread_key_create";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000217}
218
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000219// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220static JNIEnv* AttachCurrentThreadIfNeeded() {
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000221 JNIEnv* jni = GetEnv();
222 if (jni)
223 return jni;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000224 CHECK(!pthread_getspecific(g_jni_ptr))
225 << "TLS has a JNIEnv* but not attached?";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000226
227 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
228 JavaVMAttachArgs args;
229 args.version = JNI_VERSION_1_6;
230 args.name = name;
231 args.group = NULL;
232 // Deal with difference in signatures between Oracle's jni.h and Android's.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000233#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000234 void* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000235#else
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000236 JNIEnv* env = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000237#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000238 CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000239 free(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000240 CHECK(env) << "AttachCurrentThread handed back NULL!";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +0000241 jni = reinterpret_cast<JNIEnv*>(env);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000242 CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243 return jni;
244}
245
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000246// Return a |jlong| that will correctly convert back to |ptr|. This is needed
247// because the alternative (of silently passing a 32-bit pointer to a vararg
248// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000249static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000250 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000251 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000252 // Going through intptr_t to be obvious about the definedness of the
253 // conversion from pointer to integral type. intptr_t to jlong is a standard
254 // widening by the COMPILE_ASSERT above.
255 jlong ret = reinterpret_cast<intptr_t>(ptr);
256 assert(reinterpret_cast<void*>(ret) == ptr);
257 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000258}
259
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260// Android's FindClass() is trickier than usual because the app-specific
261// ClassLoader is not consulted when there is no app-specific frame on the
262// stack. Consequently, we only look up classes once in JNI_OnLoad.
263// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
264class ClassReferenceHolder {
265 public:
266 explicit ClassReferenceHolder(JNIEnv* jni) {
267 LoadClass(jni, "java/nio/ByteBuffer");
268 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000269 LoadClass(jni, "org/webrtc/DataChannel");
270 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
271 LoadClass(jni, "org/webrtc/DataChannel$Init");
272 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000273 LoadClass(jni, "org/webrtc/IceCandidate");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000274#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
275 LoadClass(jni, "android/graphics/SurfaceTexture");
276 LoadClass(jni, "android/opengl/EGLContext");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000277 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
278 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +0000279 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000280 LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000281#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000282 LoadClass(jni, "org/webrtc/MediaSource$State");
283 LoadClass(jni, "org/webrtc/MediaStream");
284 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
286 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000287 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288 LoadClass(jni, "org/webrtc/SessionDescription");
289 LoadClass(jni, "org/webrtc/SessionDescription$Type");
290 LoadClass(jni, "org/webrtc/StatsReport");
291 LoadClass(jni, "org/webrtc/StatsReport$Value");
292 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
293 LoadClass(jni, "org/webrtc/VideoTrack");
294 }
295
296 ~ClassReferenceHolder() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000297 CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298 }
299
300 void FreeReferences(JNIEnv* jni) {
301 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
302 it != classes_.end(); ++it) {
303 jni->DeleteGlobalRef(it->second);
304 }
305 classes_.clear();
306 }
307
308 jclass GetClass(const std::string& name) {
309 std::map<std::string, jclass>::iterator it = classes_.find(name);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000310 CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000311 return it->second;
312 }
313
314 private:
315 void LoadClass(JNIEnv* jni, const std::string& name) {
316 jclass localRef = jni->FindClass(name.c_str());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000317 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
318 CHECK(localRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000319 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000320 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
321 CHECK(globalRef) << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000323 CHECK(inserted) << "Duplicate class name: " << name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324 }
325
326 std::map<std::string, jclass> classes_;
327};
328
329// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
330static ClassReferenceHolder* g_class_reference_holder = NULL;
331
332// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
333// object/class/method/field is non-null.
334jmethodID GetMethodID(
335 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
336 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000337 CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
338 << signature;
339 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340 return m;
341}
342
343jmethodID GetStaticMethodID(
344 JNIEnv* jni, jclass c, const char* name, const char* signature) {
345 jmethodID m = jni->GetStaticMethodID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000346 CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
347 << signature;
348 CHECK(m) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 return m;
350}
351
352jfieldID GetFieldID(
353 JNIEnv* jni, jclass c, const char* name, const char* signature) {
354 jfieldID f = jni->GetFieldID(c, name, signature);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000355 CHECK_EXCEPTION(jni) << "error during GetFieldID";
356 CHECK(f) << name << ", " << signature;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000357 return f;
358}
359
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000360// Returns a global reference guaranteed to be valid for the lifetime of the
361// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362jclass FindClass(JNIEnv* jni, const char* name) {
363 return g_class_reference_holder->GetClass(name);
364}
365
366jclass GetObjectClass(JNIEnv* jni, jobject object) {
367 jclass c = jni->GetObjectClass(object);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000368 CHECK_EXCEPTION(jni) << "error during GetObjectClass";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000369 CHECK(c) << "GetObjectClass returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370 return c;
371}
372
373jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
374 jobject o = jni->GetObjectField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000375 CHECK_EXCEPTION(jni) << "error during GetObjectField";
glaznev@webrtc.org99678452014-09-15 17:52:42 +0000376 CHECK(o) << "GetObjectField returned NULL";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000377 return o;
378}
379
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000380jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
381 return static_cast<jstring>(GetObjectField(jni, object, id));
382}
383
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
385 jlong l = jni->GetLongField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000386 CHECK_EXCEPTION(jni) << "error during GetLongField";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 return l;
388}
389
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000390jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
391 jint i = jni->GetIntField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000392 CHECK_EXCEPTION(jni) << "error during GetIntField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000393 return i;
394}
395
396bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
397 jboolean b = jni->GetBooleanField(object, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000398 CHECK_EXCEPTION(jni) << "error during GetBooleanField";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000399 return b;
400}
401
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000402jobject NewGlobalRef(JNIEnv* jni, jobject o) {
403 jobject ret = jni->NewGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000404 CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
405 CHECK(ret);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000406 return ret;
407}
408
409void DeleteGlobalRef(JNIEnv* jni, jobject o) {
410 jni->DeleteGlobalRef(o);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000411 CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000412}
413
414// Given a jweak reference, allocate a (strong) local reference scoped to the
415// lifetime of this object if the weak reference is still valid, or NULL
416// otherwise.
417class WeakRef {
418 public:
419 WeakRef(JNIEnv* jni, jweak ref)
420 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000421 CHECK_EXCEPTION(jni) << "error during NewLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422 }
423 ~WeakRef() {
424 if (obj_) {
425 jni_->DeleteLocalRef(obj_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000426 CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 }
428 }
429 jobject obj() { return obj_; }
430
431 private:
432 JNIEnv* const jni_;
433 jobject const obj_;
434};
435
fischman@webrtc.org41776152014-01-09 00:31:17 +0000436// Scope Java local references to the lifetime of this object. Use in all C++
437// callbacks (i.e. entry points that don't originate in a Java callstack
438// through a "native" method call).
439class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000441 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000442 CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000444 ~ScopedLocalRefFrame() {
445 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000447
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 private:
449 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450};
451
452// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000453template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454class ScopedGlobalRef {
455 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000456 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000457 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458 ~ScopedGlobalRef() {
459 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
460 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000461 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000462 return obj_;
463 }
464 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000465 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000466};
467
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000468// Java references to "null" can only be distinguished as such in C++ by
469// creating a local reference, so this helper wraps that logic.
470static bool IsNull(JNIEnv* jni, jobject obj) {
471 ScopedLocalRefFrame local_ref_frame(jni);
472 return jni->NewLocalRef(obj) == NULL;
473}
474
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475// Return the (singleton) Java Enum object corresponding to |index|;
476// |state_class_fragment| is something like "MediaSource$State".
477jobject JavaEnumFromIndex(
478 JNIEnv* jni, const std::string& state_class_fragment, int index) {
479 std::string state_class_name = "org/webrtc/" + state_class_fragment;
480 jclass state_class = FindClass(jni, state_class_name.c_str());
481 jmethodID state_values_id = GetStaticMethodID(
482 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000483 jobjectArray state_values = static_cast<jobjectArray>(
484 jni->CallStaticObjectMethod(state_class, state_values_id));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000485 CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
fischman@webrtc.org41776152014-01-09 00:31:17 +0000486 jobject ret = jni->GetObjectArrayElement(state_values, index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000487 CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000488 return ret;
489}
490
491// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
492static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
493 UnicodeString ustr(UnicodeString::fromUTF8(native));
494 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000495 CHECK_EXCEPTION(jni) << "error during NewString";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496 return jstr;
497}
498
499// Given a (UTF-16) jstring return a new UTF-8 native string.
500static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
501 const jchar* jchars = jni->GetStringChars(j_string, NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000502 CHECK_EXCEPTION(jni) << "Error during GetStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000504 CHECK_EXCEPTION(jni) << "Error during GetStringLength";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 jni->ReleaseStringChars(j_string, jchars);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000506 CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 std::string ret;
508 return ustr.toUTF8String(ret);
509}
510
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000511static DataChannelInit JavaDataChannelInitToNative(
512 JNIEnv* jni, jobject j_init) {
513 DataChannelInit init;
514
515 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
516 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
517 jfieldID max_retransmit_time_id =
518 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
519 jfieldID max_retransmits_id =
520 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
521 jfieldID protocol_id =
522 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
523 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
524 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
525
526 init.ordered = GetBooleanField(jni, j_init, ordered_id);
527 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
528 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
529 init.protocol = JavaToStdString(
530 jni, GetStringField(jni, j_init, protocol_id));
531 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
532 init.id = GetIntField(jni, j_init, id_id);
533
534 return init;
535}
536
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537class ConstraintsWrapper;
538
539// Adapter between the C++ PeerConnectionObserver interface and the Java
540// PeerConnection.Observer interface. Wraps an instance of the Java interface
541// and dispatches C++ callbacks to Java.
542class PCOJava : public PeerConnectionObserver {
543 public:
544 PCOJava(JNIEnv* jni, jobject j_observer)
545 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000546 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
547 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
548 j_media_stream_ctor_(GetMethodID(
549 jni, *j_media_stream_class_, "<init>", "(J)V")),
550 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000551 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000552 jni, *j_audio_track_class_, "<init>", "(J)V")),
553 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
554 j_video_track_ctor_(GetMethodID(
555 jni, *j_video_track_class_, "<init>", "(J)V")),
556 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
557 j_data_channel_ctor_(GetMethodID(
558 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000559 }
560
561 virtual ~PCOJava() {}
562
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000563 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000564 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000565 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000566 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000567 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
568 jmethodID ctor = GetMethodID(jni(), candidate_class,
569 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000570 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
571 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
572 jobject j_candidate = jni()->NewObject(
573 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000574 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000575 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000577 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000578 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 }
580
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000581 virtual void OnError() OVERRIDE {
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000582 ScopedLocalRefFrame local_ref_frame(jni());
583 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000585 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 }
587
588 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000589 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000590 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000592 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000594 jobject new_state_enum =
595 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
596 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000597 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 }
599
600 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000601 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000602 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000604 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000606 jobject new_state_enum = JavaEnumFromIndex(
607 jni(), "PeerConnection$IceConnectionState", new_state);
608 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000609 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 }
611
612 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000613 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000614 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000616 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000618 jobject new_state_enum = JavaEnumFromIndex(
619 jni(), "PeerConnection$IceGatheringState", new_state);
620 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000621 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 }
623
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000624 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000625 ScopedLocalRefFrame local_ref_frame(jni());
626 jobject j_stream = jni()->NewObject(
627 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000628 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629
630 AudioTrackVector audio_tracks = stream->GetAudioTracks();
631 for (size_t i = 0; i < audio_tracks.size(); ++i) {
632 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000633 jstring id = JavaStringFromStdString(jni(), track->id());
634 jobject j_track = jni()->NewObject(
635 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000636 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000637 jfieldID audio_tracks_id = GetFieldID(jni(),
638 *j_media_stream_class_,
639 "audioTracks",
640 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000641 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000643 GetObjectClass(jni(), audio_tracks),
644 "add",
645 "(Ljava/lang/Object;)Z");
646 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000647 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
648 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 }
650
651 VideoTrackVector video_tracks = stream->GetVideoTracks();
652 for (size_t i = 0; i < video_tracks.size(); ++i) {
653 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000654 jstring id = JavaStringFromStdString(jni(), track->id());
655 jobject j_track = jni()->NewObject(
656 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000657 CHECK_EXCEPTION(jni()) << "error during NewObject";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000658 jfieldID video_tracks_id = GetFieldID(jni(),
659 *j_media_stream_class_,
660 "videoTracks",
661 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000662 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000664 GetObjectClass(jni(), video_tracks),
665 "add",
666 "(Ljava/lang/Object;)Z");
667 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000668 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
669 CHECK(added);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000671 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000672 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000674 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
675 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000676 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000677 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678 }
679
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000680 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000681 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000682 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000683 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684
685 WeakRef s(jni(), it->second);
686 streams_.erase(it);
687 if (!s.obj())
688 return;
689
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000690 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
691 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000693 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694 }
695
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000696 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000697 ScopedLocalRefFrame local_ref_frame(jni());
698 jobject j_channel = jni()->NewObject(
699 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000700 CHECK_EXCEPTION(jni()) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000701
702 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
703 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000704 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000705
706 // Channel is now owned by Java object, and will be freed from
707 // DataChannel.dispose(). Important that this be done _after_ the
708 // CallVoidMethod above as Java code might call back into native code and be
709 // surprised to see a refcount of 2.
710 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000711 CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel";
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000712
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000713 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000714 }
715
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000716 virtual void OnRenegotiationNeeded() OVERRIDE {
717 ScopedLocalRefFrame local_ref_frame(jni());
718 jmethodID m =
719 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
720 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000721 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000722 }
723
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 void SetConstraints(ConstraintsWrapper* constraints) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000725 CHECK(!constraints_.get()) << "constraints already set!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 constraints_.reset(constraints);
727 }
728
729 const ConstraintsWrapper* constraints() { return constraints_.get(); }
730
731 private:
732 JNIEnv* jni() {
733 return AttachCurrentThreadIfNeeded();
734 }
735
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000736 const ScopedGlobalRef<jobject> j_observer_global_;
737 const ScopedGlobalRef<jclass> j_observer_class_;
738 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000740 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000742 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000744 const ScopedGlobalRef<jclass> j_data_channel_class_;
745 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
747 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000748 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749};
750
751// Wrapper for a Java MediaConstraints object. Copies all needed data so when
752// the constructor returns the Java object is no longer needed.
753class ConstraintsWrapper : public MediaConstraintsInterface {
754 public:
755 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
756 PopulateConstraintsFromJavaPairList(
757 jni, j_constraints, "mandatory", &mandatory_);
758 PopulateConstraintsFromJavaPairList(
759 jni, j_constraints, "optional", &optional_);
760 }
761
762 virtual ~ConstraintsWrapper() {}
763
764 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000765 virtual const Constraints& GetMandatory() const OVERRIDE {
766 return mandatory_;
767 }
768
769 virtual const Constraints& GetOptional() const OVERRIDE {
770 return optional_;
771 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772
773 private:
774 // Helper for translating a List<Pair<String, String>> to a Constraints.
775 static void PopulateConstraintsFromJavaPairList(
776 JNIEnv* jni, jobject j_constraints,
777 const char* field_name, Constraints* field) {
778 jfieldID j_id = GetFieldID(jni,
779 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
780 jobject j_list = GetObjectField(jni, j_constraints, j_id);
781 jmethodID j_iterator_id = GetMethodID(jni,
782 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
783 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000784 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 jmethodID j_has_next = GetMethodID(jni,
786 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
787 jmethodID j_next = GetMethodID(jni,
788 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
789 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000790 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000792 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000793 jmethodID get_key = GetMethodID(jni,
794 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
795 jstring j_key = reinterpret_cast<jstring>(
796 jni->CallObjectMethod(entry, get_key));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000797 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000798 jmethodID get_value = GetMethodID(jni,
799 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
800 jstring j_value = reinterpret_cast<jstring>(
801 jni->CallObjectMethod(entry, get_value));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000802 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803 field->push_back(Constraint(JavaToStdString(jni, j_key),
804 JavaToStdString(jni, j_value)));
805 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000806 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 }
808
809 Constraints mandatory_;
810 Constraints optional_;
811};
812
813static jobject JavaSdpFromNativeSdp(
814 JNIEnv* jni, const SessionDescriptionInterface* desc) {
815 std::string sdp;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000816 CHECK(desc->ToString(&sdp)) << "got so far: " << sdp;
fischman@webrtc.org41776152014-01-09 00:31:17 +0000817 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818
819 jclass j_type_class = FindClass(
820 jni, "org/webrtc/SessionDescription$Type");
821 jmethodID j_type_from_canonical = GetStaticMethodID(
822 jni, j_type_class, "fromCanonicalForm",
823 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000824 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000825 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000826 j_type_class, j_type_from_canonical, j_type_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000827 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828
829 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
830 jmethodID j_sdp_ctor = GetMethodID(
831 jni, j_sdp_class, "<init>",
832 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
833 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000834 j_sdp_class, j_sdp_ctor, j_type, j_description);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000835 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000836 return j_sdp;
837}
838
839template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
840class SdpObserverWrapper : public T {
841 public:
842 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
843 ConstraintsWrapper* constraints)
844 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000845 j_observer_global_(jni, j_observer),
846 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000847 }
848
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000849 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000851 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000852 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000853 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000854 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
855 jni()->CallVoidMethod(*j_observer_global_, m);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000856 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000857 }
858
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000859 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000861 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000862 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000863 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000865 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
866 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000867 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868 }
869
870 protected:
871 // Common implementation for failure of Set & Create types, distinguished by
872 // |op| being "Set" or "Create".
873 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000874 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
875 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000876 jstring j_error_string = JavaStringFromStdString(jni(), error);
877 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000878 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000879 }
880
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 JNIEnv* jni() {
882 return AttachCurrentThreadIfNeeded();
883 }
884
fischman@webrtc.org41776152014-01-09 00:31:17 +0000885 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000886 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000887 const ScopedGlobalRef<jobject> j_observer_global_;
888 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000889};
890
891class CreateSdpObserverWrapper
892 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
893 public:
894 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
895 ConstraintsWrapper* constraints)
896 : SdpObserverWrapper(jni, j_observer, constraints) {}
897
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000898 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000899 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900 SdpObserverWrapper::OnFailure(std::string("Create"), error);
901 }
902};
903
904class SetSdpObserverWrapper
905 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
906 public:
907 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
908 ConstraintsWrapper* constraints)
909 : SdpObserverWrapper(jni, j_observer, constraints) {}
910
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000911 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000912 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000913 SdpObserverWrapper::OnFailure(std::string("Set"), error);
914 }
915};
916
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000917// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
918// and dispatching the callback from C++ back to Java.
919class DataChannelObserverWrapper : public DataChannelObserver {
920 public:
921 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
922 : j_observer_global_(jni, j_observer),
923 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000924 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000925 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
926 "onStateChange", "()V")),
927 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
928 "(Lorg/webrtc/DataChannel$Buffer;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000929 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
930 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
931 }
932
933 virtual ~DataChannelObserverWrapper() {}
934
935 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000936 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000937 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000938 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000939 }
940
941 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000942 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000943 jobject byte_buffer =
944 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
945 buffer.data.length());
946 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
947 byte_buffer, buffer.binary);
948 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000949 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000950 }
951
952 private:
953 JNIEnv* jni() {
954 return AttachCurrentThreadIfNeeded();
955 }
956
957 const ScopedGlobalRef<jobject> j_observer_global_;
958 const ScopedGlobalRef<jclass> j_observer_class_;
959 const ScopedGlobalRef<jclass> j_buffer_class_;
960 const jmethodID j_on_state_change_mid_;
961 const jmethodID j_on_message_mid_;
962 const jmethodID j_buffer_ctor_;
963};
964
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000965// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
966// dispatching the callback from C++ back to Java.
967class StatsObserverWrapper : public StatsObserver {
968 public:
969 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000970 : j_observer_global_(jni, j_observer),
971 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
972 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000973 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000974 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000975 "(Ljava/lang/String;Ljava/lang/String;D"
976 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000977 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000978 jni, "org/webrtc/StatsReport$Value")),
979 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000980 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981 "(Ljava/lang/String;Ljava/lang/String;)V")) {
982 }
983
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000984 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000985
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000986 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000987 ScopedLocalRefFrame local_ref_frame(jni());
988 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000989 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
990 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000991 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +0000992 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000993 }
994
995 private:
996 jobjectArray ReportsToJava(
997 JNIEnv* jni, const std::vector<StatsReport>& reports) {
998 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000999 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001001 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001002 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001003 jstring j_id = JavaStringFromStdString(jni, report.id);
1004 jstring j_type = JavaStringFromStdString(jni, report.type);
1005 jobjectArray j_values = ValuesToJava(jni, report.values);
1006 jobject j_report = jni->NewObject(*j_stats_report_class_,
1007 j_stats_report_ctor_,
1008 j_id,
1009 j_type,
1010 report.timestamp,
1011 j_values);
1012 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013 }
1014 return reports_array;
1015 }
1016
1017 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
1018 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001019 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001021 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +00001023 jstring j_name = JavaStringFromStdString(jni, value.name);
1024 jstring j_value = JavaStringFromStdString(jni, value.value);
1025 jobject j_element_value =
1026 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
1027 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001028 }
1029 return j_values;
1030 }
1031
1032 JNIEnv* jni() {
1033 return AttachCurrentThreadIfNeeded();
1034 }
1035
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001036 const ScopedGlobalRef<jobject> j_observer_global_;
1037 const ScopedGlobalRef<jclass> j_observer_class_;
1038 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001039 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001040 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001041 const jmethodID j_value_ctor_;
1042};
1043
1044// Adapter presenting a cricket::VideoRenderer as a
1045// webrtc::VideoRendererInterface.
1046class VideoRendererWrapper : public VideoRendererInterface {
1047 public:
1048 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1049 if (renderer)
1050 return new VideoRendererWrapper(renderer);
1051 return NULL;
1052 }
1053
1054 virtual ~VideoRendererWrapper() {}
1055
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001056 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001057 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001058 const bool kNotReserved = false; // What does this param mean??
1059 renderer_->SetSize(width, height, kNotReserved);
1060 }
1061
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001062 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001063 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064 renderer_->RenderFrame(frame);
1065 }
1066
1067 private:
1068 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1069 : renderer_(renderer) {}
1070
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001071 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072};
1073
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001074// Wrapper for texture object in TextureVideoFrame.
1075class NativeHandleImpl : public NativeHandle {
1076 public:
1077 NativeHandleImpl() :
1078 ref_count_(0), texture_object_(NULL), texture_id_(-1) {}
1079 virtual ~NativeHandleImpl() {}
1080 virtual int32_t AddRef() {
1081 return ++ref_count_;
1082 }
1083 virtual int32_t Release() {
1084 return --ref_count_;
1085 }
1086 virtual void* GetHandle() {
1087 return texture_object_;
1088 }
1089 int GetTextureId() {
1090 return texture_id_;
1091 }
1092 void SetTextureObject(void *texture_object, int texture_id) {
1093 texture_object_ = reinterpret_cast<jobject>(texture_object);
1094 texture_id_ = texture_id;
1095 }
1096 int32_t ref_count() {
1097 return ref_count_;
1098 }
1099
1100 private:
1101 int32_t ref_count_;
1102 jobject texture_object_;
1103 int32_t texture_id_;
1104};
1105
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001106// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1107// instance.
1108class JavaVideoRendererWrapper : public VideoRendererInterface {
1109 public:
1110 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001111 : j_callbacks_(jni, j_callbacks),
1112 j_set_size_id_(GetMethodID(
1113 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1114 j_render_frame_id_(GetMethodID(
1115 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1116 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1117 j_frame_class_(jni,
1118 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001119 j_i420_frame_ctor_id_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001120 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001121 j_texture_frame_ctor_id_(GetMethodID(
1122 jni, *j_frame_class_, "<init>",
1123 "(IILjava/lang/Object;I)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001124 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001125 CHECK_EXCEPTION(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126 }
1127
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001128 virtual ~JavaVideoRendererWrapper() {}
1129
1130 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001131 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001132 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001133 CHECK_EXCEPTION(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134 }
1135
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001136 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001137 ScopedLocalRefFrame local_ref_frame(jni());
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001138 if (frame->GetNativeHandle() != NULL) {
1139 jobject j_frame = CricketToJavaTextureFrame(frame);
1140 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1141 CHECK_EXCEPTION(jni());
1142 } else {
1143 jobject j_frame = CricketToJavaI420Frame(frame);
1144 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
1145 CHECK_EXCEPTION(jni());
1146 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001147 }
1148
1149 private:
1150 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001151 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001152 jintArray strides = jni()->NewIntArray(3);
1153 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001154 strides_array[0] = frame->GetYPitch();
1155 strides_array[1] = frame->GetUPitch();
1156 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001157 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1158 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1159 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001160 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001161 frame->GetYPitch() * frame->GetHeight());
1162 jobject u_buffer = jni()->NewDirectByteBuffer(
1163 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1164 jobject v_buffer = jni()->NewDirectByteBuffer(
1165 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1166 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1167 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1168 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169 return jni()->NewObject(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001170 *j_frame_class_, j_i420_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001171 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001172 }
1173
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001174 // Return a VideoRenderer.I420Frame referring texture object in |frame|.
1175 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) {
1176 NativeHandleImpl* handle =
1177 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle());
1178 jobject texture_object = reinterpret_cast<jobject>(handle->GetHandle());
1179 int texture_id = handle->GetTextureId();
1180 return jni()->NewObject(
1181 *j_frame_class_, j_texture_frame_ctor_id_,
1182 frame->GetWidth(), frame->GetHeight(), texture_object, texture_id);
1183 }
1184
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001185 JNIEnv* jni() {
1186 return AttachCurrentThreadIfNeeded();
1187 }
1188
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001189 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001190 jmethodID j_set_size_id_;
1191 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001192 ScopedGlobalRef<jclass> j_frame_class_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001193 jmethodID j_i420_frame_ctor_id_;
1194 jmethodID j_texture_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001195 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001196};
1197
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001198#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001199// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1200// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1201// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001203//#define TRACK_BUFFER_TIMING
1204#define TAG "MediaCodecVideo"
1205#ifdef TRACK_BUFFER_TIMING
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001206#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
1207#else
1208#define ALOGV(...)
1209#endif
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001210#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
1211#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001212
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001213// Set to false to switch HW video decoder back to byte buffer output.
1214#define HW_DECODER_USE_SURFACE true
1215
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001216// Color formats supported by encoder - should mirror supportedColorList
1217// from MediaCodecVideoEncoder.java
1218enum COLOR_FORMATTYPE {
1219 COLOR_FormatYUV420Planar = 0x13,
1220 COLOR_FormatYUV420SemiPlanar = 0x15,
1221 COLOR_QCOM_FormatYUV420SemiPlanar = 0x7FA30C00,
1222 // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
1223 // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
1224 // This format is presumably similar to COLOR_FormatYUV420SemiPlanar,
1225 // but requires some (16, 32?) byte alignment.
1226 COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04
1227};
1228
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001229// Arbitrary interval to poll the codec for new outputs.
1230enum { kMediaCodecPollMs = 10 };
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001231// Media codec maximum output buffer ready timeout.
1232enum { kMediaCodecTimeoutMs = 500 };
1233// Interval to print codec statistics (bitrate, fps, encoding/decoding time).
1234enum { kMediaCodecStatisticsIntervalMs = 3000 };
1235
1236static int64_t GetCurrentTimeMs() {
1237 return TickTime::Now().Ticks() / 1000000LL;
1238}
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001239
1240// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1241// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1242// HW-backed video encode. This C++ class is implemented as a very thin shim,
1243// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1244// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1245// thread, currently the libjingle Worker thread.
1246class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001247 public rtc::MessageHandler {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001248 public:
1249 virtual ~MediaCodecVideoEncoder();
1250 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1251
1252 // webrtc::VideoEncoder implementation. Everything trampolines to
1253 // |codec_thread_| for execution.
1254 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1255 int32_t /* number_of_cores */,
1256 uint32_t /* max_payload_size */) OVERRIDE;
1257 virtual int32_t Encode(
1258 const webrtc::I420VideoFrame& input_image,
1259 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1260 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1261 virtual int32_t RegisterEncodeCompleteCallback(
1262 webrtc::EncodedImageCallback* callback) OVERRIDE;
1263 virtual int32_t Release() OVERRIDE;
1264 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1265 int /* rtt */) OVERRIDE;
1266 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1267
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001268 // rtc::MessageHandler implementation.
1269 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001270
1271 private:
1272 // CHECK-fail if not running on |codec_thread_|.
1273 void CheckOnCodecThread();
1274
1275 // Release() and InitEncode() in an attempt to restore the codec to an
1276 // operable state. Necessary after all manner of OMX-layer errors.
1277 void ResetCodec();
1278
1279 // Implementation of webrtc::VideoEncoder methods above, all running on the
1280 // codec thread exclusively.
1281 //
1282 // If width==0 then this is assumed to be a re-initialization and the
1283 // previously-current values are reused instead of the passed parameters
1284 // (makes it easier to reason about thread-safety).
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001285 int32_t InitEncodeOnCodecThread(int width, int height, int kbps, int fps);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001286 int32_t EncodeOnCodecThread(
1287 const webrtc::I420VideoFrame& input_image,
1288 const std::vector<webrtc::VideoFrameType>* frame_types);
1289 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1290 webrtc::EncodedImageCallback* callback);
1291 int32_t ReleaseOnCodecThread();
1292 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1293
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001294 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1295 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1296 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1297 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1298 jlong GetOutputBufferInfoPresentationTimestampUs(
1299 JNIEnv* jni,
1300 jobject j_output_buffer_info);
1301
1302 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1303 // true on success.
1304 bool DeliverPendingOutputs(JNIEnv* jni);
1305
1306 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1307 // |codec_thread_| synchronously.
1308 webrtc::EncodedImageCallback* callback_;
1309
1310 // State that is constant for the lifetime of this object once the ctor
1311 // returns.
1312 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1313 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1314 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1315 jmethodID j_init_encode_method_;
1316 jmethodID j_dequeue_input_buffer_method_;
1317 jmethodID j_encode_method_;
1318 jmethodID j_release_method_;
1319 jmethodID j_set_rates_method_;
1320 jmethodID j_dequeue_output_buffer_method_;
1321 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001322 jfieldID j_color_format_field_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001323 jfieldID j_info_index_field_;
1324 jfieldID j_info_buffer_field_;
1325 jfieldID j_info_is_key_frame_field_;
1326 jfieldID j_info_presentation_timestamp_us_field_;
1327
1328 // State that is valid only between InitEncode() and the next Release().
1329 // Touched only on codec_thread_ so no explicit synchronization necessary.
1330 int width_; // Frame width in pixels.
1331 int height_; // Frame height in pixels.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001332 bool inited_;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001333 enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001334 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001335 int last_set_fps_; // Last-requested frame rate.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001336 int64_t current_timestamp_us_; // Current frame timestamps in us.
1337 int frames_received_; // Number of frames received by encoder.
1338 int frames_dropped_; // Number of frames dropped by encoder.
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001339 int frames_resolution_update_; // Number of frames with new codec resolution.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001340 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() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001361 // Call Release() to ensure no more callbacks to us after we are deleted.
1362 Release();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001363}
1364
1365MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001366 : callback_(NULL),
1367 inited_(false),
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"))) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001379 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
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001390 jclass j_output_buffer_info_class =
1391 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1392 j_init_encode_method_ = GetMethodID(jni,
1393 *j_media_codec_video_encoder_class_,
1394 "initEncode",
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001395 "(IIII)[Ljava/nio/ByteBuffer;");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001396 j_dequeue_input_buffer_method_ = GetMethodID(
1397 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1398 j_encode_method_ = GetMethodID(
1399 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1400 j_release_method_ =
1401 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1402 j_set_rates_method_ = GetMethodID(
1403 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1404 j_dequeue_output_buffer_method_ =
1405 GetMethodID(jni,
1406 *j_media_codec_video_encoder_class_,
1407 "dequeueOutputBuffer",
1408 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1409 j_release_output_buffer_method_ = GetMethodID(
1410 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1411
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001412 j_color_format_field_ =
1413 GetFieldID(jni, *j_media_codec_video_encoder_class_, "colorFormat", "I");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001414 j_info_index_field_ =
1415 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1416 j_info_buffer_field_ = GetFieldID(
1417 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1418 j_info_is_key_frame_field_ =
1419 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1420 j_info_presentation_timestamp_us_field_ = GetFieldID(
1421 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001422 CHECK_EXCEPTION(jni) << "MediaCodecVideoEncoder ctor failed";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001423}
1424
1425int32_t MediaCodecVideoEncoder::InitEncode(
1426 const webrtc::VideoCodec* codec_settings,
1427 int32_t /* number_of_cores */,
1428 uint32_t /* max_payload_size */) {
1429 // Factory should guard against other codecs being used with us.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001430 CHECK(codec_settings->codecType == kVideoCodecVP8) << "Unsupported codec";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001431
1432 return codec_thread_->Invoke<int32_t>(
1433 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1434 this,
1435 codec_settings->width,
1436 codec_settings->height,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001437 codec_settings->startBitrate,
1438 codec_settings->maxFramerate));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001439}
1440
1441int32_t MediaCodecVideoEncoder::Encode(
1442 const webrtc::I420VideoFrame& frame,
1443 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1444 const std::vector<webrtc::VideoFrameType>* frame_types) {
1445 return codec_thread_->Invoke<int32_t>(Bind(
1446 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1447}
1448
1449int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1450 webrtc::EncodedImageCallback* callback) {
1451 return codec_thread_->Invoke<int32_t>(
1452 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1453 this,
1454 callback));
1455}
1456
1457int32_t MediaCodecVideoEncoder::Release() {
1458 return codec_thread_->Invoke<int32_t>(
1459 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1460}
1461
1462int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1463 int /* rtt */) {
1464 return WEBRTC_VIDEO_CODEC_OK;
1465}
1466
1467int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1468 uint32_t frame_rate) {
1469 return codec_thread_->Invoke<int32_t>(
1470 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1471 this,
1472 new_bit_rate,
1473 frame_rate));
1474}
1475
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001476void MediaCodecVideoEncoder::OnMessage(rtc::Message* msg) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001477 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1478 ScopedLocalRefFrame local_ref_frame(jni);
1479
1480 // We only ever send one message to |this| directly (not through a Bind()'d
1481 // functor), so expect no ID/data.
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001482 CHECK(!msg->message_id) << "Unexpected message!";
1483 CHECK(!msg->pdata) << "Unexpected message!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001484 CheckOnCodecThread();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001485 if (!inited_) {
1486 return;
1487 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001488
1489 // It would be nice to recover from a failure here if one happened, but it's
1490 // unclear how to signal such a failure to the app, so instead we stay silent
1491 // about it and let the next app-called API method reveal the borkedness.
1492 DeliverPendingOutputs(jni);
1493 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1494}
1495
1496void MediaCodecVideoEncoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001497 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
1498 << "Running on wrong thread!";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001499}
1500
1501void MediaCodecVideoEncoder::ResetCodec() {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001502 ALOGE("ResetCodec");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001503 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1504 codec_thread_->Invoke<int32_t>(Bind(
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001505 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this,
1506 width_, height_, 0, 0)) != WEBRTC_VIDEO_CODEC_OK) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001507 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1508 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1509 // https://code.google.com/p/webrtc/issues/detail?id=2920
1510 }
1511}
1512
1513int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001514 int width, int height, int kbps, int fps) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001515 CheckOnCodecThread();
1516 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1517 ScopedLocalRefFrame local_ref_frame(jni);
1518
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001519 ALOGD("InitEncodeOnCodecThread %d x %d. Bitrate: %d kbps. Fps: %d",
1520 width, height, kbps, fps);
1521 if (kbps == 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001522 kbps = last_set_bitrate_kbps_;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001523 }
1524 if (fps == 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001525 fps = last_set_fps_;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001526 }
1527
1528 width_ = width;
1529 height_ = height;
1530 last_set_bitrate_kbps_ = kbps;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001531 last_set_fps_ = fps;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001532 yuv_size_ = width_ * height_ * 3 / 2;
1533 frames_received_ = 0;
1534 frames_dropped_ = 0;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001535 frames_resolution_update_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001536 frames_in_queue_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001537 current_timestamp_us_ = 0;
1538 start_time_ms_ = GetCurrentTimeMs();
1539 current_frames_ = 0;
1540 current_bytes_ = 0;
1541 current_encoding_time_ms_ = 0;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001542 last_input_timestamp_ms_ = -1;
1543 last_output_timestamp_ms_ = -1;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001544 timestamps_.clear();
1545 render_times_ms_.clear();
1546 frame_rtc_times_ms_.clear();
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001547 drop_next_input_frame_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001548 // We enforce no extra stride/padding in the format creation step.
1549 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1550 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1551 j_init_encode_method_,
1552 width_,
1553 height_,
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001554 kbps,
1555 fps));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001556 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001557 if (IsNull(jni, input_buffers))
1558 return WEBRTC_VIDEO_CODEC_ERROR;
1559
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001560 inited_ = true;
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001561 switch (GetIntField(jni, *j_media_codec_video_encoder_,
1562 j_color_format_field_)) {
1563 case COLOR_FormatYUV420Planar:
1564 encoder_fourcc_ = libyuv::FOURCC_YU12;
1565 break;
1566 case COLOR_FormatYUV420SemiPlanar:
1567 case COLOR_QCOM_FormatYUV420SemiPlanar:
1568 case COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m:
1569 encoder_fourcc_ = libyuv::FOURCC_NV12;
1570 break;
1571 default:
1572 LOG(LS_ERROR) << "Wrong color format.";
1573 return WEBRTC_VIDEO_CODEC_ERROR;
1574 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001575 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001576 CHECK(input_buffers_.empty())
1577 << "Unexpected double InitEncode without Release";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001578 input_buffers_.resize(num_input_buffers);
1579 for (size_t i = 0; i < num_input_buffers; ++i) {
1580 input_buffers_[i] =
1581 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001582 int64 yuv_buffer_capacity =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001583 jni->GetDirectBufferCapacity(input_buffers_[i]);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001584 CHECK_EXCEPTION(jni);
1585 CHECK(yuv_buffer_capacity >= yuv_size_) << "Insufficient capacity";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001586 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001587 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001588
1589 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1590 return WEBRTC_VIDEO_CODEC_OK;
1591}
1592
1593int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1594 const webrtc::I420VideoFrame& frame,
1595 const std::vector<webrtc::VideoFrameType>* frame_types) {
1596 CheckOnCodecThread();
1597 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1598 ScopedLocalRefFrame local_ref_frame(jni);
1599
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001600 if (!inited_) {
1601 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
1602 }
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001603 frames_received_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001604 if (!DeliverPendingOutputs(jni)) {
1605 ResetCodec();
1606 // Continue as if everything's fine.
1607 }
1608
1609 if (drop_next_input_frame_) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001610 ALOGV("Encoder drop frame - failed callback.");
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001611 drop_next_input_frame_ = false;
1612 return WEBRTC_VIDEO_CODEC_OK;
1613 }
1614
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001615 CHECK(frame_types->size() == 1) << "Unexpected stream count";
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001616 if (frame.width() != width_ || frame.height() != height_) {
1617 frames_resolution_update_++;
1618 ALOGD("Unexpected frame resolution change from %d x %d to %d x %d",
1619 width_, height_, frame.width(), frame.height());
1620 if (frames_resolution_update_ > 3) {
1621 // Reset codec if we received more than 3 frames with new resolution.
1622 width_ = frame.width();
1623 height_ = frame.height();
1624 frames_resolution_update_ = 0;
1625 ResetCodec();
1626 }
1627 return WEBRTC_VIDEO_CODEC_OK;
1628 }
1629 frames_resolution_update_ = 0;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001630
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001631 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1632
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001633 // Check if we accumulated too many frames in encoder input buffers
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001634 // or the encoder latency exceeds 70 ms and drop frame if so.
1635 if (frames_in_queue_ > 0 && last_input_timestamp_ms_ >= 0) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001636 int encoder_latency_ms = last_input_timestamp_ms_ -
1637 last_output_timestamp_ms_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001638 if (frames_in_queue_ > 2 || encoder_latency_ms > 70) {
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001639 ALOGV("Drop frame - encoder is behind by %d ms. Q size: %d",
1640 encoder_latency_ms, frames_in_queue_);
1641 frames_dropped_++;
1642 return WEBRTC_VIDEO_CODEC_OK;
1643 }
1644 }
1645
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001646 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1647 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001648 CHECK_EXCEPTION(jni);
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001649 if (j_input_buffer_index == -1) {
1650 // Video codec falls behind - no input buffer available.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001651 ALOGV("Encoder drop frame - no input buffers available");
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001652 frames_dropped_++;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001653 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001654 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001655 if (j_input_buffer_index == -2) {
1656 ResetCodec();
1657 return WEBRTC_VIDEO_CODEC_ERROR;
1658 }
1659
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001660 ALOGV("Encode frame # %d. Buffer # %d. TS: %lld.",
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001661 frames_received_, j_input_buffer_index, current_timestamp_us_ / 1000);
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001662
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001663 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001664 uint8* yuv_buffer =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001665 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001666 CHECK_EXCEPTION(jni);
1667 CHECK(yuv_buffer) << "Indirect buffer??";
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001668 CHECK(!libyuv::ConvertFromI420(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001669 frame.buffer(webrtc::kYPlane), frame.stride(webrtc::kYPlane),
1670 frame.buffer(webrtc::kUPlane), frame.stride(webrtc::kUPlane),
1671 frame.buffer(webrtc::kVPlane), frame.stride(webrtc::kVPlane),
1672 yuv_buffer, width_,
1673 width_, height_,
1674 encoder_fourcc_))
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001675 << "ConvertFromI420 failed";
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001676 last_input_timestamp_ms_ = current_timestamp_us_ / 1000;
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001677 frames_in_queue_++;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001678
1679 // Save input image timestamps for later output
1680 timestamps_.push_back(frame.timestamp());
1681 render_times_ms_.push_back(frame.render_time_ms());
1682 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
1683
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001684 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1685 j_encode_method_,
1686 key_frame,
1687 j_input_buffer_index,
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001688 yuv_size_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001689 current_timestamp_us_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001690 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001691 current_timestamp_us_ += 1000000 / last_set_fps_;
1692
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001693 if (!encode_status || !DeliverPendingOutputs(jni)) {
1694 ResetCodec();
1695 return WEBRTC_VIDEO_CODEC_ERROR;
1696 }
1697
1698 return WEBRTC_VIDEO_CODEC_OK;
1699}
1700
1701int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1702 webrtc::EncodedImageCallback* callback) {
1703 CheckOnCodecThread();
1704 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1705 ScopedLocalRefFrame local_ref_frame(jni);
1706 callback_ = callback;
1707 return WEBRTC_VIDEO_CODEC_OK;
1708}
1709
1710int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001711 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001712 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001713 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001714 CheckOnCodecThread();
1715 JNIEnv* jni = AttachCurrentThreadIfNeeded();
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001716 ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
1717 frames_received_,frames_dropped_);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001718 ScopedLocalRefFrame local_ref_frame(jni);
1719 for (size_t i = 0; i < input_buffers_.size(); ++i)
1720 jni->DeleteGlobalRef(input_buffers_[i]);
1721 input_buffers_.clear();
1722 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001723 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00001724 rtc::MessageQueueManager::Clear(this);
1725 inited_ = false;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001726 return WEBRTC_VIDEO_CODEC_OK;
1727}
1728
1729int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1730 uint32_t frame_rate) {
1731 CheckOnCodecThread();
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001732 if (last_set_bitrate_kbps_ == new_bit_rate &&
1733 last_set_fps_ == frame_rate) {
glaznev@webrtc.orga40210a2014-06-10 23:48:29 +00001734 return WEBRTC_VIDEO_CODEC_OK;
1735 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001736 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1737 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001738 if (new_bit_rate > 0) {
1739 last_set_bitrate_kbps_ = new_bit_rate;
1740 }
1741 if (frame_rate > 0) {
1742 last_set_fps_ = frame_rate;
1743 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001744 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1745 j_set_rates_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001746 last_set_bitrate_kbps_,
1747 last_set_fps_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001748 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001749 if (!ret) {
1750 ResetCodec();
1751 return WEBRTC_VIDEO_CODEC_ERROR;
1752 }
1753 return WEBRTC_VIDEO_CODEC_OK;
1754}
1755
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001756int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1757 JNIEnv* jni,
1758 jobject j_output_buffer_info) {
1759 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1760}
1761
1762jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1763 JNIEnv* jni,
1764 jobject j_output_buffer_info) {
1765 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1766}
1767
1768bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1769 JNIEnv* jni,
1770 jobject j_output_buffer_info) {
1771 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1772}
1773
1774jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1775 JNIEnv* jni,
1776 jobject j_output_buffer_info) {
1777 return GetLongField(
1778 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1779}
1780
1781bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1782 while (true) {
1783 jobject j_output_buffer_info = jni->CallObjectMethod(
1784 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001785 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001786 if (IsNull(jni, j_output_buffer_info)) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001787 break;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001788 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001789
1790 int output_buffer_index =
1791 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1792 if (output_buffer_index == -1) {
1793 ResetCodec();
1794 return false;
1795 }
1796
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001797 // Get frame timestamps from a queue.
1798 last_output_timestamp_ms_ =
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001799 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1800 1000;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001801 int32_t timestamp = timestamps_.front();
1802 timestamps_.erase(timestamps_.begin());
1803 int64_t render_time_ms = render_times_ms_.front();
1804 render_times_ms_.erase(render_times_ms_.begin());
1805 int64_t frame_encoding_time_ms = GetCurrentTimeMs() -
1806 frame_rtc_times_ms_.front();
1807 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
glaznev@webrtc.orgc6c1dfd2014-06-13 22:59:08 +00001808 frames_in_queue_--;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001809
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001810 // Extract payload and key frame flag.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001811 int32_t callback_status = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001812 jobject j_output_buffer =
1813 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1814 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1815 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1816 uint8* payload = reinterpret_cast<uint8_t*>(
1817 jni->GetDirectBufferAddress(j_output_buffer));
1818 CHECK_EXCEPTION(jni);
1819
1820 ALOGV("Encoder got output buffer # %d. Size: %d. TS: %lld. Latency: %lld."
1821 " EncTime: %lld",
1822 output_buffer_index, payload_size, last_output_timestamp_ms_,
1823 last_input_timestamp_ms_ - last_output_timestamp_ms_,
1824 frame_encoding_time_ms);
1825
1826 // Calculate and print encoding statistics - every 3 seconds.
1827 current_frames_++;
1828 current_bytes_ += payload_size;
1829 current_encoding_time_ms_ += frame_encoding_time_ms;
1830 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
1831 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
1832 current_frames_ > 0) {
1833 ALOGD("Encoder bitrate: %d, target: %d kbps, fps: %d,"
1834 " encTime: %d for last %d ms",
1835 current_bytes_ * 8 / statistic_time_ms,
1836 last_set_bitrate_kbps_,
1837 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
1838 current_encoding_time_ms_ / current_frames_, statistic_time_ms);
1839 start_time_ms_ = GetCurrentTimeMs();
1840 current_frames_ = 0;
1841 current_bytes_= 0;
1842 current_encoding_time_ms_ = 0;
1843 }
1844
1845 // Callback - return encoded frame.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001846 if (callback_) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001847 scoped_ptr<webrtc::EncodedImage> image(
1848 new webrtc::EncodedImage(payload, payload_size, payload_size));
1849 image->_encodedWidth = width_;
1850 image->_encodedHeight = height_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001851 image->_timeStamp = timestamp;
1852 image->capture_time_ms_ = render_time_ms;
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001853 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1854 image->_completeFrame = true;
1855
1856 webrtc::CodecSpecificInfo info;
1857 memset(&info, 0, sizeof(info));
1858 info.codecType = kVideoCodecVP8;
1859 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1860 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1861 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1862
1863 // Generate a header describing a single fragment.
1864 webrtc::RTPFragmentationHeader header;
1865 memset(&header, 0, sizeof(header));
1866 header.VerifyAndAllocateFragmentationHeader(1);
1867 header.fragmentationOffset[0] = 0;
1868 header.fragmentationLength[0] = image->_length;
1869 header.fragmentationPlType[0] = 0;
1870 header.fragmentationTimeDiff[0] = 0;
1871
1872 callback_status = callback_->Encoded(*image, &info, &header);
1873 }
1874
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001875 // Return output buffer back to the encoder.
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001876 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1877 j_release_output_buffer_method_,
1878 output_buffer_index);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001879 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001880 if (!success) {
1881 ResetCodec();
1882 return false;
1883 }
1884
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001885 if (callback_status > 0) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001886 drop_next_input_frame_ = true;
1887 // Theoretically could handle callback_status<0 here, but unclear what that
1888 // would mean for us.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001889 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001890 }
1891
1892 return true;
1893}
1894
1895// Simplest-possible implementation of an encoder factory, churns out
1896// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1897class MediaCodecVideoEncoderFactory
1898 : public cricket::WebRtcVideoEncoderFactory {
1899 public:
1900 MediaCodecVideoEncoderFactory();
1901 virtual ~MediaCodecVideoEncoderFactory();
1902
1903 // WebRtcVideoEncoderFactory implementation.
1904 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1905 OVERRIDE;
1906 virtual void AddObserver(Observer* observer) OVERRIDE;
1907 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1908 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1909 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1910
1911 private:
1912 // Empty if platform support is lacking, const after ctor returns.
1913 std::vector<VideoCodec> supported_codecs_;
1914};
1915
1916MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1917 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1918 ScopedLocalRefFrame local_ref_frame(jni);
1919 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1920 bool is_platform_supported = jni->CallStaticBooleanMethod(
1921 j_encoder_class,
1922 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00001923 CHECK_EXCEPTION(jni);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001924 if (!is_platform_supported)
1925 return;
1926
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001927 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1928 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1929 // reasonable defaults.
1930 supported_codecs_.push_back(
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001931 VideoCodec(kVideoCodecVP8, "VP8", 1280, 1280, 30));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001932}
1933
1934MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1935
1936webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1937 webrtc::VideoCodecType type) {
1938 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1939 return NULL;
1940 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1941}
1942
1943// Since the available codec list is never going to change, we ignore the
1944// Observer-related interface here.
1945void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1946void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1947
1948const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1949MediaCodecVideoEncoderFactory::codecs() const {
1950 return supported_codecs_;
1951}
1952
1953void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1954 webrtc::VideoEncoder* encoder) {
1955 delete encoder;
1956}
1957
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001958class MediaCodecVideoDecoder : public webrtc::VideoDecoder,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001959 public rtc::MessageHandler {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001960 public:
1961 explicit MediaCodecVideoDecoder(JNIEnv* jni);
1962 virtual ~MediaCodecVideoDecoder();
1963
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001964 static int SetAndroidObjects(JNIEnv* jni, jobject render_egl_context);
1965
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001966 virtual int32_t InitDecode(const VideoCodec* codecSettings,
1967 int32_t numberOfCores) OVERRIDE;
1968
1969 virtual int32_t
1970 Decode(const EncodedImage& inputImage, bool missingFrames,
1971 const RTPFragmentationHeader* fragmentation,
1972 const CodecSpecificInfo* codecSpecificInfo = NULL,
1973 int64_t renderTimeMs = -1) OVERRIDE;
1974
1975 virtual int32_t RegisterDecodeCompleteCallback(
1976 DecodedImageCallback* callback) OVERRIDE;
1977
1978 virtual int32_t Release() OVERRIDE;
1979
1980 virtual int32_t Reset() OVERRIDE;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001981 // rtc::MessageHandler implementation.
1982 virtual void OnMessage(rtc::Message* msg) OVERRIDE;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001983
1984 private:
1985 // CHECK-fail if not running on |codec_thread_|.
1986 void CheckOnCodecThread();
1987
1988 int32_t InitDecodeOnCodecThread();
1989 int32_t ReleaseOnCodecThread();
1990 int32_t DecodeOnCodecThread(const EncodedImage& inputImage);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001991 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1992 // true on success.
1993 bool DeliverPendingOutputs(JNIEnv* jni, int dequeue_timeout_us);
1994
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001995
1996 bool key_frame_required_;
1997 bool inited_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00001998 bool use_surface_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00001999 VideoCodec codec_;
2000 I420VideoFrame decoded_image_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002001 NativeHandleImpl native_handle_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002002 DecodedImageCallback* callback_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002003 int frames_received_; // Number of frames received by decoder.
2004 int frames_decoded_; // Number of frames decoded by decoder
2005 int64_t start_time_ms_; // Start time for statistics.
2006 int current_frames_; // Number of frames in the current statistics interval.
2007 int current_bytes_; // Encoded bytes in the current statistics interval.
2008 int current_decoding_time_ms_; // Overall decoding time in the current second
2009 uint32_t max_pending_frames_; // Maximum number of pending input frames
2010 std::vector<int32_t> timestamps_;
2011 std::vector<int64_t> ntp_times_ms_;
2012 std::vector<int64_t> frame_rtc_times_ms_; // Time when video frame is sent to
2013 // decoder input.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002014
2015 // State that is constant for the lifetime of this object once the ctor
2016 // returns.
2017 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
2018 ScopedGlobalRef<jclass> j_media_codec_video_decoder_class_;
2019 ScopedGlobalRef<jobject> j_media_codec_video_decoder_;
2020 jmethodID j_init_decode_method_;
2021 jmethodID j_release_method_;
2022 jmethodID j_dequeue_input_buffer_method_;
2023 jmethodID j_queue_input_buffer_method_;
2024 jmethodID j_dequeue_output_buffer_method_;
2025 jmethodID j_release_output_buffer_method_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002026 // MediaCodecVideoDecoder fields.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002027 jfieldID j_input_buffers_field_;
2028 jfieldID j_output_buffers_field_;
2029 jfieldID j_color_format_field_;
2030 jfieldID j_width_field_;
2031 jfieldID j_height_field_;
2032 jfieldID j_stride_field_;
2033 jfieldID j_slice_height_field_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002034 jfieldID j_surface_texture_field_;
2035 jfieldID j_textureID_field_;
2036 // MediaCodecVideoDecoder.DecoderOutputBufferInfo fields.
2037 jfieldID j_info_index_field_;
2038 jfieldID j_info_offset_field_;
2039 jfieldID j_info_size_field_;
2040 jfieldID j_info_presentation_timestamp_us_field_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002041
2042 // Global references; must be deleted in Release().
2043 std::vector<jobject> input_buffers_;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002044 jobject surface_texture_;
2045
2046 // Render EGL context.
2047 static jobject render_egl_context_;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002048};
2049
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002050jobject MediaCodecVideoDecoder::render_egl_context_ = NULL;
2051
2052int MediaCodecVideoDecoder::SetAndroidObjects(JNIEnv* jni,
2053 jobject render_egl_context) {
2054 if (render_egl_context_) {
2055 jni->DeleteGlobalRef(render_egl_context_);
2056 }
2057 render_egl_context_ = jni->NewGlobalRef(render_egl_context);
2058 ALOGD("VideoDecoder EGL context set");
2059 return 0;
2060}
2061
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002062MediaCodecVideoDecoder::MediaCodecVideoDecoder(JNIEnv* jni)
2063 : key_frame_required_(true),
2064 inited_(false),
2065 use_surface_(HW_DECODER_USE_SURFACE),
2066 codec_thread_(new Thread()),
2067 j_media_codec_video_decoder_class_(
2068 jni,
2069 FindClass(jni, "org/webrtc/MediaCodecVideoDecoder")),
2070 j_media_codec_video_decoder_(
2071 jni,
2072 jni->NewObject(*j_media_codec_video_decoder_class_,
2073 GetMethodID(jni,
2074 *j_media_codec_video_decoder_class_,
2075 "<init>",
2076 "()V"))) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002077 ScopedLocalRefFrame local_ref_frame(jni);
2078 codec_thread_->SetName("MediaCodecVideoDecoder", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002079 CHECK(codec_thread_->Start()) << "Failed to start MediaCodecVideoDecoder";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002080
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002081 j_init_decode_method_ = GetMethodID(
2082 jni, *j_media_codec_video_decoder_class_, "initDecode",
2083 "(IIZLandroid/opengl/EGLContext;)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002084 j_release_method_ =
2085 GetMethodID(jni, *j_media_codec_video_decoder_class_, "release", "()V");
2086 j_dequeue_input_buffer_method_ = GetMethodID(
2087 jni, *j_media_codec_video_decoder_class_, "dequeueInputBuffer", "()I");
2088 j_queue_input_buffer_method_ = GetMethodID(
2089 jni, *j_media_codec_video_decoder_class_, "queueInputBuffer", "(IIJ)Z");
2090 j_dequeue_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002091 jni, *j_media_codec_video_decoder_class_, "dequeueOutputBuffer",
2092 "(I)Lorg/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo;");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002093 j_release_output_buffer_method_ = GetMethodID(
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002094 jni, *j_media_codec_video_decoder_class_, "releaseOutputBuffer", "(IZ)Z");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002095
2096 j_input_buffers_field_ = GetFieldID(
2097 jni, *j_media_codec_video_decoder_class_,
2098 "inputBuffers", "[Ljava/nio/ByteBuffer;");
2099 j_output_buffers_field_ = GetFieldID(
2100 jni, *j_media_codec_video_decoder_class_,
2101 "outputBuffers", "[Ljava/nio/ByteBuffer;");
2102 j_color_format_field_ = GetFieldID(
2103 jni, *j_media_codec_video_decoder_class_, "colorFormat", "I");
2104 j_width_field_ = GetFieldID(
2105 jni, *j_media_codec_video_decoder_class_, "width", "I");
2106 j_height_field_ = GetFieldID(
2107 jni, *j_media_codec_video_decoder_class_, "height", "I");
2108 j_stride_field_ = GetFieldID(
2109 jni, *j_media_codec_video_decoder_class_, "stride", "I");
2110 j_slice_height_field_ = GetFieldID(
2111 jni, *j_media_codec_video_decoder_class_, "sliceHeight", "I");
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002112 j_textureID_field_ = GetFieldID(
2113 jni, *j_media_codec_video_decoder_class_, "textureID", "I");
2114 j_surface_texture_field_ = GetFieldID(
2115 jni, *j_media_codec_video_decoder_class_, "surfaceTexture",
2116 "Landroid/graphics/SurfaceTexture;");
2117
2118 jclass j_decoder_output_buffer_info_class = FindClass(jni,
2119 "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
2120 j_info_index_field_ = GetFieldID(
2121 jni, j_decoder_output_buffer_info_class, "index", "I");
2122 j_info_offset_field_ = GetFieldID(
2123 jni, j_decoder_output_buffer_info_class, "offset", "I");
2124 j_info_size_field_ = GetFieldID(
2125 jni, j_decoder_output_buffer_info_class, "size", "I");
2126 j_info_presentation_timestamp_us_field_ = GetFieldID(
2127 jni, j_decoder_output_buffer_info_class, "presentationTimestampUs", "J");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002128
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002129 CHECK_EXCEPTION(jni) << "MediaCodecVideoDecoder ctor failed";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002130 memset(&codec_, 0, sizeof(codec_));
2131}
2132
2133MediaCodecVideoDecoder::~MediaCodecVideoDecoder() {
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002134 // Call Release() to ensure no more callbacks to us after we are deleted.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002135 Release();
2136}
2137
2138int32_t MediaCodecVideoDecoder::InitDecode(const VideoCodec* inst,
2139 int32_t numberOfCores) {
2140 if (inst == NULL) {
2141 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2142 }
2143 int ret_val = Release();
2144 if (ret_val < 0) {
2145 return ret_val;
2146 }
2147 // Save VideoCodec instance for later.
2148 if (&codec_ != inst) {
2149 codec_ = *inst;
2150 }
2151 codec_.maxFramerate = (codec_.maxFramerate >= 1) ? codec_.maxFramerate : 1;
2152
2153 // Always start with a complete key frame.
2154 key_frame_required_ = true;
2155 frames_received_ = 0;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002156 frames_decoded_ = 0;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002157
2158 // Call Java init.
2159 return codec_thread_->Invoke<int32_t>(
2160 Bind(&MediaCodecVideoDecoder::InitDecodeOnCodecThread, this));
2161}
2162
2163int32_t MediaCodecVideoDecoder::InitDecodeOnCodecThread() {
2164 CheckOnCodecThread();
2165 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2166 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002167 ALOGD("InitDecodeOnCodecThread: %d x %d. fps: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002168 codec_.width, codec_.height, codec_.maxFramerate);
2169
2170 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2171 j_init_decode_method_,
2172 codec_.width,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002173 codec_.height,
2174 use_surface_,
2175 render_egl_context_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002176 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002177 if (!success) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002178 return WEBRTC_VIDEO_CODEC_ERROR;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002179 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002180 inited_ = true;
2181
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002182 max_pending_frames_ = 0;
2183 if (use_surface_) {
2184 max_pending_frames_ = 1;
2185 }
2186 start_time_ms_ = GetCurrentTimeMs();
2187 current_frames_ = 0;
2188 current_bytes_ = 0;
2189 current_decoding_time_ms_ = 0;
2190 timestamps_.clear();
2191 ntp_times_ms_.clear();
2192 frame_rtc_times_ms_.clear();
2193
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002194 jobjectArray input_buffers = (jobjectArray)GetObjectField(
2195 jni, *j_media_codec_video_decoder_, j_input_buffers_field_);
2196 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002197 input_buffers_.resize(num_input_buffers);
2198 for (size_t i = 0; i < num_input_buffers; ++i) {
2199 input_buffers_[i] =
2200 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002201 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002202 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002203
2204 if (use_surface_) {
2205 jobject surface_texture = GetObjectField(
2206 jni, *j_media_codec_video_decoder_, j_surface_texture_field_);
2207 surface_texture_ = jni->NewGlobalRef(surface_texture);
2208 }
2209 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
2210
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002211 return WEBRTC_VIDEO_CODEC_OK;
2212}
2213
2214int32_t MediaCodecVideoDecoder::Release() {
2215 return codec_thread_->Invoke<int32_t>(
2216 Bind(&MediaCodecVideoDecoder::ReleaseOnCodecThread, this));
2217}
2218
2219int32_t MediaCodecVideoDecoder::ReleaseOnCodecThread() {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002220 if (!inited_) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002221 return WEBRTC_VIDEO_CODEC_OK;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002222 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002223 CheckOnCodecThread();
2224 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2225 ALOGD("DecoderRelease: Frames received: %d.", frames_received_);
2226 ScopedLocalRefFrame local_ref_frame(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002227 for (size_t i = 0; i < input_buffers_.size(); i++) {
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002228 jni->DeleteGlobalRef(input_buffers_[i]);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002229 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002230 input_buffers_.clear();
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002231 if (use_surface_) {
2232 // Before deleting texture object make sure it is no longer referenced
2233 // by any TextureVideoFrame.
2234 int32_t waitTimeoutUs = 3000000; // 3 second wait
2235 while (waitTimeoutUs > 0 && native_handle_.ref_count() > 0) {
2236 ALOGD("Current Texture RefCnt: %d", native_handle_.ref_count());
2237 usleep(30000);
2238 waitTimeoutUs -= 30000;
2239 }
2240 ALOGD("TextureRefCnt: %d", native_handle_.ref_count());
2241 jni->DeleteGlobalRef(surface_texture_);
2242 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002243 jni->CallVoidMethod(*j_media_codec_video_decoder_, j_release_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002244 CHECK_EXCEPTION(jni);
glaznev@webrtc.org0b435ba2014-09-18 23:01:03 +00002245 rtc::MessageQueueManager::Clear(this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002246 inited_ = false;
2247 return WEBRTC_VIDEO_CODEC_OK;
2248}
2249
2250
2251void MediaCodecVideoDecoder::CheckOnCodecThread() {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002252 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread())
2253 << "Running on wrong thread!";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002254}
2255
2256int32_t MediaCodecVideoDecoder::Decode(
2257 const EncodedImage& inputImage,
2258 bool missingFrames,
2259 const RTPFragmentationHeader* fragmentation,
2260 const CodecSpecificInfo* codecSpecificInfo,
2261 int64_t renderTimeMs) {
2262 if (!inited_) {
2263 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2264 }
2265 if (callback_ == NULL) {
2266 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2267 }
2268 if (inputImage._buffer == NULL && inputImage._length > 0) {
2269 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2270 }
2271 // Check if encoded frame dimension has changed.
2272 if ((inputImage._encodedWidth * inputImage._encodedHeight > 0) &&
2273 (inputImage._encodedWidth != codec_.width ||
2274 inputImage._encodedHeight != codec_.height)) {
2275 codec_.width = inputImage._encodedWidth;
2276 codec_.height = inputImage._encodedHeight;
2277 InitDecode(&codec_, 1);
2278 }
2279
2280 // Always start with a complete key frame.
2281 if (key_frame_required_) {
2282 if (inputImage._frameType != webrtc::kKeyFrame) {
2283 return WEBRTC_VIDEO_CODEC_ERROR;
2284 }
2285 if (!inputImage._completeFrame) {
2286 return WEBRTC_VIDEO_CODEC_ERROR;
2287 }
2288 key_frame_required_ = false;
2289 }
2290 if (inputImage._length == 0) {
2291 return WEBRTC_VIDEO_CODEC_ERROR;
2292 }
2293
2294 return codec_thread_->Invoke<int32_t>(Bind(
2295 &MediaCodecVideoDecoder::DecodeOnCodecThread, this, inputImage));
2296}
2297
2298int32_t MediaCodecVideoDecoder::DecodeOnCodecThread(
2299 const EncodedImage& inputImage) {
2300 static uint8_t yVal_ = 0x7f;
2301
2302 CheckOnCodecThread();
2303 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2304 ScopedLocalRefFrame local_ref_frame(jni);
2305
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002306 // Try to drain the decoder and wait until output is not too
2307 // much behind the input.
2308 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2309 ALOGV("Wait for output...");
2310 if (!DeliverPendingOutputs(jni, kMediaCodecTimeoutMs * 1000)) {
2311 Reset();
2312 return WEBRTC_VIDEO_CODEC_ERROR;
2313 }
2314 if (frames_received_ > frames_decoded_ + max_pending_frames_) {
2315 ALOGE("Output buffer dequeue timeout");
2316 Reset();
2317 return WEBRTC_VIDEO_CODEC_ERROR;
2318 }
2319 }
2320
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002321 // Get input buffer.
2322 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_decoder_,
2323 j_dequeue_input_buffer_method_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002324 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002325 if (j_input_buffer_index < 0) {
2326 ALOGE("dequeueInputBuffer error");
2327 Reset();
2328 return WEBRTC_VIDEO_CODEC_ERROR;
2329 }
2330
2331 // Copy encoded data to Java ByteBuffer.
2332 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
2333 uint8* buffer =
2334 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002335 CHECK(buffer) << "Indirect buffer??";
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002336 int64 buffer_capacity = jni->GetDirectBufferCapacity(j_input_buffer);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002337 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002338 if (buffer_capacity < inputImage._length) {
2339 ALOGE("Input frame size %d is bigger than buffer size %d.",
2340 inputImage._length, buffer_capacity);
2341 Reset();
2342 return WEBRTC_VIDEO_CODEC_ERROR;
2343 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002344 ALOGV("Decoder frame in # %d. Buffer # %d. Size: %d",
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002345 frames_received_, j_input_buffer_index, inputImage._length);
2346 memcpy(buffer, inputImage._buffer, inputImage._length);
2347
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002348 // Save input image timestamps for later output.
2349 frames_received_++;
2350 current_bytes_ += inputImage._length;
2351 timestamps_.push_back(inputImage._timeStamp);
2352 ntp_times_ms_.push_back(inputImage.ntp_time_ms_);
2353 frame_rtc_times_ms_.push_back(GetCurrentTimeMs());
2354
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002355 // Feed input to decoder.
2356 jlong timestamp_us = (frames_received_ * 1000000) / codec_.maxFramerate;
2357 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
2358 j_queue_input_buffer_method_,
2359 j_input_buffer_index,
2360 inputImage._length,
2361 timestamp_us);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002362 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002363 if (!success) {
2364 ALOGE("queueInputBuffer error");
2365 Reset();
2366 return WEBRTC_VIDEO_CODEC_ERROR;
2367 }
2368
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002369 // Try to drain the decoder
2370 if (!DeliverPendingOutputs(jni, 0)) {
2371 ALOGE("DeliverPendingOutputs error");
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002372 Reset();
2373 return WEBRTC_VIDEO_CODEC_ERROR;
2374 }
2375
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002376 return WEBRTC_VIDEO_CODEC_OK;
2377}
2378
2379bool MediaCodecVideoDecoder::DeliverPendingOutputs(
2380 JNIEnv* jni, int dequeue_timeout_us) {
2381 if (frames_received_ <= frames_decoded_) {
2382 // No need to query for output buffers - decoder is drained.
2383 return true;
2384 }
2385 // Get decoder output.
2386 jobject j_decoder_output_buffer_info = jni->CallObjectMethod(
2387 *j_media_codec_video_decoder_,
2388 j_dequeue_output_buffer_method_,
2389 dequeue_timeout_us);
2390
2391 CHECK_EXCEPTION(jni);
2392 if (IsNull(jni, j_decoder_output_buffer_info)) {
2393 return true;
2394 }
2395
2396 // Extract data from Java DecoderOutputBufferInfo.
2397 int output_buffer_index =
2398 GetIntField(jni, j_decoder_output_buffer_info, j_info_index_field_);
2399 if (output_buffer_index < 0) {
2400 ALOGE("dequeueOutputBuffer error : %d", output_buffer_index);
2401 Reset();
2402 return false;
2403 }
2404 int output_buffer_offset =
2405 GetIntField(jni, j_decoder_output_buffer_info, j_info_offset_field_);
2406 int output_buffer_size =
2407 GetIntField(jni, j_decoder_output_buffer_info, j_info_size_field_);
2408 CHECK_EXCEPTION(jni);
2409
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002410 // Extract data from Java ByteBuffer.
2411 jobjectArray output_buffers = reinterpret_cast<jobjectArray>(GetObjectField(
2412 jni, *j_media_codec_video_decoder_, j_output_buffers_field_));
2413 jobject output_buffer =
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002414 jni->GetObjectArrayElement(output_buffers, output_buffer_index);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002415 uint8_t* payload =
2416 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(output_buffer));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002417 CHECK_EXCEPTION(jni);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002418 payload += output_buffer_offset;
2419 // Get decoded video frame properties.
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002420 int color_format = GetIntField(jni, *j_media_codec_video_decoder_,
2421 j_color_format_field_);
2422 int width = GetIntField(jni, *j_media_codec_video_decoder_, j_width_field_);
2423 int height = GetIntField(jni, *j_media_codec_video_decoder_, j_height_field_);
2424 int stride = GetIntField(jni, *j_media_codec_video_decoder_, j_stride_field_);
2425 int slice_height = GetIntField(jni, *j_media_codec_video_decoder_,
2426 j_slice_height_field_);
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002427 int texture_id = GetIntField(jni, *j_media_codec_video_decoder_,
2428 j_textureID_field_);
2429 if (!use_surface_ && output_buffer_size < width * height * 3 / 2) {
2430 ALOGE("Insufficient output buffer size: %d", output_buffer_size);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002431 Reset();
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002432 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002433 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002434
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002435 // Get frame timestamps from a queue.
2436 int32_t timestamp = timestamps_.front();
2437 timestamps_.erase(timestamps_.begin());
2438 int64_t ntp_time_ms = ntp_times_ms_.front();
2439 ntp_times_ms_.erase(ntp_times_ms_.begin());
2440 int64_t frame_decoding_time_ms = GetCurrentTimeMs() -
2441 frame_rtc_times_ms_.front();
2442 frame_rtc_times_ms_.erase(frame_rtc_times_ms_.begin());
2443
2444 ALOGV("Decoder frame out # %d. %d x %d. %d x %d. Color: 0x%x. Size: %d."
2445 " DecTime: %lld", frames_decoded_, width, height, stride, slice_height,
2446 color_format, output_buffer_size, frame_decoding_time_ms);
2447
2448 // Create yuv420 frame.
2449 if (!use_surface_) {
2450 if (color_format == COLOR_FormatYUV420Planar) {
2451 decoded_image_.CreateFrame(
2452 stride * slice_height, payload,
2453 (stride * slice_height) / 4, payload + (stride * slice_height),
2454 (stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
2455 width, height,
2456 stride, stride / 2, stride / 2);
2457 } else {
2458 // All other supported formats are nv12.
2459 decoded_image_.CreateEmptyFrame(width, height, width,
2460 width / 2, width / 2);
2461 libyuv::NV12ToI420(
2462 payload, stride,
2463 payload + stride * slice_height, stride,
2464 decoded_image_.buffer(webrtc::kYPlane),
2465 decoded_image_.stride(webrtc::kYPlane),
2466 decoded_image_.buffer(webrtc::kUPlane),
2467 decoded_image_.stride(webrtc::kUPlane),
2468 decoded_image_.buffer(webrtc::kVPlane),
2469 decoded_image_.stride(webrtc::kVPlane),
2470 width, height);
2471 }
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002472 }
2473
2474 // Return output buffer back to codec.
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002475 bool success = jni->CallBooleanMethod(*j_media_codec_video_decoder_,
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002476 j_release_output_buffer_method_,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002477 output_buffer_index,
2478 use_surface_);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002479 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002480 if (!success) {
2481 ALOGE("releaseOutputBuffer error");
2482 Reset();
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002483 return false;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002484 }
2485
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002486 // Calculate and print decoding statistics - every 3 seconds.
2487 frames_decoded_++;
2488 current_frames_++;
2489 current_decoding_time_ms_ += frame_decoding_time_ms;
2490 int statistic_time_ms = GetCurrentTimeMs() - start_time_ms_;
2491 if (statistic_time_ms >= kMediaCodecStatisticsIntervalMs &&
2492 current_frames_ > 0) {
2493 ALOGD("Decoder bitrate: %d kbps, fps: %d, decTime: %d for last %d ms",
2494 current_bytes_ * 8 / statistic_time_ms,
2495 (current_frames_ * 1000 + statistic_time_ms / 2) / statistic_time_ms,
2496 current_decoding_time_ms_ / current_frames_, statistic_time_ms);
2497 start_time_ms_ = GetCurrentTimeMs();
2498 current_frames_ = 0;
2499 current_bytes_= 0;
2500 current_decoding_time_ms_ = 0;
2501 }
2502
2503 // Callback - output decoded frame.
2504 int32_t callback_status = WEBRTC_VIDEO_CODEC_OK;
2505 if (use_surface_) {
2506 native_handle_.SetTextureObject(surface_texture_, texture_id);
2507 TextureVideoFrame texture_image(
2508 &native_handle_, width, height, timestamp, 0);
2509 texture_image.set_ntp_time_ms(ntp_time_ms);
2510 callback_status = callback_->Decoded(texture_image);
2511 } else {
2512 decoded_image_.set_timestamp(timestamp);
2513 decoded_image_.set_ntp_time_ms(ntp_time_ms);
2514 callback_status = callback_->Decoded(decoded_image_);
2515 }
2516 if (callback_status > 0) {
2517 ALOGE("callback error");
2518 }
2519
2520 return true;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002521}
2522
2523int32_t MediaCodecVideoDecoder::RegisterDecodeCompleteCallback(
2524 DecodedImageCallback* callback) {
2525 callback_ = callback;
2526 return WEBRTC_VIDEO_CODEC_OK;
2527}
2528
2529int32_t MediaCodecVideoDecoder::Reset() {
2530 ALOGD("DecoderReset");
2531 if (!inited_) {
2532 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2533 }
2534 return InitDecode(&codec_, 1);
2535}
2536
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002537void MediaCodecVideoDecoder::OnMessage(rtc::Message* msg) {
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002538 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2539 ScopedLocalRefFrame local_ref_frame(jni);
2540 if (!inited_) {
2541 return;
2542 }
2543 // We only ever send one message to |this| directly (not through a Bind()'d
2544 // functor), so expect no ID/data.
2545 CHECK(!msg->message_id) << "Unexpected message!";
2546 CHECK(!msg->pdata) << "Unexpected message!";
2547 CheckOnCodecThread();
2548
2549 DeliverPendingOutputs(jni, 0);
2550 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002551}
2552
2553class MediaCodecVideoDecoderFactory
2554 : public cricket::WebRtcVideoDecoderFactory {
2555 public:
2556 MediaCodecVideoDecoderFactory();
2557 virtual ~MediaCodecVideoDecoderFactory();
2558 // WebRtcVideoDecoderFactory implementation.
2559 virtual webrtc::VideoDecoder* CreateVideoDecoder(
2560 webrtc::VideoCodecType type) OVERRIDE;
2561
2562 virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) OVERRIDE;
2563
2564 private:
2565 bool is_platform_supported_;
2566};
2567
2568MediaCodecVideoDecoderFactory::MediaCodecVideoDecoderFactory() {
2569 JNIEnv* jni = AttachCurrentThreadIfNeeded();
2570 ScopedLocalRefFrame local_ref_frame(jni);
2571 jclass j_decoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoDecoder");
2572 is_platform_supported_ = jni->CallStaticBooleanMethod(
2573 j_decoder_class,
2574 GetStaticMethodID(jni, j_decoder_class, "isPlatformSupported", "()Z"));
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002575 CHECK_EXCEPTION(jni);
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002576}
2577
2578MediaCodecVideoDecoderFactory::~MediaCodecVideoDecoderFactory() {}
2579
2580webrtc::VideoDecoder* MediaCodecVideoDecoderFactory::CreateVideoDecoder(
2581 webrtc::VideoCodecType type) {
2582 if (type != kVideoCodecVP8 || !is_platform_supported_) {
2583 return NULL;
2584 }
2585 return new MediaCodecVideoDecoder(AttachCurrentThreadIfNeeded());
2586}
2587
2588
2589void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
2590 webrtc::VideoDecoder* decoder) {
2591 delete decoder;
2592}
2593
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002594#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002595
2596} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002597
2598// Convenience macro defining JNI-accessible methods in the org.webrtc package.
2599// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
2600#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
2601 Java_org_webrtc_##name
2602
2603extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002604 CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002605 g_jvm = jvm;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002606 CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002607
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002608 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002609
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002610 CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002611
2612 JNIEnv* jni;
2613 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
2614 return -1;
2615 g_class_reference_holder = new ClassReferenceHolder(jni);
2616
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002617 return JNI_VERSION_1_6;
2618}
2619
2620extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002621 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002622 delete g_class_reference_holder;
2623 g_class_reference_holder = NULL;
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002624 CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
fischman@webrtc.orgc2d75e02014-02-18 16:57:36 +00002625 g_jvm = NULL;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002626}
2627
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002628static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002629 jfieldID native_dc_id = GetFieldID(jni,
2630 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
2631 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002632 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002633}
2634
2635JOW(jlong, DataChannel_registerObserverNative)(
2636 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002637 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002638 new DataChannelObserverWrapper(jni, j_observer));
2639 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00002640 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002641}
2642
2643JOW(void, DataChannel_unregisterObserverNative)(
2644 JNIEnv* jni, jobject j_dc, jlong native_observer) {
2645 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
2646 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
2647}
2648
2649JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
2650 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
2651}
2652
2653JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
2654 return JavaEnumFromIndex(
2655 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
2656}
2657
2658JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
2659 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002660 CHECK_LE(buffered_amount, std::numeric_limits<int64>::max())
2661 << "buffered_amount overflowed jlong!";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002662 return static_cast<jlong>(buffered_amount);
2663}
2664
2665JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
2666 ExtractNativeDC(jni, j_dc)->Close();
2667}
2668
2669JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
2670 jbyteArray data, jboolean binary) {
2671 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
2672 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002673 rtc::Buffer(bytes, jni->GetArrayLength(data)),
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002674 binary));
2675 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
2676 return ret;
2677}
2678
2679JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002680 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002681}
2682
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002683JOW(void, Logging_nativeEnableTracing)(
2684 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
2685 jint nativeSeverity) {
2686 std::string path = JavaToStdString(jni, j_path);
2687 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00002688 webrtc::Trace::set_level_filter(nativeLevels);
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002689#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002690 if (path != "logcat:") {
2691#endif
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002692 CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
2693 << "SetTraceFile failed";
glaznev@webrtc.orge6581242014-09-19 16:53:46 +00002694#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00002695 } else {
2696 // Intentionally leak this to avoid needing to reason about its lifecycle.
2697 // It keeps no state and functions only as a dispatch point.
2698 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
2699 }
2700#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002701 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002702 rtc::LogMessage::LogToDebug(nativeSeverity);
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00002703}
2704
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002705JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002706 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002707}
2708
2709JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
2710 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
2711 delete p;
2712}
2713
2714JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002715 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002716}
2717
2718JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
2719 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
2720}
2721
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002722JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002723 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
2724}
2725
glaznev@webrtc.orga59c5012014-09-17 03:26:59 +00002726JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
2727 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
2728}
2729
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002730JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002731 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002732}
2733
2734JOW(jboolean, MediaStream_nativeAddAudioTrack)(
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)->AddTrack(
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_nativeAddVideoTrack)(
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)
2743 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002744}
2745
2746JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
2747 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002748 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002749 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002750}
2751
2752JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
2753 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002754 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002755 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002756}
2757
2758JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
2759 return JavaStringFromStdString(
2760 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
2761}
2762
2763JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002764 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002765}
2766
2767JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
2768 JNIEnv * jni, jclass, jobject j_observer) {
2769 return (jlong)new PCOJava(jni, j_observer);
2770}
2771
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002772#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002773JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002774 JNIEnv* jni, jclass, jobject context,
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002775 jboolean initialize_audio, jboolean initialize_video,
2776 jobject render_egl_context) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002777 CHECK(g_jvm) << "JNI_OnLoad failed to run?";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002778 bool failure = false;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002779 if (!factory_static_initialized) {
andresp@webrtc.org85ef7702014-09-17 11:44:51 +00002780 if (initialize_video) {
2781 failure |= webrtc::SetCaptureAndroidVM(g_jvm, context);
2782 failure |= webrtc::SetRenderAndroidVM(g_jvm);
2783 }
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002784 if (initialize_audio)
2785 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
2786 factory_static_initialized = true;
2787 }
fischman@webrtc.orga150bc92014-05-14 22:00:50 +00002788 if (initialize_video)
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002789 failure |= MediaCodecVideoDecoder::SetAndroidObjects(jni,
2790 render_egl_context);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002791 return !failure;
2792}
glaznev@webrtc.org1d53f642014-09-11 16:58:25 +00002793#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002794
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002795// Helper struct for working around the fact that CreatePeerConnectionFactory()
2796// comes in two flavors: either entirely automagical (constructing its own
2797// threads and deleting them on teardown, but no external codec factory support)
2798// or entirely manual (requires caller to delete threads after factory
2799// teardown). This struct takes ownership of its ctor's arguments to present a
2800// single thing for Java to hold and eventually free.
2801class OwnedFactoryAndThreads {
2802 public:
2803 OwnedFactoryAndThreads(Thread* worker_thread,
2804 Thread* signaling_thread,
2805 PeerConnectionFactoryInterface* factory)
2806 : worker_thread_(worker_thread),
2807 signaling_thread_(signaling_thread),
2808 factory_(factory) {}
2809
2810 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
2811
2812 PeerConnectionFactoryInterface* factory() { return factory_; }
2813
2814 private:
2815 const scoped_ptr<Thread> worker_thread_;
2816 const scoped_ptr<Thread> signaling_thread_;
2817 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
2818};
2819
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002820JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
2821 JNIEnv* jni, jclass) {
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002822 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but
2823 // ThreadManager only WrapCurrentThread()s the thread where it is first
2824 // created. Since the semantics around when auto-wrapping happens in
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002825 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think
fischman@webrtc.org2c98af72014-05-14 17:33:32 +00002826 // about ramifications of auto-wrapping there.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002827 rtc::ThreadManager::Instance()->WrapCurrentThread();
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002828 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002829 Thread* worker_thread = new Thread();
2830 worker_thread->SetName("worker_thread", NULL);
2831 Thread* signaling_thread = new Thread();
2832 signaling_thread->SetName("signaling_thread", NULL);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002833 CHECK(worker_thread->Start() && signaling_thread->Start())
2834 << "Failed to start threads";
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002835 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002836 scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
glaznev@webrtc.org99678452014-09-15 17:52:42 +00002837#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002838 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002839 decoder_factory.reset(new MediaCodecVideoDecoderFactory());
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002840#endif
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002841 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002842 webrtc::CreatePeerConnectionFactory(worker_thread,
2843 signaling_thread,
2844 NULL,
2845 encoder_factory.release(),
glaznev@webrtc.orgefe4b9a2014-07-22 17:44:53 +00002846 decoder_factory.release()));
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002847 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
2848 worker_thread, signaling_thread, factory.release());
2849 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002850}
2851
2852JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002853 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002854 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002855}
2856
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002857static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
2858 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
2859}
2860
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002861JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
2862 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002863 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002864 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002865 rtc::scoped_refptr<MediaStreamInterface> stream(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002866 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
2867 return (jlong)stream.release();
2868}
2869
2870JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
2871 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
2872 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002873 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002874 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002875 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002876 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002877 rtc::scoped_refptr<VideoSourceInterface> source(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002878 factory->CreateVideoSource(
2879 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
2880 constraints.get()));
2881 return (jlong)source.release();
2882}
2883
2884JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
2885 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2886 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002887 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002888 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002889 rtc::scoped_refptr<VideoTrackInterface> track(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002890 factory->CreateVideoTrack(
2891 JavaToStdString(jni, id),
2892 reinterpret_cast<VideoSourceInterface*>(native_source)));
2893 return (jlong)track.release();
2894}
2895
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002896JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
2897 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
2898 scoped_ptr<ConstraintsWrapper> constraints(
2899 new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002900 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002901 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002902 rtc::scoped_refptr<AudioSourceInterface> source(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002903 factory->CreateAudioSource(constraints.get()));
2904 return (jlong)source.release();
2905}
2906
2907JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
2908 JNIEnv* jni, jclass, jlong native_factory, jstring id,
2909 jlong native_source) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002910 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002911 factoryFromJava(native_factory));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002912 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00002913 JavaToStdString(jni, id),
2914 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002915 return (jlong)track.release();
2916}
2917
2918static void JavaIceServersToJsepIceServers(
2919 JNIEnv* jni, jobject j_ice_servers,
2920 PeerConnectionInterface::IceServers* ice_servers) {
2921 jclass list_class = GetObjectClass(jni, j_ice_servers);
2922 jmethodID iterator_id = GetMethodID(
2923 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2924 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002925 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002926 jmethodID iterator_has_next = GetMethodID(
2927 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2928 jmethodID iterator_next = GetMethodID(
2929 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2930 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002931 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002932 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002933 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002934 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2935 jfieldID j_ice_server_uri_id =
2936 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2937 jfieldID j_ice_server_username_id =
2938 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2939 jfieldID j_ice_server_password_id =
2940 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2941 jstring uri = reinterpret_cast<jstring>(
2942 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2943 jstring username = reinterpret_cast<jstring>(
2944 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2945 jstring password = reinterpret_cast<jstring>(
2946 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2947 PeerConnectionInterface::IceServer server;
2948 server.uri = JavaToStdString(jni, uri);
2949 server.username = JavaToStdString(jni, username);
2950 server.password = JavaToStdString(jni, password);
2951 ice_servers->push_back(server);
2952 }
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00002953 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002954}
2955
2956JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2957 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2958 jobject j_constraints, jlong observer_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002959 rtc::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002960 reinterpret_cast<PeerConnectionFactoryInterface*>(
2961 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002962 PeerConnectionInterface::IceServers servers;
2963 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2964 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2965 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002966 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
mallinath@webrtc.orga0d30672014-04-26 00:00:15 +00002967 servers, observer->constraints(), NULL, NULL, observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002968 return (jlong)pc.release();
2969}
2970
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002971static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002972 JNIEnv* jni, jobject j_pc) {
2973 jfieldID native_pc_id = GetFieldID(jni,
2974 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2975 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002976 return rtc::scoped_refptr<PeerConnectionInterface>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002977 reinterpret_cast<PeerConnectionInterface*>(j_p));
2978}
2979
2980JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2981 const SessionDescriptionInterface* sdp =
2982 ExtractNativePC(jni, j_pc)->local_description();
2983 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2984}
2985
2986JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2987 const SessionDescriptionInterface* sdp =
2988 ExtractNativePC(jni, j_pc)->remote_description();
2989 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2990}
2991
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002992JOW(jobject, PeerConnection_createDataChannel)(
2993 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2994 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002995 rtc::scoped_refptr<DataChannelInterface> channel(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002996 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2997 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002998 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2999 // vararg parameter as 64-bit and reading memory that doesn't belong to the
3000 // 32-bit parameter.
3001 jlong nativeChannelPtr = jlongFromPointer(channel.get());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003002 CHECK(nativeChannelPtr) << "Failed to create DataChannel";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003003 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
3004 jmethodID j_data_channel_ctor = GetMethodID(
3005 jni, j_data_channel_class, "<init>", "(J)V");
3006 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00003007 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003008 CHECK_EXCEPTION(jni) << "error during NewObject";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003009 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003010 int bumped_count = channel->AddRef();
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003011 CHECK(bumped_count == 2) << "Unexpected refcount";
henrike@webrtc.org723d6832013-07-12 16:04:50 +00003012 return j_channel;
3013}
3014
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003015JOW(void, PeerConnection_createOffer)(
3016 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3017 ConstraintsWrapper* constraints =
3018 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003019 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3020 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003021 jni, j_observer, constraints));
3022 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
3023}
3024
3025JOW(void, PeerConnection_createAnswer)(
3026 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
3027 ConstraintsWrapper* constraints =
3028 new ConstraintsWrapper(jni, j_constraints);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003029 rtc::scoped_refptr<CreateSdpObserverWrapper> observer(
3030 new rtc::RefCountedObject<CreateSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003031 jni, j_observer, constraints));
3032 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
3033}
3034
3035// Helper to create a SessionDescriptionInterface from a SessionDescription.
3036static SessionDescriptionInterface* JavaSdpToNativeSdp(
3037 JNIEnv* jni, jobject j_sdp) {
3038 jfieldID j_type_id = GetFieldID(
3039 jni, GetObjectClass(jni, j_sdp), "type",
3040 "Lorg/webrtc/SessionDescription$Type;");
3041 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
3042 jmethodID j_canonical_form_id = GetMethodID(
3043 jni, GetObjectClass(jni, j_type), "canonicalForm",
3044 "()Ljava/lang/String;");
3045 jstring j_type_string = (jstring)jni->CallObjectMethod(
3046 j_type, j_canonical_form_id);
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003047 CHECK_EXCEPTION(jni) << "error during CallObjectMethod";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003048 std::string std_type = JavaToStdString(jni, j_type_string);
3049
3050 jfieldID j_description_id = GetFieldID(
3051 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
3052 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
3053 std::string std_description = JavaToStdString(jni, j_description);
3054
3055 return webrtc::CreateSessionDescription(
3056 std_type, std_description, NULL);
3057}
3058
3059JOW(void, PeerConnection_setLocalDescription)(
3060 JNIEnv* jni, jobject j_pc,
3061 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003062 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3063 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003064 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3065 ExtractNativePC(jni, j_pc)->SetLocalDescription(
3066 observer, JavaSdpToNativeSdp(jni, j_sdp));
3067}
3068
3069JOW(void, PeerConnection_setRemoteDescription)(
3070 JNIEnv* jni, jobject j_pc,
3071 jobject j_observer, jobject j_sdp) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003072 rtc::scoped_refptr<SetSdpObserverWrapper> observer(
3073 new rtc::RefCountedObject<SetSdpObserverWrapper>(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003074 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
3075 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
3076 observer, JavaSdpToNativeSdp(jni, j_sdp));
3077}
3078
3079JOW(jboolean, PeerConnection_updateIce)(
3080 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
3081 PeerConnectionInterface::IceServers ice_servers;
3082 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003083 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003084 new ConstraintsWrapper(jni, j_constraints));
3085 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
3086}
3087
3088JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
3089 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
3090 jint j_sdp_mline_index, jstring j_candidate_sdp) {
3091 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
3092 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003093 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003094 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
3095 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
3096}
3097
3098JOW(jboolean, PeerConnection_nativeAddLocalStream)(
3099 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003100 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003101 new ConstraintsWrapper(jni, j_constraints));
3102 return ExtractNativePC(jni, j_pc)->AddStream(
3103 reinterpret_cast<MediaStreamInterface*>(native_stream),
3104 constraints.get());
3105}
3106
3107JOW(void, PeerConnection_nativeRemoveLocalStream)(
3108 JNIEnv* jni, jobject j_pc, jlong native_stream) {
3109 ExtractNativePC(jni, j_pc)->RemoveStream(
3110 reinterpret_cast<MediaStreamInterface*>(native_stream));
3111}
3112
3113JOW(bool, PeerConnection_nativeGetStats)(
3114 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003115 rtc::scoped_refptr<StatsObserverWrapper> observer(
3116 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003117 return ExtractNativePC(jni, j_pc)->GetStats(
jiayl@webrtc.orgdb41b4d2014-03-03 21:30:06 +00003118 observer,
3119 reinterpret_cast<MediaStreamTrackInterface*>(native_track),
3120 PeerConnectionInterface::kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003121}
3122
3123JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
3124 PeerConnectionInterface::SignalingState state =
3125 ExtractNativePC(jni, j_pc)->signaling_state();
3126 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
3127}
3128
3129JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
3130 PeerConnectionInterface::IceConnectionState state =
3131 ExtractNativePC(jni, j_pc)->ice_connection_state();
3132 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
3133}
3134
3135JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
3136 PeerConnectionInterface::IceGatheringState state =
3137 ExtractNativePC(jni, j_pc)->ice_gathering_state();
3138 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
3139}
3140
3141JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
3142 ExtractNativePC(jni, j_pc)->Close();
3143 return;
3144}
3145
3146JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00003147 rtc::scoped_refptr<MediaSourceInterface> p(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003148 reinterpret_cast<MediaSourceInterface*>(j_p));
3149 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
3150}
3151
3152JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
3153 JNIEnv* jni, jclass, jstring j_device_name) {
3154 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003155 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003156 cricket::DeviceManagerFactory::Create());
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003157 CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003158 cricket::Device device;
3159 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003160 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003161 return 0;
3162 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003163 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003164 device_manager->CreateVideoCapturer(device));
3165 return (jlong)capturer.release();
3166}
3167
3168JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
3169 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003170 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
3171 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003172 return (jlong)renderer.release();
3173}
3174
3175JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
3176 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003177 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003178 new JavaVideoRendererWrapper(jni, j_callbacks));
3179 return (jlong)renderer.release();
3180}
3181
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003182JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
3183 cricket::VideoCapturer* capturer =
3184 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003185 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003186 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
3187 capturer->Stop();
3188 return jlongFromPointer(format.release());
3189}
3190
3191JOW(void, VideoSource_restart)(
3192 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
andresp@webrtc.org4d19e052014-09-09 11:45:44 +00003193 CHECK(j_p_source);
3194 CHECK(j_p_format);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00003195 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003196 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
3197 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
3198 StartCapturing(cricket::VideoFormat(*format));
3199}
3200
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00003201JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00003202 JNIEnv* jni, jclass, jlong j_p) {
3203 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
3204}
3205
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003206JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003207 return JavaStringFromStdString(
3208 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003209}
3210
3211JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003212 return JavaStringFromStdString(
3213 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003214}
3215
3216JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003217 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003218}
3219
3220JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003221 return JavaEnumFromIndex(
3222 jni,
3223 "MediaStreamTrack$State",
3224 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003225}
3226
3227JOW(jboolean, MediaStreamTrack_nativeSetState)(
3228 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003229 MediaStreamTrackInterface::TrackState new_state =
3230 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003231 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3232 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003233}
3234
3235JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
3236 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003237 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
3238 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003239}
3240
3241JOW(void, VideoTrack_nativeAddRenderer)(
3242 JNIEnv* jni, jclass,
3243 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003244 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003245 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3246}
3247
3248JOW(void, VideoTrack_nativeRemoveRenderer)(
3249 JNIEnv* jni, jclass,
3250 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00003251 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003252 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
3253}