blob: 2185aef20697fcc0aea40b4a51c4191cd4881963 [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>
henrike@webrtc.org723d6832013-07-12 16:04:50 +000060#include <limits>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061#include <map>
fischman@webrtc.org32001ef2013-08-12 23:26:21 +000062#include <sys/prctl.h>
63#include <sys/syscall.h>
fischman@webrtc.orgeb7def22013-12-09 21:34:30 +000064#include <unistd.h>
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"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000069#include "talk/base/bind.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070#include "talk/base/logging.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000071#include "talk/base/messagequeue.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072#include "talk/base/ssladapter.h"
73#include "talk/media/base/videocapturer.h"
74#include "talk/media/base/videorenderer.h"
75#include "talk/media/devices/videorendererfactory.h"
76#include "talk/media/webrtc/webrtcvideocapturer.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000077#include "talk/media/webrtc/webrtcvideoencoderfactory.h"
fischman@webrtc.org3d496fb2013-07-30 17:14:35 +000078#include "third_party/icu/source/common/unicode/unistr.h"
fischman@webrtc.org540acde2014-02-13 03:56:14 +000079#include "third_party/libyuv/include/libyuv/convert.h"
80#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
andrew@webrtc.org31628aa2013-10-22 12:50:00 +000081#include "webrtc/system_wrappers/interface/compile_assert.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000082#include "webrtc/system_wrappers/interface/trace.h"
83#include "webrtc/video_engine/include/vie_base.h"
84#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +000086#ifdef ANDROID
87#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
88using webrtc::LogcatTraceContext;
89#endif
90
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091using icu::UnicodeString;
fischman@webrtc.org540acde2014-02-13 03:56:14 +000092using talk_base::Bind;
93using talk_base::Thread;
94using talk_base::ThreadManager;
95using talk_base::scoped_ptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000096using webrtc::AudioSourceInterface;
97using webrtc::AudioTrackInterface;
98using webrtc::AudioTrackVector;
99using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000100using webrtc::DataBuffer;
101using webrtc::DataChannelInit;
102using webrtc::DataChannelInterface;
103using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104using webrtc::IceCandidateInterface;
105using webrtc::MediaConstraintsInterface;
106using webrtc::MediaSourceInterface;
107using webrtc::MediaStreamInterface;
108using webrtc::MediaStreamTrackInterface;
109using webrtc::PeerConnectionFactoryInterface;
110using webrtc::PeerConnectionInterface;
111using webrtc::PeerConnectionObserver;
112using webrtc::SessionDescriptionInterface;
113using webrtc::SetSessionDescriptionObserver;
114using webrtc::StatsObserver;
115using webrtc::StatsReport;
116using webrtc::VideoRendererInterface;
117using webrtc::VideoSourceInterface;
118using webrtc::VideoTrackInterface;
119using webrtc::VideoTrackVector;
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000120using webrtc::kVideoCodecVP8;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121
122// Abort the process if |x| is false, emitting |msg|.
123#define CHECK(x, msg) \
124 if (x) {} else { \
125 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
126 abort(); \
127 }
128// Abort the process if |jni| has a Java exception pending, emitting |msg|.
129#define CHECK_EXCEPTION(jni, msg) \
130 if (0) {} else { \
131 if (jni->ExceptionCheck()) { \
132 jni->ExceptionDescribe(); \
133 jni->ExceptionClear(); \
134 CHECK(0, msg); \
135 } \
136 }
137
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000138// Helper that calls ptr->Release() and logs a useful message if that didn't
139// actually delete *ptr because of extra refcounts.
140#define CHECK_RELEASE(ptr) \
141 do { \
142 int count = (ptr)->Release(); \
143 if (count != 0) { \
144 LOG(LS_ERROR) << "Refcount unexpectedly not 0: " << (ptr) \
145 << ": " << count; \
146 } \
147 CHECK(!count, "Unexpected refcount"); \
148 } while (0)
149
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000150namespace {
151
152static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
153
154static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
155static pthread_key_t g_jni_ptr; // Key for per-thread JNIEnv* data.
156
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000157// Return thread ID as a string.
158static std::string GetThreadId() {
159 char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
160 CHECK(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)) <= sizeof(buf),
161 "Thread id is bigger than uint64??");
162 return std::string(buf);
163}
164
165// Return the current thread's name.
166static std::string GetThreadName() {
167 char name[17];
168 CHECK(prctl(PR_GET_NAME, name) == 0, "prctl(PR_GET_NAME) failed");
169 name[16] = '\0';
170 return std::string(name);
171}
172
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000173static void ThreadDestructor(void* unused) {
174 jint status = g_jvm->DetachCurrentThread();
175 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
176}
177
178static void CreateJNIPtrKey() {
179 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
180 "pthread_key_create");
181}
182
183// Deal with difference in signatures between Oracle's jni.h and Android's.
184static JNIEnv* AttachCurrentThreadIfNeeded() {
185 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
186 "pthread_once");
187 JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
188 if (jni == NULL) {
189#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
190 void* env;
191#else
192 JNIEnv* env;
193#endif
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000194 char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
195 JavaVMAttachArgs args;
196 args.version = JNI_VERSION_1_6;
197 args.name = name;
198 args.group = NULL;
199 CHECK(!g_jvm->AttachCurrentThread(&env, &args), "Failed to attach thread");
200 free(name);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201 CHECK(env, "AttachCurrentThread handed back NULL!");
202 jni = reinterpret_cast<JNIEnv*>(env);
203 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
204 }
205 return jni;
206}
207
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000208// Return a |jlong| that will correctly convert back to |ptr|. This is needed
209// because the alternative (of silently passing a 32-bit pointer to a vararg
210// function expecting a 64-bit param) picks up garbage in the high 32 bits.
fischman@webrtc.org87881672013-09-03 18:58:12 +0000211static jlong jlongFromPointer(void* ptr) {
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000212 COMPILE_ASSERT(sizeof(intptr_t) <= sizeof(jlong),
fischman@webrtc.org87881672013-09-03 18:58:12 +0000213 Time_to_rethink_the_use_of_jlongs);
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +0000214 // Going through intptr_t to be obvious about the definedness of the
215 // conversion from pointer to integral type. intptr_t to jlong is a standard
216 // widening by the COMPILE_ASSERT above.
217 jlong ret = reinterpret_cast<intptr_t>(ptr);
218 assert(reinterpret_cast<void*>(ret) == ptr);
219 return ret;
fischman@webrtc.org87881672013-09-03 18:58:12 +0000220}
221
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000222// Android's FindClass() is trickier than usual because the app-specific
223// ClassLoader is not consulted when there is no app-specific frame on the
224// stack. Consequently, we only look up classes once in JNI_OnLoad.
225// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
226class ClassReferenceHolder {
227 public:
228 explicit ClassReferenceHolder(JNIEnv* jni) {
229 LoadClass(jni, "java/nio/ByteBuffer");
230 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000231 LoadClass(jni, "org/webrtc/DataChannel");
232 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
233 LoadClass(jni, "org/webrtc/DataChannel$Init");
234 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000235 LoadClass(jni, "org/webrtc/IceCandidate");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000236#ifdef ANDROID
237 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
238 LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
239#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000240 LoadClass(jni, "org/webrtc/MediaSource$State");
241 LoadClass(jni, "org/webrtc/MediaStream");
242 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
244 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000245 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000246 LoadClass(jni, "org/webrtc/SessionDescription");
247 LoadClass(jni, "org/webrtc/SessionDescription$Type");
248 LoadClass(jni, "org/webrtc/StatsReport");
249 LoadClass(jni, "org/webrtc/StatsReport$Value");
250 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
251 LoadClass(jni, "org/webrtc/VideoTrack");
252 }
253
254 ~ClassReferenceHolder() {
255 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
256 }
257
258 void FreeReferences(JNIEnv* jni) {
259 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
260 it != classes_.end(); ++it) {
261 jni->DeleteGlobalRef(it->second);
262 }
263 classes_.clear();
264 }
265
266 jclass GetClass(const std::string& name) {
267 std::map<std::string, jclass>::iterator it = classes_.find(name);
268 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
269 return it->second;
270 }
271
272 private:
273 void LoadClass(JNIEnv* jni, const std::string& name) {
274 jclass localRef = jni->FindClass(name.c_str());
275 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
276 CHECK(localRef, name);
277 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
278 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
279 CHECK(globalRef, name);
280 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
281 CHECK(inserted, "Duplicate class name: " << name);
282 }
283
284 std::map<std::string, jclass> classes_;
285};
286
287// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
288static ClassReferenceHolder* g_class_reference_holder = NULL;
289
290// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
291// object/class/method/field is non-null.
292jmethodID GetMethodID(
293 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
294 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
295 CHECK_EXCEPTION(jni,
296 "error during GetMethodID: " << name << ", " << signature);
297 CHECK(m, name << ", " << signature);
298 return m;
299}
300
301jmethodID GetStaticMethodID(
302 JNIEnv* jni, jclass c, const char* name, const char* signature) {
303 jmethodID m = jni->GetStaticMethodID(c, name, signature);
304 CHECK_EXCEPTION(jni,
305 "error during GetStaticMethodID: "
306 << name << ", " << signature);
307 CHECK(m, name << ", " << signature);
308 return m;
309}
310
311jfieldID GetFieldID(
312 JNIEnv* jni, jclass c, const char* name, const char* signature) {
313 jfieldID f = jni->GetFieldID(c, name, signature);
314 CHECK_EXCEPTION(jni, "error during GetFieldID");
315 CHECK(f, name << ", " << signature);
316 return f;
317}
318
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000319// Returns a global reference guaranteed to be valid for the lifetime of the
320// process.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321jclass FindClass(JNIEnv* jni, const char* name) {
322 return g_class_reference_holder->GetClass(name);
323}
324
325jclass GetObjectClass(JNIEnv* jni, jobject object) {
326 jclass c = jni->GetObjectClass(object);
327 CHECK_EXCEPTION(jni, "error during GetObjectClass");
328 CHECK(c, "");
329 return c;
330}
331
332jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
333 jobject o = jni->GetObjectField(object, id);
334 CHECK_EXCEPTION(jni, "error during GetObjectField");
335 CHECK(o, "");
336 return o;
337}
338
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000339jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
340 return static_cast<jstring>(GetObjectField(jni, object, id));
341}
342
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000343jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
344 jlong l = jni->GetLongField(object, id);
345 CHECK_EXCEPTION(jni, "error during GetLongField");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000346 return l;
347}
348
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000349jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
350 jint i = jni->GetIntField(object, id);
351 CHECK_EXCEPTION(jni, "error during GetIntField");
352 return i;
353}
354
355bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
356 jboolean b = jni->GetBooleanField(object, id);
357 CHECK_EXCEPTION(jni, "error during GetBooleanField");
358 return b;
359}
360
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361jobject NewGlobalRef(JNIEnv* jni, jobject o) {
362 jobject ret = jni->NewGlobalRef(o);
363 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
364 CHECK(ret, "");
365 return ret;
366}
367
368void DeleteGlobalRef(JNIEnv* jni, jobject o) {
369 jni->DeleteGlobalRef(o);
370 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
371}
372
373// Given a jweak reference, allocate a (strong) local reference scoped to the
374// lifetime of this object if the weak reference is still valid, or NULL
375// otherwise.
376class WeakRef {
377 public:
378 WeakRef(JNIEnv* jni, jweak ref)
379 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
380 CHECK_EXCEPTION(jni, "error during NewLocalRef");
381 }
382 ~WeakRef() {
383 if (obj_) {
384 jni_->DeleteLocalRef(obj_);
385 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
386 }
387 }
388 jobject obj() { return obj_; }
389
390 private:
391 JNIEnv* const jni_;
392 jobject const obj_;
393};
394
fischman@webrtc.org41776152014-01-09 00:31:17 +0000395// Scope Java local references to the lifetime of this object. Use in all C++
396// callbacks (i.e. entry points that don't originate in a Java callstack
397// through a "native" method call).
398class ScopedLocalRefFrame {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000399 public:
fischman@webrtc.org41776152014-01-09 00:31:17 +0000400 explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
401 CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000402 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000403 ~ScopedLocalRefFrame() {
404 jni_->PopLocalFrame(NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000405 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000406
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000407 private:
408 JNIEnv* jni_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000409};
410
411// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000412template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000413class ScopedGlobalRef {
414 public:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000415 ScopedGlobalRef(JNIEnv* jni, T obj)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000416 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000417 ~ScopedGlobalRef() {
418 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
419 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000420 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 return obj_;
422 }
423 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000424 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425};
426
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000427// Java references to "null" can only be distinguished as such in C++ by
428// creating a local reference, so this helper wraps that logic.
429static bool IsNull(JNIEnv* jni, jobject obj) {
430 ScopedLocalRefFrame local_ref_frame(jni);
431 return jni->NewLocalRef(obj) == NULL;
432}
433
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434// Return the (singleton) Java Enum object corresponding to |index|;
435// |state_class_fragment| is something like "MediaSource$State".
436jobject JavaEnumFromIndex(
437 JNIEnv* jni, const std::string& state_class_fragment, int index) {
438 std::string state_class_name = "org/webrtc/" + state_class_fragment;
439 jclass state_class = FindClass(jni, state_class_name.c_str());
440 jmethodID state_values_id = GetStaticMethodID(
441 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
fischman@webrtc.org41776152014-01-09 00:31:17 +0000442 jobjectArray state_values = static_cast<jobjectArray>(
443 jni->CallStaticObjectMethod(state_class, state_values_id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000444 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000445 jobject ret = jni->GetObjectArrayElement(state_values, index);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
447 return ret;
448}
449
450// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
451static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
452 UnicodeString ustr(UnicodeString::fromUTF8(native));
453 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
454 CHECK_EXCEPTION(jni, "error during NewString");
455 return jstr;
456}
457
458// Given a (UTF-16) jstring return a new UTF-8 native string.
459static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
460 const jchar* jchars = jni->GetStringChars(j_string, NULL);
461 CHECK_EXCEPTION(jni, "Error during GetStringChars");
462 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
463 CHECK_EXCEPTION(jni, "Error during GetStringLength");
464 jni->ReleaseStringChars(j_string, jchars);
465 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
466 std::string ret;
467 return ustr.toUTF8String(ret);
468}
469
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000470static DataChannelInit JavaDataChannelInitToNative(
471 JNIEnv* jni, jobject j_init) {
472 DataChannelInit init;
473
474 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
475 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
476 jfieldID max_retransmit_time_id =
477 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
478 jfieldID max_retransmits_id =
479 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
480 jfieldID protocol_id =
481 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
482 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
483 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
484
485 init.ordered = GetBooleanField(jni, j_init, ordered_id);
486 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
487 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
488 init.protocol = JavaToStdString(
489 jni, GetStringField(jni, j_init, protocol_id));
490 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
491 init.id = GetIntField(jni, j_init, id_id);
492
493 return init;
494}
495
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000496class ConstraintsWrapper;
497
498// Adapter between the C++ PeerConnectionObserver interface and the Java
499// PeerConnection.Observer interface. Wraps an instance of the Java interface
500// and dispatches C++ callbacks to Java.
501class PCOJava : public PeerConnectionObserver {
502 public:
503 PCOJava(JNIEnv* jni, jobject j_observer)
504 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000505 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
506 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
507 j_media_stream_ctor_(GetMethodID(
508 jni, *j_media_stream_class_, "<init>", "(J)V")),
509 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000511 jni, *j_audio_track_class_, "<init>", "(J)V")),
512 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
513 j_video_track_ctor_(GetMethodID(
514 jni, *j_video_track_class_, "<init>", "(J)V")),
515 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
516 j_data_channel_ctor_(GetMethodID(
517 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000518 }
519
520 virtual ~PCOJava() {}
521
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000522 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000523 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000524 std::string sdp;
525 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
526 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
527 jmethodID ctor = GetMethodID(jni(), candidate_class,
528 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000529 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
530 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
531 jobject j_candidate = jni()->NewObject(
532 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000534 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000535 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000536 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
538 }
539
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000540 virtual void OnError() OVERRIDE {
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000541 ScopedLocalRefFrame local_ref_frame(jni());
542 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "()V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 jni()->CallVoidMethod(*j_observer_global_, m);
544 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
545 }
546
547 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000548 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000549 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000551 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000553 jobject new_state_enum =
554 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
555 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
557 }
558
559 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000560 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000561 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000563 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000565 jobject new_state_enum = JavaEnumFromIndex(
566 jni(), "PeerConnection$IceConnectionState", new_state);
567 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
569 }
570
571 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000572 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000573 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000574 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000575 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000577 jobject new_state_enum = JavaEnumFromIndex(
578 jni(), "PeerConnection$IceGatheringState", new_state);
579 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
581 }
582
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000583 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000584 ScopedLocalRefFrame local_ref_frame(jni());
585 jobject j_stream = jni()->NewObject(
586 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 CHECK_EXCEPTION(jni(), "error during NewObject");
588
589 AudioTrackVector audio_tracks = stream->GetAudioTracks();
590 for (size_t i = 0; i < audio_tracks.size(); ++i) {
591 AudioTrackInterface* track = audio_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000592 jstring id = JavaStringFromStdString(jni(), track->id());
593 jobject j_track = jni()->NewObject(
594 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000596 jfieldID audio_tracks_id = GetFieldID(jni(),
597 *j_media_stream_class_,
598 "audioTracks",
599 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000600 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000602 GetObjectClass(jni(), audio_tracks),
603 "add",
604 "(Ljava/lang/Object;)Z");
605 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
607 CHECK(added, "");
608 }
609
610 VideoTrackVector video_tracks = stream->GetVideoTracks();
611 for (size_t i = 0; i < video_tracks.size(); ++i) {
612 VideoTrackInterface* track = video_tracks[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000613 jstring id = JavaStringFromStdString(jni(), track->id());
614 jobject j_track = jni()->NewObject(
615 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 CHECK_EXCEPTION(jni(), "error during NewObject");
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000617 jfieldID video_tracks_id = GetFieldID(jni(),
618 *j_media_stream_class_,
619 "videoTracks",
620 "Ljava/util/LinkedList;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000621 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 jmethodID add = GetMethodID(jni(),
fischman@webrtc.org41776152014-01-09 00:31:17 +0000623 GetObjectClass(jni(), video_tracks),
624 "add",
625 "(Ljava/lang/Object;)Z");
626 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000627 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
628 CHECK(added, "");
629 }
fischman@webrtc.org41776152014-01-09 00:31:17 +0000630 streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
632
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000633 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
634 "(Lorg/webrtc/MediaStream;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000635 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
637 }
638
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000639 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000640 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
642 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
643
644 WeakRef s(jni(), it->second);
645 streams_.erase(it);
646 if (!s.obj())
647 return;
648
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000649 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
650 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
652 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
653 }
654
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000655 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000656 ScopedLocalRefFrame local_ref_frame(jni());
657 jobject j_channel = jni()->NewObject(
658 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000659 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000660
661 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
662 "(Lorg/webrtc/DataChannel;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000663 jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000664
665 // Channel is now owned by Java object, and will be freed from
666 // DataChannel.dispose(). Important that this be done _after_ the
667 // CallVoidMethod above as Java code might call back into native code and be
668 // surprised to see a refcount of 2.
669 int bumped_count = channel->AddRef();
670 CHECK(bumped_count == 2, "Unexpected refcount OnDataChannel");
671
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000672 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
673 }
674
fischman@webrtc.orgd7568a02014-01-13 22:04:12 +0000675 virtual void OnRenegotiationNeeded() OVERRIDE {
676 ScopedLocalRefFrame local_ref_frame(jni());
677 jmethodID m =
678 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V");
679 jni()->CallVoidMethod(*j_observer_global_, m);
680 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
681 }
682
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683 void SetConstraints(ConstraintsWrapper* constraints) {
684 CHECK(!constraints_.get(), "constraints already set!");
685 constraints_.reset(constraints);
686 }
687
688 const ConstraintsWrapper* constraints() { return constraints_.get(); }
689
690 private:
691 JNIEnv* jni() {
692 return AttachCurrentThreadIfNeeded();
693 }
694
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000695 const ScopedGlobalRef<jobject> j_observer_global_;
696 const ScopedGlobalRef<jclass> j_observer_class_;
697 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000698 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000699 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000701 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000703 const ScopedGlobalRef<jclass> j_data_channel_class_;
704 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
706 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000707 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000708};
709
710// Wrapper for a Java MediaConstraints object. Copies all needed data so when
711// the constructor returns the Java object is no longer needed.
712class ConstraintsWrapper : public MediaConstraintsInterface {
713 public:
714 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
715 PopulateConstraintsFromJavaPairList(
716 jni, j_constraints, "mandatory", &mandatory_);
717 PopulateConstraintsFromJavaPairList(
718 jni, j_constraints, "optional", &optional_);
719 }
720
721 virtual ~ConstraintsWrapper() {}
722
723 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000724 virtual const Constraints& GetMandatory() const OVERRIDE {
725 return mandatory_;
726 }
727
728 virtual const Constraints& GetOptional() const OVERRIDE {
729 return optional_;
730 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731
732 private:
733 // Helper for translating a List<Pair<String, String>> to a Constraints.
734 static void PopulateConstraintsFromJavaPairList(
735 JNIEnv* jni, jobject j_constraints,
736 const char* field_name, Constraints* field) {
737 jfieldID j_id = GetFieldID(jni,
738 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
739 jobject j_list = GetObjectField(jni, j_constraints, j_id);
740 jmethodID j_iterator_id = GetMethodID(jni,
741 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
742 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
743 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
744 jmethodID j_has_next = GetMethodID(jni,
745 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
746 jmethodID j_next = GetMethodID(jni,
747 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
748 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
749 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
750 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
751 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
752 jmethodID get_key = GetMethodID(jni,
753 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
754 jstring j_key = reinterpret_cast<jstring>(
755 jni->CallObjectMethod(entry, get_key));
756 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
757 jmethodID get_value = GetMethodID(jni,
758 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
759 jstring j_value = reinterpret_cast<jstring>(
760 jni->CallObjectMethod(entry, get_value));
761 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
762 field->push_back(Constraint(JavaToStdString(jni, j_key),
763 JavaToStdString(jni, j_value)));
764 }
765 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
766 }
767
768 Constraints mandatory_;
769 Constraints optional_;
770};
771
772static jobject JavaSdpFromNativeSdp(
773 JNIEnv* jni, const SessionDescriptionInterface* desc) {
774 std::string sdp;
775 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
fischman@webrtc.org41776152014-01-09 00:31:17 +0000776 jstring j_description = JavaStringFromStdString(jni, sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777
778 jclass j_type_class = FindClass(
779 jni, "org/webrtc/SessionDescription$Type");
780 jmethodID j_type_from_canonical = GetStaticMethodID(
781 jni, j_type_class, "fromCanonicalForm",
782 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000783 jstring j_type_string = JavaStringFromStdString(jni, desc->type());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784 jobject j_type = jni->CallStaticObjectMethod(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000785 j_type_class, j_type_from_canonical, j_type_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
787
788 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
789 jmethodID j_sdp_ctor = GetMethodID(
790 jni, j_sdp_class, "<init>",
791 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
792 jobject j_sdp = jni->NewObject(
fischman@webrtc.org41776152014-01-09 00:31:17 +0000793 j_sdp_class, j_sdp_ctor, j_type, j_description);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 CHECK_EXCEPTION(jni, "error during NewObject");
795 return j_sdp;
796}
797
798template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
799class SdpObserverWrapper : public T {
800 public:
801 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
802 ConstraintsWrapper* constraints)
803 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000804 j_observer_global_(jni, j_observer),
805 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806 }
807
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000808 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000809
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000810 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000811 virtual void OnSuccess() {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000812 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000813 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
814 jni()->CallVoidMethod(*j_observer_global_, m);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000815 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
816 }
817
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000818 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819 virtual void OnSuccess(SessionDescriptionInterface* desc) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000820 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000822 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 "(Lorg/webrtc/SessionDescription;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000824 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
825 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
827 }
828
829 protected:
830 // Common implementation for failure of Set & Create types, distinguished by
831 // |op| being "Set" or "Create".
832 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000833 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
834 "(Ljava/lang/String;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000835 jstring j_error_string = JavaStringFromStdString(jni(), error);
836 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000837 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
838 }
839
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 JNIEnv* jni() {
841 return AttachCurrentThreadIfNeeded();
842 }
843
fischman@webrtc.org41776152014-01-09 00:31:17 +0000844 private:
fischman@webrtc.org540acde2014-02-13 03:56:14 +0000845 scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000846 const ScopedGlobalRef<jobject> j_observer_global_;
847 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848};
849
850class CreateSdpObserverWrapper
851 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
852 public:
853 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
854 ConstraintsWrapper* constraints)
855 : SdpObserverWrapper(jni, j_observer, constraints) {}
856
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000857 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000858 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 SdpObserverWrapper::OnFailure(std::string("Create"), error);
860 }
861};
862
863class SetSdpObserverWrapper
864 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
865 public:
866 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
867 ConstraintsWrapper* constraints)
868 : SdpObserverWrapper(jni, j_observer, constraints) {}
869
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000870 virtual void OnFailure(const std::string& error) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000871 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872 SdpObserverWrapper::OnFailure(std::string("Set"), error);
873 }
874};
875
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000876// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
877// and dispatching the callback from C++ back to Java.
878class DataChannelObserverWrapper : public DataChannelObserver {
879 public:
880 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
881 : j_observer_global_(jni, j_observer),
882 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
883 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
884 "onStateChange", "()V")),
885 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
886 "(Lorg/webrtc/DataChannel$Buffer;)V")),
887 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
888 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
889 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
890 }
891
892 virtual ~DataChannelObserverWrapper() {}
893
894 virtual void OnStateChange() OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000895 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000896 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
897 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
898 }
899
900 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000901 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000902 jobject byte_buffer =
903 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
904 buffer.data.length());
905 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
906 byte_buffer, buffer.binary);
907 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
908 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
909 }
910
911 private:
912 JNIEnv* jni() {
913 return AttachCurrentThreadIfNeeded();
914 }
915
916 const ScopedGlobalRef<jobject> j_observer_global_;
917 const ScopedGlobalRef<jclass> j_observer_class_;
918 const ScopedGlobalRef<jclass> j_buffer_class_;
919 const jmethodID j_on_state_change_mid_;
920 const jmethodID j_on_message_mid_;
921 const jmethodID j_buffer_ctor_;
922};
923
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000924// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
925// dispatching the callback from C++ back to Java.
926class StatsObserverWrapper : public StatsObserver {
927 public:
928 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000929 : j_observer_global_(jni, j_observer),
930 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
931 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000933 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934 "(Ljava/lang/String;Ljava/lang/String;D"
935 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000936 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 jni, "org/webrtc/StatsReport$Value")),
938 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000939 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940 "(Ljava/lang/String;Ljava/lang/String;)V")) {
941 }
942
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000943 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000945 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000946 ScopedLocalRefFrame local_ref_frame(jni());
947 jobjectArray j_reports = ReportsToJava(jni(), reports);
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000948 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
949 "([Lorg/webrtc/StatsReport;)V");
fischman@webrtc.org41776152014-01-09 00:31:17 +0000950 jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
952 }
953
954 private:
955 jobjectArray ReportsToJava(
956 JNIEnv* jni, const std::vector<StatsReport>& reports) {
957 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000958 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000959 for (int i = 0; i < reports.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000960 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000961 const StatsReport& report = reports[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000962 jstring j_id = JavaStringFromStdString(jni, report.id);
963 jstring j_type = JavaStringFromStdString(jni, report.type);
964 jobjectArray j_values = ValuesToJava(jni, report.values);
965 jobject j_report = jni->NewObject(*j_stats_report_class_,
966 j_stats_report_ctor_,
967 j_id,
968 j_type,
969 report.timestamp,
970 j_values);
971 jni->SetObjectArrayElement(reports_array, i, j_report);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000972 }
973 return reports_array;
974 }
975
976 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
977 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000978 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979 for (int i = 0; i < values.size(); ++i) {
fischman@webrtc.org41776152014-01-09 00:31:17 +0000980 ScopedLocalRefFrame local_ref_frame(jni);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981 const StatsReport::Value& value = values[i];
fischman@webrtc.org41776152014-01-09 00:31:17 +0000982 jstring j_name = JavaStringFromStdString(jni, value.name);
983 jstring j_value = JavaStringFromStdString(jni, value.value);
984 jobject j_element_value =
985 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
986 jni->SetObjectArrayElement(j_values, i, j_element_value);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987 }
988 return j_values;
989 }
990
991 JNIEnv* jni() {
992 return AttachCurrentThreadIfNeeded();
993 }
994
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000995 const ScopedGlobalRef<jobject> j_observer_global_;
996 const ScopedGlobalRef<jclass> j_observer_class_;
997 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000999 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001000 const jmethodID j_value_ctor_;
1001};
1002
1003// Adapter presenting a cricket::VideoRenderer as a
1004// webrtc::VideoRendererInterface.
1005class VideoRendererWrapper : public VideoRendererInterface {
1006 public:
1007 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
1008 if (renderer)
1009 return new VideoRendererWrapper(renderer);
1010 return NULL;
1011 }
1012
1013 virtual ~VideoRendererWrapper() {}
1014
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001015 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001016 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001017 const bool kNotReserved = false; // What does this param mean??
1018 renderer_->SetSize(width, height, kNotReserved);
1019 }
1020
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001021 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001022 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001023 renderer_->RenderFrame(frame);
1024 }
1025
1026 private:
1027 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
1028 : renderer_(renderer) {}
1029
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001030 scoped_ptr<cricket::VideoRenderer> renderer_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001031};
1032
1033// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
1034// instance.
1035class JavaVideoRendererWrapper : public VideoRendererInterface {
1036 public:
1037 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001038 : j_callbacks_(jni, j_callbacks),
1039 j_set_size_id_(GetMethodID(
1040 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
1041 j_render_frame_id_(GetMethodID(
1042 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
1043 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
1044 j_frame_class_(jni,
1045 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
1046 j_frame_ctor_id_(GetMethodID(
1047 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
1048 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001049 CHECK_EXCEPTION(jni, "");
1050 }
1051
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001052 virtual ~JavaVideoRendererWrapper() {}
1053
1054 virtual void SetSize(int width, int height) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001055 ScopedLocalRefFrame local_ref_frame(jni());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001056 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
1057 CHECK_EXCEPTION(jni(), "");
1058 }
1059
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001060 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001061 ScopedLocalRefFrame local_ref_frame(jni());
1062 jobject j_frame = CricketToJavaFrame(frame);
1063 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001064 CHECK_EXCEPTION(jni(), "");
1065 }
1066
1067 private:
1068 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
1069 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
fischman@webrtc.org41776152014-01-09 00:31:17 +00001070 jintArray strides = jni()->NewIntArray(3);
1071 jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001072 strides_array[0] = frame->GetYPitch();
1073 strides_array[1] = frame->GetUPitch();
1074 strides_array[2] = frame->GetVPitch();
fischman@webrtc.org41776152014-01-09 00:31:17 +00001075 jni()->ReleaseIntArrayElements(strides, strides_array, 0);
1076 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
1077 jobject y_buffer = jni()->NewDirectByteBuffer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001078 const_cast<uint8*>(frame->GetYPlane()),
fischman@webrtc.org41776152014-01-09 00:31:17 +00001079 frame->GetYPitch() * frame->GetHeight());
1080 jobject u_buffer = jni()->NewDirectByteBuffer(
1081 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
1082 jobject v_buffer = jni()->NewDirectByteBuffer(
1083 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
1084 jni()->SetObjectArrayElement(planes, 0, y_buffer);
1085 jni()->SetObjectArrayElement(planes, 1, u_buffer);
1086 jni()->SetObjectArrayElement(planes, 2, v_buffer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001087 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001088 *j_frame_class_, j_frame_ctor_id_,
fischman@webrtc.org41776152014-01-09 00:31:17 +00001089 frame->GetWidth(), frame->GetHeight(), strides, planes);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090 }
1091
1092 JNIEnv* jni() {
1093 return AttachCurrentThreadIfNeeded();
1094 }
1095
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001096 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001097 jmethodID j_set_size_id_;
1098 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001099 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001100 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001101 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001102};
1103
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001104#ifdef ANDROID
1105// TODO(fischman): consider pulling MediaCodecVideoEncoder out of this file and
1106// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
1107// from this file.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001108
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001109// Arbitrary interval to poll the codec for new outputs.
1110enum { kMediaCodecPollMs = 10 };
1111
1112// MediaCodecVideoEncoder is a webrtc::VideoEncoder implementation that uses
1113// Android's MediaCodec SDK API behind the scenes to implement (hopefully)
1114// HW-backed video encode. This C++ class is implemented as a very thin shim,
1115// delegating all of the interesting work to org.webrtc.MediaCodecVideoEncoder.
1116// MediaCodecVideoEncoder is created, operated, and destroyed on a single
1117// thread, currently the libjingle Worker thread.
1118class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
1119 public talk_base::MessageHandler {
1120 public:
1121 virtual ~MediaCodecVideoEncoder();
1122 explicit MediaCodecVideoEncoder(JNIEnv* jni);
1123
1124 // webrtc::VideoEncoder implementation. Everything trampolines to
1125 // |codec_thread_| for execution.
1126 virtual int32_t InitEncode(const webrtc::VideoCodec* codec_settings,
1127 int32_t /* number_of_cores */,
1128 uint32_t /* max_payload_size */) OVERRIDE;
1129 virtual int32_t Encode(
1130 const webrtc::I420VideoFrame& input_image,
1131 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1132 const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
1133 virtual int32_t RegisterEncodeCompleteCallback(
1134 webrtc::EncodedImageCallback* callback) OVERRIDE;
1135 virtual int32_t Release() OVERRIDE;
1136 virtual int32_t SetChannelParameters(uint32_t /* packet_loss */,
1137 int /* rtt */) OVERRIDE;
1138 virtual int32_t SetRates(uint32_t new_bit_rate, uint32_t frame_rate) OVERRIDE;
1139
1140 // talk_base::MessageHandler implementation.
1141 virtual void OnMessage(talk_base::Message* msg) OVERRIDE;
1142
1143 private:
1144 // CHECK-fail if not running on |codec_thread_|.
1145 void CheckOnCodecThread();
1146
1147 // Release() and InitEncode() in an attempt to restore the codec to an
1148 // operable state. Necessary after all manner of OMX-layer errors.
1149 void ResetCodec();
1150
1151 // Implementation of webrtc::VideoEncoder methods above, all running on the
1152 // codec thread exclusively.
1153 //
1154 // If width==0 then this is assumed to be a re-initialization and the
1155 // previously-current values are reused instead of the passed parameters
1156 // (makes it easier to reason about thread-safety).
1157 int32_t InitEncodeOnCodecThread(int width, int height, int kbps);
1158 int32_t EncodeOnCodecThread(
1159 const webrtc::I420VideoFrame& input_image,
1160 const std::vector<webrtc::VideoFrameType>* frame_types);
1161 int32_t RegisterEncodeCompleteCallbackOnCodecThread(
1162 webrtc::EncodedImageCallback* callback);
1163 int32_t ReleaseOnCodecThread();
1164 int32_t SetRatesOnCodecThread(uint32_t new_bit_rate, uint32_t frame_rate);
1165
1166 // Reset parameters valid between InitEncode() & Release() (see below).
1167 void ResetParameters(JNIEnv* jni);
1168
1169 // Helper accessors for MediaCodecVideoEncoder$OutputBufferInfo members.
1170 int GetOutputBufferInfoIndex(JNIEnv* jni, jobject j_output_buffer_info);
1171 jobject GetOutputBufferInfoBuffer(JNIEnv* jni, jobject j_output_buffer_info);
1172 bool GetOutputBufferInfoIsKeyFrame(JNIEnv* jni, jobject j_output_buffer_info);
1173 jlong GetOutputBufferInfoPresentationTimestampUs(
1174 JNIEnv* jni,
1175 jobject j_output_buffer_info);
1176
1177 // Deliver any outputs pending in the MediaCodec to our |callback_| and return
1178 // true on success.
1179 bool DeliverPendingOutputs(JNIEnv* jni);
1180
1181 // Valid all the time since RegisterEncodeCompleteCallback() Invoke()s to
1182 // |codec_thread_| synchronously.
1183 webrtc::EncodedImageCallback* callback_;
1184
1185 // State that is constant for the lifetime of this object once the ctor
1186 // returns.
1187 scoped_ptr<Thread> codec_thread_; // Thread on which to operate MediaCodec.
1188 ScopedGlobalRef<jclass> j_media_codec_video_encoder_class_;
1189 ScopedGlobalRef<jobject> j_media_codec_video_encoder_;
1190 jmethodID j_init_encode_method_;
1191 jmethodID j_dequeue_input_buffer_method_;
1192 jmethodID j_encode_method_;
1193 jmethodID j_release_method_;
1194 jmethodID j_set_rates_method_;
1195 jmethodID j_dequeue_output_buffer_method_;
1196 jmethodID j_release_output_buffer_method_;
1197 jfieldID j_info_index_field_;
1198 jfieldID j_info_buffer_field_;
1199 jfieldID j_info_is_key_frame_field_;
1200 jfieldID j_info_presentation_timestamp_us_field_;
1201
1202 // State that is valid only between InitEncode() and the next Release().
1203 // Touched only on codec_thread_ so no explicit synchronization necessary.
1204 int width_; // Frame width in pixels.
1205 int height_; // Frame height in pixels.
1206 int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
1207 // Frame size in bytes fed to MediaCodec (stride==width, sliceHeight==height).
1208 int nv12_size_;
1209 // True only when between a callback_->Encoded() call return a positive value
1210 // and the next Encode() call being ignored.
1211 bool drop_next_input_frame_;
1212 // Global references; must be deleted in Release().
1213 std::vector<jobject> input_buffers_;
1214};
1215
1216enum { MSG_SET_RATES, MSG_POLL_FOR_READY_OUTPUTS, };
1217
1218MediaCodecVideoEncoder::~MediaCodecVideoEncoder() {
1219 // We depend on ResetParameters() to ensure no more callbacks to us after we
1220 // are deleted, so assert it here.
1221 CHECK(width_ == 0, "Release() should have been called");
1222}
1223
1224MediaCodecVideoEncoder::MediaCodecVideoEncoder(JNIEnv* jni)
1225 : callback_(NULL),
1226 codec_thread_(new Thread()),
1227 j_media_codec_video_encoder_class_(
1228 jni,
1229 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder")),
1230 j_media_codec_video_encoder_(
1231 jni,
1232 jni->NewObject(*j_media_codec_video_encoder_class_,
1233 GetMethodID(jni,
1234 *j_media_codec_video_encoder_class_,
1235 "<init>",
1236 "()V"))) {
1237 ScopedLocalRefFrame local_ref_frame(jni);
1238 // It would be nice to avoid spinning up a new thread per MediaCodec, and
1239 // instead re-use e.g. the PeerConnectionFactory's |worker_thread_|, but bug
1240 // 2732 means that deadlocks abound. This class synchronously trampolines
1241 // to |codec_thread_|, so if anything else can be coming to _us_ from
1242 // |codec_thread_|, or from any thread holding the |_sendCritSect| described
1243 // in the bug, we have a problem. For now work around that with a dedicated
1244 // thread.
1245 codec_thread_->SetName("MediaCodecVideoEncoder", NULL);
1246 CHECK(codec_thread_->Start(), "Failed to start MediaCodecVideoEncoder");
1247
1248 ResetParameters(jni);
1249
1250 jclass j_output_buffer_info_class =
1251 FindClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
1252 j_init_encode_method_ = GetMethodID(jni,
1253 *j_media_codec_video_encoder_class_,
1254 "initEncode",
1255 "(III)[Ljava/nio/ByteBuffer;");
1256 j_dequeue_input_buffer_method_ = GetMethodID(
1257 jni, *j_media_codec_video_encoder_class_, "dequeueInputBuffer", "()I");
1258 j_encode_method_ = GetMethodID(
1259 jni, *j_media_codec_video_encoder_class_, "encode", "(ZIIJ)Z");
1260 j_release_method_ =
1261 GetMethodID(jni, *j_media_codec_video_encoder_class_, "release", "()V");
1262 j_set_rates_method_ = GetMethodID(
1263 jni, *j_media_codec_video_encoder_class_, "setRates", "(II)Z");
1264 j_dequeue_output_buffer_method_ =
1265 GetMethodID(jni,
1266 *j_media_codec_video_encoder_class_,
1267 "dequeueOutputBuffer",
1268 "()Lorg/webrtc/MediaCodecVideoEncoder$OutputBufferInfo;");
1269 j_release_output_buffer_method_ = GetMethodID(
1270 jni, *j_media_codec_video_encoder_class_, "releaseOutputBuffer", "(I)Z");
1271
1272 j_info_index_field_ =
1273 GetFieldID(jni, j_output_buffer_info_class, "index", "I");
1274 j_info_buffer_field_ = GetFieldID(
1275 jni, j_output_buffer_info_class, "buffer", "Ljava/nio/ByteBuffer;");
1276 j_info_is_key_frame_field_ =
1277 GetFieldID(jni, j_output_buffer_info_class, "isKeyFrame", "Z");
1278 j_info_presentation_timestamp_us_field_ = GetFieldID(
1279 jni, j_output_buffer_info_class, "presentationTimestampUs", "J");
1280 CHECK_EXCEPTION(jni, "MediaCodecVideoEncoder ctor failed");
1281}
1282
1283int32_t MediaCodecVideoEncoder::InitEncode(
1284 const webrtc::VideoCodec* codec_settings,
1285 int32_t /* number_of_cores */,
1286 uint32_t /* max_payload_size */) {
1287 // Factory should guard against other codecs being used with us.
1288 CHECK(codec_settings->codecType == kVideoCodecVP8, "Unsupported codec");
1289
1290 return codec_thread_->Invoke<int32_t>(
1291 Bind(&MediaCodecVideoEncoder::InitEncodeOnCodecThread,
1292 this,
1293 codec_settings->width,
1294 codec_settings->height,
1295 codec_settings->startBitrate));
1296}
1297
1298int32_t MediaCodecVideoEncoder::Encode(
1299 const webrtc::I420VideoFrame& frame,
1300 const webrtc::CodecSpecificInfo* /* codec_specific_info */,
1301 const std::vector<webrtc::VideoFrameType>* frame_types) {
1302 return codec_thread_->Invoke<int32_t>(Bind(
1303 &MediaCodecVideoEncoder::EncodeOnCodecThread, this, frame, frame_types));
1304}
1305
1306int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallback(
1307 webrtc::EncodedImageCallback* callback) {
1308 return codec_thread_->Invoke<int32_t>(
1309 Bind(&MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread,
1310 this,
1311 callback));
1312}
1313
1314int32_t MediaCodecVideoEncoder::Release() {
1315 return codec_thread_->Invoke<int32_t>(
1316 Bind(&MediaCodecVideoEncoder::ReleaseOnCodecThread, this));
1317}
1318
1319int32_t MediaCodecVideoEncoder::SetChannelParameters(uint32_t /* packet_loss */,
1320 int /* rtt */) {
1321 return WEBRTC_VIDEO_CODEC_OK;
1322}
1323
1324int32_t MediaCodecVideoEncoder::SetRates(uint32_t new_bit_rate,
1325 uint32_t frame_rate) {
1326 return codec_thread_->Invoke<int32_t>(
1327 Bind(&MediaCodecVideoEncoder::SetRatesOnCodecThread,
1328 this,
1329 new_bit_rate,
1330 frame_rate));
1331}
1332
1333void MediaCodecVideoEncoder::OnMessage(talk_base::Message* msg) {
1334 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1335 ScopedLocalRefFrame local_ref_frame(jni);
1336
1337 // We only ever send one message to |this| directly (not through a Bind()'d
1338 // functor), so expect no ID/data.
1339 CHECK(!msg->message_id, "Unexpected message!");
1340 CHECK(!msg->pdata, "Unexpected message!");
1341 CheckOnCodecThread();
1342
1343 // It would be nice to recover from a failure here if one happened, but it's
1344 // unclear how to signal such a failure to the app, so instead we stay silent
1345 // about it and let the next app-called API method reveal the borkedness.
1346 DeliverPendingOutputs(jni);
1347 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1348}
1349
1350void MediaCodecVideoEncoder::CheckOnCodecThread() {
1351 CHECK(codec_thread_ == ThreadManager::Instance()->CurrentThread(),
1352 "Running on wrong thread!");
1353}
1354
1355void MediaCodecVideoEncoder::ResetCodec() {
1356 if (Release() != WEBRTC_VIDEO_CODEC_OK ||
1357 codec_thread_->Invoke<int32_t>(Bind(
1358 &MediaCodecVideoEncoder::InitEncodeOnCodecThread, this, 0, 0, 0)) !=
1359 WEBRTC_VIDEO_CODEC_OK) {
1360 // TODO(fischman): wouldn't it be nice if there was a way to gracefully
1361 // degrade to a SW encoder at this point? There isn't one AFAICT :(
1362 // https://code.google.com/p/webrtc/issues/detail?id=2920
1363 }
1364}
1365
1366int32_t MediaCodecVideoEncoder::InitEncodeOnCodecThread(
1367 int width, int height, int kbps) {
1368 CheckOnCodecThread();
1369 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1370 ScopedLocalRefFrame local_ref_frame(jni);
1371
1372 if (width == 0) {
1373 width = width_;
1374 height = height_;
1375 kbps = last_set_bitrate_kbps_;
1376 }
1377
1378 width_ = width;
1379 height_ = height;
1380 last_set_bitrate_kbps_ = kbps;
1381 nv12_size_ = width_ * height_ * 3 / 2;
1382 // We enforce no extra stride/padding in the format creation step.
1383 jobjectArray input_buffers = reinterpret_cast<jobjectArray>(
1384 jni->CallObjectMethod(*j_media_codec_video_encoder_,
1385 j_init_encode_method_,
1386 width_,
1387 height_,
1388 kbps));
1389 CHECK_EXCEPTION(jni, "");
1390 if (IsNull(jni, input_buffers))
1391 return WEBRTC_VIDEO_CODEC_ERROR;
1392
1393 size_t num_input_buffers = jni->GetArrayLength(input_buffers);
1394 CHECK(input_buffers_.empty(), "Unexpected double InitEncode without Release");
1395 input_buffers_.resize(num_input_buffers);
1396 for (size_t i = 0; i < num_input_buffers; ++i) {
1397 input_buffers_[i] =
1398 jni->NewGlobalRef(jni->GetObjectArrayElement(input_buffers, i));
1399 int64 nv12_buffer_capacity =
1400 jni->GetDirectBufferCapacity(input_buffers_[i]);
1401 CHECK_EXCEPTION(jni, "");
1402 CHECK(nv12_buffer_capacity >= nv12_size_, "Insufficient capacity");
1403 }
1404 CHECK_EXCEPTION(jni, "");
1405
1406 codec_thread_->PostDelayed(kMediaCodecPollMs, this);
1407 return WEBRTC_VIDEO_CODEC_OK;
1408}
1409
1410int32_t MediaCodecVideoEncoder::EncodeOnCodecThread(
1411 const webrtc::I420VideoFrame& frame,
1412 const std::vector<webrtc::VideoFrameType>* frame_types) {
1413 CheckOnCodecThread();
1414 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1415 ScopedLocalRefFrame local_ref_frame(jni);
1416
1417 if (!DeliverPendingOutputs(jni)) {
1418 ResetCodec();
1419 // Continue as if everything's fine.
1420 }
1421
1422 if (drop_next_input_frame_) {
1423 drop_next_input_frame_ = false;
1424 return WEBRTC_VIDEO_CODEC_OK;
1425 }
1426
1427 CHECK(frame_types->size() == 1, "Unexpected stream count");
1428 bool key_frame = frame_types->front() != webrtc::kDeltaFrame;
1429
1430 CHECK(frame.width() == width_, "Unexpected resolution change");
1431 CHECK(frame.height() == height_, "Unexpected resolution change");
1432
1433 int j_input_buffer_index = jni->CallIntMethod(*j_media_codec_video_encoder_,
1434 j_dequeue_input_buffer_method_);
1435 CHECK_EXCEPTION(jni, "");
1436 if (j_input_buffer_index == -1)
1437 return WEBRTC_VIDEO_CODEC_OK; // TODO(fischman): see webrtc bug 2887.
1438 if (j_input_buffer_index == -2) {
1439 ResetCodec();
1440 return WEBRTC_VIDEO_CODEC_ERROR;
1441 }
1442
1443 jobject j_input_buffer = input_buffers_[j_input_buffer_index];
1444 uint8* nv12_buffer =
1445 reinterpret_cast<uint8*>(jni->GetDirectBufferAddress(j_input_buffer));
1446 CHECK_EXCEPTION(jni, "");
1447 CHECK(nv12_buffer, "Indirect buffer??");
1448 CHECK(!libyuv::I420ToNV12(
1449 frame.buffer(webrtc::kYPlane),
1450 frame.stride(webrtc::kYPlane),
1451 frame.buffer(webrtc::kUPlane),
1452 frame.stride(webrtc::kUPlane),
1453 frame.buffer(webrtc::kVPlane),
1454 frame.stride(webrtc::kVPlane),
1455 nv12_buffer,
1456 frame.width(),
1457 nv12_buffer + frame.stride(webrtc::kYPlane) * frame.height(),
1458 frame.width(),
1459 frame.width(),
1460 frame.height()),
1461 "I420ToNV12 failed");
1462 jlong timestamp_us = frame.render_time_ms() * 1000;
1463 int64_t start = talk_base::Time();
1464 bool encode_status = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1465 j_encode_method_,
1466 key_frame,
1467 j_input_buffer_index,
1468 nv12_size_,
1469 timestamp_us);
1470 CHECK_EXCEPTION(jni, "");
1471 if (!encode_status || !DeliverPendingOutputs(jni)) {
1472 ResetCodec();
1473 return WEBRTC_VIDEO_CODEC_ERROR;
1474 }
1475
1476 return WEBRTC_VIDEO_CODEC_OK;
1477}
1478
1479int32_t MediaCodecVideoEncoder::RegisterEncodeCompleteCallbackOnCodecThread(
1480 webrtc::EncodedImageCallback* callback) {
1481 CheckOnCodecThread();
1482 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1483 ScopedLocalRefFrame local_ref_frame(jni);
1484 callback_ = callback;
1485 return WEBRTC_VIDEO_CODEC_OK;
1486}
1487
1488int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
1489 CheckOnCodecThread();
1490 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1491 ScopedLocalRefFrame local_ref_frame(jni);
1492 for (size_t i = 0; i < input_buffers_.size(); ++i)
1493 jni->DeleteGlobalRef(input_buffers_[i]);
1494 input_buffers_.clear();
1495 jni->CallVoidMethod(*j_media_codec_video_encoder_, j_release_method_);
1496 ResetParameters(jni);
1497 CHECK_EXCEPTION(jni, "");
1498 return WEBRTC_VIDEO_CODEC_OK;
1499}
1500
1501int32_t MediaCodecVideoEncoder::SetRatesOnCodecThread(uint32_t new_bit_rate,
1502 uint32_t frame_rate) {
1503 CheckOnCodecThread();
1504 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1505 ScopedLocalRefFrame local_ref_frame(jni);
1506 last_set_bitrate_kbps_ = new_bit_rate;
1507 bool ret = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1508 j_set_rates_method_,
1509 new_bit_rate,
1510 frame_rate);
1511 CHECK_EXCEPTION(jni, "");
1512 if (!ret) {
1513 ResetCodec();
1514 return WEBRTC_VIDEO_CODEC_ERROR;
1515 }
1516 return WEBRTC_VIDEO_CODEC_OK;
1517}
1518
1519void MediaCodecVideoEncoder::ResetParameters(JNIEnv* jni) {
1520 talk_base::MessageQueueManager::Clear(this);
1521 width_ = 0;
1522 height_ = 0;
1523 nv12_size_ = 0;
1524 drop_next_input_frame_ = false;
1525 CHECK(input_buffers_.empty(),
1526 "ResetParameters called while holding input_buffers_!");
1527}
1528
1529int MediaCodecVideoEncoder::GetOutputBufferInfoIndex(
1530 JNIEnv* jni,
1531 jobject j_output_buffer_info) {
1532 return GetIntField(jni, j_output_buffer_info, j_info_index_field_);
1533}
1534
1535jobject MediaCodecVideoEncoder::GetOutputBufferInfoBuffer(
1536 JNIEnv* jni,
1537 jobject j_output_buffer_info) {
1538 return GetObjectField(jni, j_output_buffer_info, j_info_buffer_field_);
1539}
1540
1541bool MediaCodecVideoEncoder::GetOutputBufferInfoIsKeyFrame(
1542 JNIEnv* jni,
1543 jobject j_output_buffer_info) {
1544 return GetBooleanField(jni, j_output_buffer_info, j_info_is_key_frame_field_);
1545}
1546
1547jlong MediaCodecVideoEncoder::GetOutputBufferInfoPresentationTimestampUs(
1548 JNIEnv* jni,
1549 jobject j_output_buffer_info) {
1550 return GetLongField(
1551 jni, j_output_buffer_info, j_info_presentation_timestamp_us_field_);
1552}
1553
1554bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
1555 while (true) {
1556 jobject j_output_buffer_info = jni->CallObjectMethod(
1557 *j_media_codec_video_encoder_, j_dequeue_output_buffer_method_);
1558 CHECK_EXCEPTION(jni, "");
1559 if (IsNull(jni, j_output_buffer_info))
1560 break;
1561
1562 int output_buffer_index =
1563 GetOutputBufferInfoIndex(jni, j_output_buffer_info);
1564 if (output_buffer_index == -1) {
1565 ResetCodec();
1566 return false;
1567 }
1568
1569 jlong capture_time_ms =
1570 GetOutputBufferInfoPresentationTimestampUs(jni, j_output_buffer_info) /
1571 1000;
1572
1573 int32_t callback_status = 0;
1574 if (callback_) {
1575 jobject j_output_buffer =
1576 GetOutputBufferInfoBuffer(jni, j_output_buffer_info);
1577 bool key_frame = GetOutputBufferInfoIsKeyFrame(jni, j_output_buffer_info);
1578 size_t payload_size = jni->GetDirectBufferCapacity(j_output_buffer);
1579 uint8* payload = reinterpret_cast<uint8_t*>(
1580 jni->GetDirectBufferAddress(j_output_buffer));
1581 CHECK_EXCEPTION(jni, "");
1582 scoped_ptr<webrtc::EncodedImage> image(
1583 new webrtc::EncodedImage(payload, payload_size, payload_size));
1584 image->_encodedWidth = width_;
1585 image->_encodedHeight = height_;
1586 // Convert capture time to 90 kHz RTP timestamp.
1587 image->_timeStamp = static_cast<uint32_t>(90 * capture_time_ms);
1588 image->capture_time_ms_ = capture_time_ms;
1589 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
1590 image->_completeFrame = true;
1591
1592 webrtc::CodecSpecificInfo info;
1593 memset(&info, 0, sizeof(info));
1594 info.codecType = kVideoCodecVP8;
1595 info.codecSpecific.VP8.pictureId = webrtc::kNoPictureId;
1596 info.codecSpecific.VP8.tl0PicIdx = webrtc::kNoTl0PicIdx;
1597 info.codecSpecific.VP8.keyIdx = webrtc::kNoKeyIdx;
1598
1599 // Generate a header describing a single fragment.
1600 webrtc::RTPFragmentationHeader header;
1601 memset(&header, 0, sizeof(header));
1602 header.VerifyAndAllocateFragmentationHeader(1);
1603 header.fragmentationOffset[0] = 0;
1604 header.fragmentationLength[0] = image->_length;
1605 header.fragmentationPlType[0] = 0;
1606 header.fragmentationTimeDiff[0] = 0;
1607
1608 callback_status = callback_->Encoded(*image, &info, &header);
1609 }
1610
1611 bool success = jni->CallBooleanMethod(*j_media_codec_video_encoder_,
1612 j_release_output_buffer_method_,
1613 output_buffer_index);
1614 CHECK_EXCEPTION(jni, "");
1615 if (!success) {
1616 ResetCodec();
1617 return false;
1618 }
1619
1620 if (callback_status > 0)
1621 drop_next_input_frame_ = true;
1622 // Theoretically could handle callback_status<0 here, but unclear what that
1623 // would mean for us.
1624 }
1625
1626 return true;
1627}
1628
1629// Simplest-possible implementation of an encoder factory, churns out
1630// MediaCodecVideoEncoders on demand (or errors, if that's not possible).
1631class MediaCodecVideoEncoderFactory
1632 : public cricket::WebRtcVideoEncoderFactory {
1633 public:
1634 MediaCodecVideoEncoderFactory();
1635 virtual ~MediaCodecVideoEncoderFactory();
1636
1637 // WebRtcVideoEncoderFactory implementation.
1638 virtual webrtc::VideoEncoder* CreateVideoEncoder(webrtc::VideoCodecType type)
1639 OVERRIDE;
1640 virtual void AddObserver(Observer* observer) OVERRIDE;
1641 virtual void RemoveObserver(Observer* observer) OVERRIDE;
1642 virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
1643 virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
1644
1645 private:
1646 // Empty if platform support is lacking, const after ctor returns.
1647 std::vector<VideoCodec> supported_codecs_;
1648};
1649
1650MediaCodecVideoEncoderFactory::MediaCodecVideoEncoderFactory() {
1651 JNIEnv* jni = AttachCurrentThreadIfNeeded();
1652 ScopedLocalRefFrame local_ref_frame(jni);
1653 jclass j_encoder_class = FindClass(jni, "org/webrtc/MediaCodecVideoEncoder");
1654 bool is_platform_supported = jni->CallStaticBooleanMethod(
1655 j_encoder_class,
1656 GetStaticMethodID(jni, j_encoder_class, "isPlatformSupported", "()Z"));
1657 CHECK_EXCEPTION(jni, "");
1658 if (!is_platform_supported)
1659 return;
1660
1661 if (true) {
1662 // TODO(fischman): re-enable once
1663 // https://code.google.com/p/webrtc/issues/detail?id=2899 is fixed. Until
1664 // then the Android MediaCodec experience is too abysmal to turn on.
1665 return;
1666 }
1667
1668 // Wouldn't it be nice if MediaCodec exposed the maximum capabilities of the
1669 // encoder? Sure would be. Too bad it doesn't. So we hard-code some
1670 // reasonable defaults.
1671 supported_codecs_.push_back(
1672 VideoCodec(kVideoCodecVP8, "VP8", 1920, 1088, 30));
1673}
1674
1675MediaCodecVideoEncoderFactory::~MediaCodecVideoEncoderFactory() {}
1676
1677webrtc::VideoEncoder* MediaCodecVideoEncoderFactory::CreateVideoEncoder(
1678 webrtc::VideoCodecType type) {
1679 if (type != kVideoCodecVP8 || supported_codecs_.empty())
1680 return NULL;
1681 return new MediaCodecVideoEncoder(AttachCurrentThreadIfNeeded());
1682}
1683
1684// Since the available codec list is never going to change, we ignore the
1685// Observer-related interface here.
1686void MediaCodecVideoEncoderFactory::AddObserver(Observer* observer) {}
1687void MediaCodecVideoEncoderFactory::RemoveObserver(Observer* observer) {}
1688
1689const std::vector<MediaCodecVideoEncoderFactory::VideoCodec>&
1690MediaCodecVideoEncoderFactory::codecs() const {
1691 return supported_codecs_;
1692}
1693
1694void MediaCodecVideoEncoderFactory::DestroyVideoEncoder(
1695 webrtc::VideoEncoder* encoder) {
1696 delete encoder;
1697}
1698
1699#endif // ANDROID
1700
1701} // anonymous namespace
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001702
1703// Convenience macro defining JNI-accessible methods in the org.webrtc package.
1704// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1705#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1706 Java_org_webrtc_##name
1707
1708extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1709 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1710 g_jvm = jvm;
1711 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1712
1713 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1714
1715 JNIEnv* jni;
1716 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1717 return -1;
1718 g_class_reference_holder = new ClassReferenceHolder(jni);
1719
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001720 return JNI_VERSION_1_6;
1721}
1722
1723extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001724 g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001725 delete g_class_reference_holder;
1726 g_class_reference_holder = NULL;
1727 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
1728}
1729
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001730static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001731 jfieldID native_dc_id = GetFieldID(jni,
1732 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1733 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001734 return reinterpret_cast<DataChannelInterface*>(j_d);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001735}
1736
1737JOW(jlong, DataChannel_registerObserverNative)(
1738 JNIEnv* jni, jobject j_dc, jobject j_observer) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001739 scoped_ptr<DataChannelObserverWrapper> observer(
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001740 new DataChannelObserverWrapper(jni, j_observer));
1741 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
fischman@webrtc.orgf41f06b2013-12-11 21:07:18 +00001742 return jlongFromPointer(observer.release());
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001743}
1744
1745JOW(void, DataChannel_unregisterObserverNative)(
1746 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1747 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1748 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1749}
1750
1751JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1752 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1753}
1754
1755JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1756 return JavaEnumFromIndex(
1757 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1758}
1759
1760JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1761 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1762 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1763 "buffered_amount overflowed jlong!");
1764 return static_cast<jlong>(buffered_amount);
1765}
1766
1767JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1768 ExtractNativeDC(jni, j_dc)->Close();
1769}
1770
1771JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1772 jbyteArray data, jboolean binary) {
1773 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1774 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1775 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1776 binary));
1777 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1778 return ret;
1779}
1780
1781JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001782 CHECK_RELEASE(ExtractNativeDC(jni, j_dc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001783}
1784
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001785JOW(void, Logging_nativeEnableTracing)(
1786 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels,
1787 jint nativeSeverity) {
1788 std::string path = JavaToStdString(jni, j_path);
1789 if (nativeLevels != webrtc::kTraceNone) {
andrew@webrtc.org90805182013-09-05 16:40:43 +00001790 webrtc::Trace::set_level_filter(nativeLevels);
fischman@webrtc.org7e4d0df2013-10-01 02:40:43 +00001791#ifdef ANDROID
1792 if (path != "logcat:") {
1793#endif
1794 CHECK(webrtc::Trace::SetTraceFile(path.c_str(), false) == 0,
1795 "SetTraceFile failed");
1796#ifdef ANDROID
1797 } else {
1798 // Intentionally leak this to avoid needing to reason about its lifecycle.
1799 // It keeps no state and functions only as a dispatch point.
1800 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
1801 }
1802#endif
fischman@webrtc.orgc883fdc2013-08-06 19:00:53 +00001803 }
1804 talk_base::LogMessage::LogToDebug(nativeSeverity);
1805}
1806
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001807JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001808 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809}
1810
1811JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1812 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1813 delete p;
1814}
1815
1816JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001817 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001818}
1819
1820JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1821 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1822}
1823
1824JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1825 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1826}
1827
1828JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001829 CHECK_RELEASE(reinterpret_cast<MediaStreamTrackInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001830}
1831
1832JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1833 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001834 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001835 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001836}
1837
1838JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1839 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001840 return reinterpret_cast<MediaStreamInterface*>(pointer)
1841 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001842}
1843
1844JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1845 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001846 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001847 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001848}
1849
1850JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1851 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001852 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001853 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001854}
1855
1856JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1857 return JavaStringFromStdString(
1858 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1859}
1860
1861JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001862 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001863}
1864
1865JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1866 JNIEnv * jni, jclass, jobject j_observer) {
1867 return (jlong)new PCOJava(jni, j_observer);
1868}
1869
1870#ifdef ANDROID
1871JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1872 JNIEnv* jni, jclass, jobject context) {
1873 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1874 bool failure = false;
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00001875 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001876 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1877 return !failure;
1878}
1879#endif // ANDROID
1880
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001881// Helper struct for working around the fact that CreatePeerConnectionFactory()
1882// comes in two flavors: either entirely automagical (constructing its own
1883// threads and deleting them on teardown, but no external codec factory support)
1884// or entirely manual (requires caller to delete threads after factory
1885// teardown). This struct takes ownership of its ctor's arguments to present a
1886// single thing for Java to hold and eventually free.
1887class OwnedFactoryAndThreads {
1888 public:
1889 OwnedFactoryAndThreads(Thread* worker_thread,
1890 Thread* signaling_thread,
1891 PeerConnectionFactoryInterface* factory)
1892 : worker_thread_(worker_thread),
1893 signaling_thread_(signaling_thread),
1894 factory_(factory) {}
1895
1896 ~OwnedFactoryAndThreads() { CHECK_RELEASE(factory_); }
1897
1898 PeerConnectionFactoryInterface* factory() { return factory_; }
1899
1900 private:
1901 const scoped_ptr<Thread> worker_thread_;
1902 const scoped_ptr<Thread> signaling_thread_;
1903 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor.
1904};
1905
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001906JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1907 JNIEnv* jni, jclass) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001908 webrtc::Trace::CreateTrace();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001909 Thread* worker_thread = new Thread();
1910 worker_thread->SetName("worker_thread", NULL);
1911 Thread* signaling_thread = new Thread();
1912 signaling_thread->SetName("signaling_thread", NULL);
1913 CHECK(worker_thread->Start() && signaling_thread->Start(),
1914 "Failed to start threads");
1915 scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
1916#ifdef ANDROID
1917 encoder_factory.reset(new MediaCodecVideoEncoderFactory());
1918#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001920 webrtc::CreatePeerConnectionFactory(worker_thread,
1921 signaling_thread,
1922 NULL,
1923 encoder_factory.release(),
1924 NULL));
1925 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads(
1926 worker_thread, signaling_thread, factory.release());
1927 return jlongFromPointer(owned_factory);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001928}
1929
1930JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001931 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p);
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00001932 webrtc::Trace::ReturnTrace();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001933}
1934
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001935static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) {
1936 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory();
1937}
1938
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001939JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1940 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1941 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001942 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001943 talk_base::scoped_refptr<MediaStreamInterface> stream(
1944 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1945 return (jlong)stream.release();
1946}
1947
1948JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1949 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1950 jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001951 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001952 new ConstraintsWrapper(jni, j_constraints));
1953 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001954 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955 talk_base::scoped_refptr<VideoSourceInterface> source(
1956 factory->CreateVideoSource(
1957 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1958 constraints.get()));
1959 return (jlong)source.release();
1960}
1961
1962JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1963 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1964 jlong native_source) {
1965 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001966 factoryFromJava(native_factory));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001967 talk_base::scoped_refptr<VideoTrackInterface> track(
1968 factory->CreateVideoTrack(
1969 JavaToStdString(jni, id),
1970 reinterpret_cast<VideoSourceInterface*>(native_source)));
1971 return (jlong)track.release();
1972}
1973
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00001974JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)(
1975 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) {
1976 scoped_ptr<ConstraintsWrapper> constraints(
1977 new ConstraintsWrapper(jni, j_constraints));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001978 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00001979 factoryFromJava(native_factory));
fischman@webrtc.org3eda6432014-02-13 04:01:04 +00001980 talk_base::scoped_refptr<AudioSourceInterface> source(
1981 factory->CreateAudioSource(constraints.get()));
1982 return (jlong)source.release();
1983}
1984
1985JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1986 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1987 jlong native_source) {
1988 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1989 factoryFromJava(native_factory));
1990 talk_base::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack(
1991 JavaToStdString(jni, id),
1992 reinterpret_cast<AudioSourceInterface*>(native_source)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001993 return (jlong)track.release();
1994}
1995
1996static void JavaIceServersToJsepIceServers(
1997 JNIEnv* jni, jobject j_ice_servers,
1998 PeerConnectionInterface::IceServers* ice_servers) {
1999 jclass list_class = GetObjectClass(jni, j_ice_servers);
2000 jmethodID iterator_id = GetMethodID(
2001 jni, list_class, "iterator", "()Ljava/util/Iterator;");
2002 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
2003 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2004 jmethodID iterator_has_next = GetMethodID(
2005 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
2006 jmethodID iterator_next = GetMethodID(
2007 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
2008 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
2009 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2010 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
2011 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2012 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
2013 jfieldID j_ice_server_uri_id =
2014 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
2015 jfieldID j_ice_server_username_id =
2016 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
2017 jfieldID j_ice_server_password_id =
2018 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
2019 jstring uri = reinterpret_cast<jstring>(
2020 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
2021 jstring username = reinterpret_cast<jstring>(
2022 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
2023 jstring password = reinterpret_cast<jstring>(
2024 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
2025 PeerConnectionInterface::IceServer server;
2026 server.uri = JavaToStdString(jni, uri);
2027 server.username = JavaToStdString(jni, username);
2028 server.password = JavaToStdString(jni, password);
2029 ice_servers->push_back(server);
2030 }
2031 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
2032}
2033
2034JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
2035 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
2036 jobject j_constraints, jlong observer_p) {
2037 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002038 reinterpret_cast<PeerConnectionFactoryInterface*>(
2039 factoryFromJava(factory)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002040 PeerConnectionInterface::IceServers servers;
2041 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
2042 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
2043 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
2044 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
2045 servers, observer->constraints(), NULL, observer));
2046 return (jlong)pc.release();
2047}
2048
2049static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
2050 JNIEnv* jni, jobject j_pc) {
2051 jfieldID native_pc_id = GetFieldID(jni,
2052 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
2053 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
2054 return talk_base::scoped_refptr<PeerConnectionInterface>(
2055 reinterpret_cast<PeerConnectionInterface*>(j_p));
2056}
2057
2058JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
2059 const SessionDescriptionInterface* sdp =
2060 ExtractNativePC(jni, j_pc)->local_description();
2061 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2062}
2063
2064JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
2065 const SessionDescriptionInterface* sdp =
2066 ExtractNativePC(jni, j_pc)->remote_description();
2067 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
2068}
2069
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002070JOW(jobject, PeerConnection_createDataChannel)(
2071 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
2072 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
2073 talk_base::scoped_refptr<DataChannelInterface> channel(
2074 ExtractNativePC(jni, j_pc)->CreateDataChannel(
2075 JavaToStdString(jni, j_label), &init));
fischman@webrtc.org87881672013-09-03 18:58:12 +00002076 // Mustn't pass channel.get() directly through NewObject to avoid reading its
2077 // vararg parameter as 64-bit and reading memory that doesn't belong to the
2078 // 32-bit parameter.
2079 jlong nativeChannelPtr = jlongFromPointer(channel.get());
2080 CHECK(nativeChannelPtr, "Failed to create DataChannel");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002081 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
2082 jmethodID j_data_channel_ctor = GetMethodID(
2083 jni, j_data_channel_class, "<init>", "(J)V");
2084 jobject j_channel = jni->NewObject(
fischman@webrtc.org87881672013-09-03 18:58:12 +00002085 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr);
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002086 CHECK_EXCEPTION(jni, "error during NewObject");
2087 // Channel is now owned by Java object, and will be freed from there.
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002088 int bumped_count = channel->AddRef();
2089 CHECK(bumped_count == 2, "Unexpected refcount");
henrike@webrtc.org723d6832013-07-12 16:04:50 +00002090 return j_channel;
2091}
2092
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002093JOW(void, PeerConnection_createOffer)(
2094 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2095 ConstraintsWrapper* constraints =
2096 new ConstraintsWrapper(jni, j_constraints);
2097 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2098 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2099 jni, j_observer, constraints));
2100 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
2101}
2102
2103JOW(void, PeerConnection_createAnswer)(
2104 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
2105 ConstraintsWrapper* constraints =
2106 new ConstraintsWrapper(jni, j_constraints);
2107 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
2108 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
2109 jni, j_observer, constraints));
2110 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
2111}
2112
2113// Helper to create a SessionDescriptionInterface from a SessionDescription.
2114static SessionDescriptionInterface* JavaSdpToNativeSdp(
2115 JNIEnv* jni, jobject j_sdp) {
2116 jfieldID j_type_id = GetFieldID(
2117 jni, GetObjectClass(jni, j_sdp), "type",
2118 "Lorg/webrtc/SessionDescription$Type;");
2119 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
2120 jmethodID j_canonical_form_id = GetMethodID(
2121 jni, GetObjectClass(jni, j_type), "canonicalForm",
2122 "()Ljava/lang/String;");
2123 jstring j_type_string = (jstring)jni->CallObjectMethod(
2124 j_type, j_canonical_form_id);
2125 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
2126 std::string std_type = JavaToStdString(jni, j_type_string);
2127
2128 jfieldID j_description_id = GetFieldID(
2129 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
2130 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
2131 std::string std_description = JavaToStdString(jni, j_description);
2132
2133 return webrtc::CreateSessionDescription(
2134 std_type, std_description, NULL);
2135}
2136
2137JOW(void, PeerConnection_setLocalDescription)(
2138 JNIEnv* jni, jobject j_pc,
2139 jobject j_observer, jobject j_sdp) {
2140 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2141 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2142 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2143 ExtractNativePC(jni, j_pc)->SetLocalDescription(
2144 observer, JavaSdpToNativeSdp(jni, j_sdp));
2145}
2146
2147JOW(void, PeerConnection_setRemoteDescription)(
2148 JNIEnv* jni, jobject j_pc,
2149 jobject j_observer, jobject j_sdp) {
2150 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
2151 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
2152 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
2153 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
2154 observer, JavaSdpToNativeSdp(jni, j_sdp));
2155}
2156
2157JOW(jboolean, PeerConnection_updateIce)(
2158 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
2159 PeerConnectionInterface::IceServers ice_servers;
2160 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002161 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002162 new ConstraintsWrapper(jni, j_constraints));
2163 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
2164}
2165
2166JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
2167 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
2168 jint j_sdp_mline_index, jstring j_candidate_sdp) {
2169 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
2170 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002171 scoped_ptr<IceCandidateInterface> candidate(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002172 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
2173 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
2174}
2175
2176JOW(jboolean, PeerConnection_nativeAddLocalStream)(
2177 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002178 scoped_ptr<ConstraintsWrapper> constraints(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002179 new ConstraintsWrapper(jni, j_constraints));
2180 return ExtractNativePC(jni, j_pc)->AddStream(
2181 reinterpret_cast<MediaStreamInterface*>(native_stream),
2182 constraints.get());
2183}
2184
2185JOW(void, PeerConnection_nativeRemoveLocalStream)(
2186 JNIEnv* jni, jobject j_pc, jlong native_stream) {
2187 ExtractNativePC(jni, j_pc)->RemoveStream(
2188 reinterpret_cast<MediaStreamInterface*>(native_stream));
2189}
2190
2191JOW(bool, PeerConnection_nativeGetStats)(
2192 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
2193 talk_base::scoped_refptr<StatsObserverWrapper> observer(
2194 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
2195 return ExtractNativePC(jni, j_pc)->GetStats(
2196 observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
2197}
2198
2199JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
2200 PeerConnectionInterface::SignalingState state =
2201 ExtractNativePC(jni, j_pc)->signaling_state();
2202 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
2203}
2204
2205JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
2206 PeerConnectionInterface::IceConnectionState state =
2207 ExtractNativePC(jni, j_pc)->ice_connection_state();
2208 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
2209}
2210
2211JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
2212 PeerConnectionInterface::IceGatheringState state =
2213 ExtractNativePC(jni, j_pc)->ice_gathering_state();
2214 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
2215}
2216
2217JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
2218 ExtractNativePC(jni, j_pc)->Close();
2219 return;
2220}
2221
2222JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
2223 talk_base::scoped_refptr<MediaSourceInterface> p(
2224 reinterpret_cast<MediaSourceInterface*>(j_p));
2225 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
2226}
2227
2228JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
2229 JNIEnv* jni, jclass, jstring j_device_name) {
2230 std::string device_name = JavaToStdString(jni, j_device_name);
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002231 scoped_ptr<cricket::DeviceManagerInterface> device_manager(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002232 cricket::DeviceManagerFactory::Create());
2233 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
2234 cricket::Device device;
2235 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002236 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002237 return 0;
2238 }
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002239 scoped_ptr<cricket::VideoCapturer> capturer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002240 device_manager->CreateVideoCapturer(device));
2241 return (jlong)capturer.release();
2242}
2243
2244JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
2245 JNIEnv* jni, jclass, int x, int y) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002246 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
2247 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002248 return (jlong)renderer.release();
2249}
2250
2251JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
2252 JNIEnv* jni, jclass, jobject j_callbacks) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002253 scoped_ptr<JavaVideoRendererWrapper> renderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002254 new JavaVideoRendererWrapper(jni, j_callbacks));
2255 return (jlong)renderer.release();
2256}
2257
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002258JOW(jlong, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) {
2259 cricket::VideoCapturer* capturer =
2260 reinterpret_cast<VideoSourceInterface*>(j_p)->GetVideoCapturer();
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002261 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002262 new cricket::VideoFormatPod(*capturer->GetCaptureFormat()));
2263 capturer->Stop();
2264 return jlongFromPointer(format.release());
2265}
2266
2267JOW(void, VideoSource_restart)(
2268 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) {
fischman@webrtc.org540acde2014-02-13 03:56:14 +00002269 CHECK(j_p_source, "");
2270 CHECK(j_p_format, "");
2271 scoped_ptr<cricket::VideoFormatPod> format(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002272 reinterpret_cast<cricket::VideoFormatPod*>(j_p_format));
2273 reinterpret_cast<VideoSourceInterface*>(j_p_source)->GetVideoCapturer()->
2274 StartCapturing(cricket::VideoFormat(*format));
2275}
2276
fischman@webrtc.orga7266ca2013-10-03 19:04:18 +00002277JOW(void, VideoSource_freeNativeVideoFormat)(
fischman@webrtc.org4e65e072013-10-03 18:23:13 +00002278 JNIEnv* jni, jclass, jlong j_p) {
2279 delete reinterpret_cast<cricket::VideoFormatPod*>(j_p);
2280}
2281
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002282JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002283 return JavaStringFromStdString(
2284 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002285}
2286
2287JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002288 return JavaStringFromStdString(
2289 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002290}
2291
2292JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002293 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002294}
2295
2296JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002297 return JavaEnumFromIndex(
2298 jni,
2299 "MediaStreamTrack$State",
2300 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002301}
2302
2303JOW(jboolean, MediaStreamTrack_nativeSetState)(
2304 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002305 MediaStreamTrackInterface::TrackState new_state =
2306 (MediaStreamTrackInterface::TrackState)j_new_state;
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002307 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2308 ->set_state(new_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002309}
2310
2311JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
2312 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002313 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)
2314 ->set_enabled(enabled);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002315}
2316
2317JOW(void, VideoTrack_nativeAddRenderer)(
2318 JNIEnv* jni, jclass,
2319 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002320 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002321 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2322}
2323
2324JOW(void, VideoTrack_nativeRemoveRenderer)(
2325 JNIEnv* jni, jclass,
2326 jlong j_video_track_pointer, jlong j_renderer_pointer) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +00002327 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002328 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
2329}