blob: d6a8b589d14c40fb8b16de552aa13292b9633e76 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2013, Google Inc.
4 *
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
henrike@webrtc.org723d6832013-07-12 16:04:50 +000059#include <limits>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060#include <map>
61
62#include "talk/app/webrtc/mediaconstraintsinterface.h"
63#include "talk/app/webrtc/peerconnectioninterface.h"
64#include "talk/app/webrtc/videosourceinterface.h"
65#include "talk/base/logging.h"
66#include "talk/base/ssladapter.h"
67#include "talk/media/base/videocapturer.h"
68#include "talk/media/base/videorenderer.h"
69#include "talk/media/devices/videorendererfactory.h"
70#include "talk/media/webrtc/webrtcvideocapturer.h"
71#include "third_party/icu/public/common/unicode/unistr.h"
henrike@webrtc.org9de257d2013-07-17 14:42:53 +000072#include "webrtc/system_wrappers/interface/trace.h"
73#include "webrtc/video_engine/include/vie_base.h"
74#include "webrtc/voice_engine/include/voe_base.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075
76using icu::UnicodeString;
77using webrtc::AudioSourceInterface;
78using webrtc::AudioTrackInterface;
79using webrtc::AudioTrackVector;
80using webrtc::CreateSessionDescriptionObserver;
henrike@webrtc.org723d6832013-07-12 16:04:50 +000081using webrtc::DataBuffer;
82using webrtc::DataChannelInit;
83using webrtc::DataChannelInterface;
84using webrtc::DataChannelObserver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085using webrtc::IceCandidateInterface;
86using webrtc::MediaConstraintsInterface;
87using webrtc::MediaSourceInterface;
88using webrtc::MediaStreamInterface;
89using webrtc::MediaStreamTrackInterface;
90using webrtc::PeerConnectionFactoryInterface;
91using webrtc::PeerConnectionInterface;
92using webrtc::PeerConnectionObserver;
93using webrtc::SessionDescriptionInterface;
94using webrtc::SetSessionDescriptionObserver;
95using webrtc::StatsObserver;
96using webrtc::StatsReport;
97using webrtc::VideoRendererInterface;
98using webrtc::VideoSourceInterface;
99using webrtc::VideoTrackInterface;
100using webrtc::VideoTrackVector;
101using webrtc::VideoRendererInterface;
102
103// Abort the process if |x| is false, emitting |msg|.
104#define CHECK(x, msg) \
105 if (x) {} else { \
106 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
107 abort(); \
108 }
109// Abort the process if |jni| has a Java exception pending, emitting |msg|.
110#define CHECK_EXCEPTION(jni, msg) \
111 if (0) {} else { \
112 if (jni->ExceptionCheck()) { \
113 jni->ExceptionDescribe(); \
114 jni->ExceptionClear(); \
115 CHECK(0, msg); \
116 } \
117 }
118
119namespace {
120
121static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
122
123static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
124static pthread_key_t g_jni_ptr; // Key for per-thread JNIEnv* data.
125
126static void ThreadDestructor(void* unused) {
127 jint status = g_jvm->DetachCurrentThread();
128 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
129}
130
131static void CreateJNIPtrKey() {
132 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
133 "pthread_key_create");
134}
135
136// Deal with difference in signatures between Oracle's jni.h and Android's.
137static JNIEnv* AttachCurrentThreadIfNeeded() {
138 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
139 "pthread_once");
140 JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
141 if (jni == NULL) {
142#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
143 void* env;
144#else
145 JNIEnv* env;
146#endif
147 CHECK(!g_jvm->AttachCurrentThread(&env, NULL), "Failed to attach thread");
148 CHECK(env, "AttachCurrentThread handed back NULL!");
149 jni = reinterpret_cast<JNIEnv*>(env);
150 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
151 }
152 return jni;
153}
154
155// Android's FindClass() is trickier than usual because the app-specific
156// ClassLoader is not consulted when there is no app-specific frame on the
157// stack. Consequently, we only look up classes once in JNI_OnLoad.
158// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
159class ClassReferenceHolder {
160 public:
161 explicit ClassReferenceHolder(JNIEnv* jni) {
162 LoadClass(jni, "java/nio/ByteBuffer");
163 LoadClass(jni, "org/webrtc/AudioTrack");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000164 LoadClass(jni, "org/webrtc/DataChannel");
165 LoadClass(jni, "org/webrtc/DataChannel$Buffer");
166 LoadClass(jni, "org/webrtc/DataChannel$Init");
167 LoadClass(jni, "org/webrtc/DataChannel$State");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000168 LoadClass(jni, "org/webrtc/IceCandidate");
169 LoadClass(jni, "org/webrtc/MediaSource$State");
170 LoadClass(jni, "org/webrtc/MediaStream");
171 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
172 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
173 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
174 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
175 LoadClass(jni, "org/webrtc/SessionDescription");
176 LoadClass(jni, "org/webrtc/SessionDescription$Type");
177 LoadClass(jni, "org/webrtc/StatsReport");
178 LoadClass(jni, "org/webrtc/StatsReport$Value");
179 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
180 LoadClass(jni, "org/webrtc/VideoTrack");
181 }
182
183 ~ClassReferenceHolder() {
184 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
185 }
186
187 void FreeReferences(JNIEnv* jni) {
188 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
189 it != classes_.end(); ++it) {
190 jni->DeleteGlobalRef(it->second);
191 }
192 classes_.clear();
193 }
194
195 jclass GetClass(const std::string& name) {
196 std::map<std::string, jclass>::iterator it = classes_.find(name);
197 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
198 return it->second;
199 }
200
201 private:
202 void LoadClass(JNIEnv* jni, const std::string& name) {
203 jclass localRef = jni->FindClass(name.c_str());
204 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
205 CHECK(localRef, name);
206 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
207 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
208 CHECK(globalRef, name);
209 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
210 CHECK(inserted, "Duplicate class name: " << name);
211 }
212
213 std::map<std::string, jclass> classes_;
214};
215
216// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
217static ClassReferenceHolder* g_class_reference_holder = NULL;
218
219// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
220// object/class/method/field is non-null.
221jmethodID GetMethodID(
222 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
223 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
224 CHECK_EXCEPTION(jni,
225 "error during GetMethodID: " << name << ", " << signature);
226 CHECK(m, name << ", " << signature);
227 return m;
228}
229
230jmethodID GetStaticMethodID(
231 JNIEnv* jni, jclass c, const char* name, const char* signature) {
232 jmethodID m = jni->GetStaticMethodID(c, name, signature);
233 CHECK_EXCEPTION(jni,
234 "error during GetStaticMethodID: "
235 << name << ", " << signature);
236 CHECK(m, name << ", " << signature);
237 return m;
238}
239
240jfieldID GetFieldID(
241 JNIEnv* jni, jclass c, const char* name, const char* signature) {
242 jfieldID f = jni->GetFieldID(c, name, signature);
243 CHECK_EXCEPTION(jni, "error during GetFieldID");
244 CHECK(f, name << ", " << signature);
245 return f;
246}
247
248jclass FindClass(JNIEnv* jni, const char* name) {
249 return g_class_reference_holder->GetClass(name);
250}
251
252jclass GetObjectClass(JNIEnv* jni, jobject object) {
253 jclass c = jni->GetObjectClass(object);
254 CHECK_EXCEPTION(jni, "error during GetObjectClass");
255 CHECK(c, "");
256 return c;
257}
258
259jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
260 jobject o = jni->GetObjectField(object, id);
261 CHECK_EXCEPTION(jni, "error during GetObjectField");
262 CHECK(o, "");
263 return o;
264}
265
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000266jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
267 return static_cast<jstring>(GetObjectField(jni, object, id));
268}
269
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
271 jlong l = jni->GetLongField(object, id);
272 CHECK_EXCEPTION(jni, "error during GetLongField");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000273 return l;
274}
275
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000276jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
277 jint i = jni->GetIntField(object, id);
278 CHECK_EXCEPTION(jni, "error during GetIntField");
279 return i;
280}
281
282bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
283 jboolean b = jni->GetBooleanField(object, id);
284 CHECK_EXCEPTION(jni, "error during GetBooleanField");
285 return b;
286}
287
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288jobject NewGlobalRef(JNIEnv* jni, jobject o) {
289 jobject ret = jni->NewGlobalRef(o);
290 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
291 CHECK(ret, "");
292 return ret;
293}
294
295void DeleteGlobalRef(JNIEnv* jni, jobject o) {
296 jni->DeleteGlobalRef(o);
297 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
298}
299
300// Given a jweak reference, allocate a (strong) local reference scoped to the
301// lifetime of this object if the weak reference is still valid, or NULL
302// otherwise.
303class WeakRef {
304 public:
305 WeakRef(JNIEnv* jni, jweak ref)
306 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
307 CHECK_EXCEPTION(jni, "error during NewLocalRef");
308 }
309 ~WeakRef() {
310 if (obj_) {
311 jni_->DeleteLocalRef(obj_);
312 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
313 }
314 }
315 jobject obj() { return obj_; }
316
317 private:
318 JNIEnv* const jni_;
319 jobject const obj_;
320};
321
322// Given a local ref, take ownership of it and delete the ref when this goes out
323// of scope.
324template<class T> // T is jclass, jobject, jintArray, etc.
325class ScopedLocalRef {
326 public:
327 ScopedLocalRef(JNIEnv* jni, T obj)
328 : jni_(jni), obj_(obj) {}
329 ~ScopedLocalRef() {
330 jni_->DeleteLocalRef(obj_);
331 }
332 T operator*() const {
333 return obj_;
334 }
335 private:
336 JNIEnv* jni_;
337 T obj_;
338};
339
340// Scoped holder for global Java refs.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000341template<class T> // T is jclass, jobject, jintArray, etc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000342class ScopedGlobalRef {
343 public:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000344 explicit ScopedGlobalRef(JNIEnv* jni, T obj)
345 : obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000346 ~ScopedGlobalRef() {
347 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
348 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000349 T operator*() const {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 return obj_;
351 }
352 private:
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000353 T obj_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000354};
355
356// Return the (singleton) Java Enum object corresponding to |index|;
357// |state_class_fragment| is something like "MediaSource$State".
358jobject JavaEnumFromIndex(
359 JNIEnv* jni, const std::string& state_class_fragment, int index) {
360 std::string state_class_name = "org/webrtc/" + state_class_fragment;
361 jclass state_class = FindClass(jni, state_class_name.c_str());
362 jmethodID state_values_id = GetStaticMethodID(
363 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
364 ScopedLocalRef<jobjectArray> state_values(
365 jni,
366 (jobjectArray)jni->CallStaticObjectMethod(state_class, state_values_id));
367 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
368 jobject ret = jni->GetObjectArrayElement(*state_values, index);
369 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
370 return ret;
371}
372
373// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
374static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
375 UnicodeString ustr(UnicodeString::fromUTF8(native));
376 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
377 CHECK_EXCEPTION(jni, "error during NewString");
378 return jstr;
379}
380
381// Given a (UTF-16) jstring return a new UTF-8 native string.
382static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
383 const jchar* jchars = jni->GetStringChars(j_string, NULL);
384 CHECK_EXCEPTION(jni, "Error during GetStringChars");
385 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
386 CHECK_EXCEPTION(jni, "Error during GetStringLength");
387 jni->ReleaseStringChars(j_string, jchars);
388 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
389 std::string ret;
390 return ustr.toUTF8String(ret);
391}
392
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000393static DataChannelInit JavaDataChannelInitToNative(
394 JNIEnv* jni, jobject j_init) {
395 DataChannelInit init;
396
397 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init");
398 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z");
399 jfieldID max_retransmit_time_id =
400 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I");
401 jfieldID max_retransmits_id =
402 GetFieldID(jni, j_init_class, "maxRetransmits", "I");
403 jfieldID protocol_id =
404 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;");
405 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z");
406 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I");
407
408 init.ordered = GetBooleanField(jni, j_init, ordered_id);
409 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id);
410 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id);
411 init.protocol = JavaToStdString(
412 jni, GetStringField(jni, j_init, protocol_id));
413 init.negotiated = GetBooleanField(jni, j_init, negotiated_id);
414 init.id = GetIntField(jni, j_init, id_id);
415
416 return init;
417}
418
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419class ConstraintsWrapper;
420
421// Adapter between the C++ PeerConnectionObserver interface and the Java
422// PeerConnection.Observer interface. Wraps an instance of the Java interface
423// and dispatches C++ callbacks to Java.
424class PCOJava : public PeerConnectionObserver {
425 public:
426 PCOJava(JNIEnv* jni, jobject j_observer)
427 : j_observer_global_(jni, j_observer),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000428 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)),
429 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")),
430 j_media_stream_ctor_(GetMethodID(
431 jni, *j_media_stream_class_, "<init>", "(J)V")),
432 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000433 j_audio_track_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000434 jni, *j_audio_track_class_, "<init>", "(J)V")),
435 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
436 j_video_track_ctor_(GetMethodID(
437 jni, *j_video_track_class_, "<init>", "(J)V")),
438 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
439 j_data_channel_ctor_(GetMethodID(
440 jni, *j_data_channel_class_, "<init>", "(J)V")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000441 }
442
443 virtual ~PCOJava() {}
444
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000445 virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000446 std::string sdp;
447 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
448 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
449 jmethodID ctor = GetMethodID(jni(), candidate_class,
450 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
451 ScopedLocalRef<jstring> j_mid(
452 jni(), JavaStringFromStdString(jni(), candidate->sdp_mid()));
453 ScopedLocalRef<jstring> j_sdp(jni(), JavaStringFromStdString(jni(), sdp));
454 ScopedLocalRef<jobject> j_candidate(jni(), jni()->NewObject(
455 candidate_class, ctor, *j_mid, candidate->sdp_mline_index(), *j_sdp));
456 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000457 jmethodID m = GetMethodID(jni(), *j_observer_class_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
459 jni()->CallVoidMethod(*j_observer_global_, m, *j_candidate);
460 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
461 }
462
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000463 virtual void OnError() OVERRIDE {
464 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onError", "(V)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465 jni()->CallVoidMethod(*j_observer_global_, m);
466 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
467 }
468
469 virtual void OnSignalingChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000470 PeerConnectionInterface::SignalingState new_state) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000472 jni(), *j_observer_class_, "onSignalingChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
474 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
475 jni(), "PeerConnection$SignalingState", new_state));
476 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
477 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
478 }
479
480 virtual void OnIceConnectionChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000481 PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000482 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000483 jni(), *j_observer_class_, "onIceConnectionChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000484 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
485 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
486 jni(), "PeerConnection$IceConnectionState", new_state));
487 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
488 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
489 }
490
491 virtual void OnIceGatheringChange(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000492 PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000493 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000494 jni(), *j_observer_class_, "onIceGatheringChange",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000495 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
496 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
497 jni(), "PeerConnection$IceGatheringState", new_state));
498 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
499 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
500 }
501
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000502 virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000503 ScopedLocalRef<jobject> j_stream(jni(), jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000504 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 CHECK_EXCEPTION(jni(), "error during NewObject");
506
507 AudioTrackVector audio_tracks = stream->GetAudioTracks();
508 for (size_t i = 0; i < audio_tracks.size(); ++i) {
509 AudioTrackInterface* track = audio_tracks[i];
510 ScopedLocalRef<jstring> id(
511 jni(), JavaStringFromStdString(jni(), track->id()));
512 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000513 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000514 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000515 jfieldID audio_tracks_id = GetFieldID(
516 jni(), *j_media_stream_class_, "audioTracks", "Ljava/util/List;");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000517 ScopedLocalRef<jobject> audio_tracks(jni(), GetObjectField(
518 jni(), *j_stream, audio_tracks_id));
519 jmethodID add = GetMethodID(jni(),
520 GetObjectClass(jni(), *audio_tracks), "add", "(Ljava/lang/Object;)Z");
521 jboolean added = jni()->CallBooleanMethod(*audio_tracks, add, *j_track);
522 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
523 CHECK(added, "");
524 }
525
526 VideoTrackVector video_tracks = stream->GetVideoTracks();
527 for (size_t i = 0; i < video_tracks.size(); ++i) {
528 VideoTrackInterface* track = video_tracks[i];
529 ScopedLocalRef<jstring> id(
530 jni(), JavaStringFromStdString(jni(), track->id()));
531 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000532 *j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533 CHECK_EXCEPTION(jni(), "error during NewObject");
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000534 jfieldID video_tracks_id = GetFieldID(
535 jni(), *j_media_stream_class_, "videoTracks", "Ljava/util/List;");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536 ScopedLocalRef<jobject> video_tracks(jni(), GetObjectField(
537 jni(), *j_stream, video_tracks_id));
538 jmethodID add = GetMethodID(jni(),
539 GetObjectClass(jni(), *video_tracks), "add", "(Ljava/lang/Object;)Z");
540 jboolean added = jni()->CallBooleanMethod(*video_tracks, add, *j_track);
541 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
542 CHECK(added, "");
543 }
544 streams_[stream] = jni()->NewWeakGlobalRef(*j_stream);
545 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
546
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000547 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
548 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 jni()->CallVoidMethod(*j_observer_global_, m, *j_stream);
550 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
551 }
552
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000553 virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
555 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
556
557 WeakRef s(jni(), it->second);
558 streams_.erase(it);
559 if (!s.obj())
560 return;
561
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000562 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
563 "(Lorg/webrtc/MediaStream;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
565 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
566 }
567
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000568 virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
569 ScopedLocalRef<jobject> j_channel(jni(), jni()->NewObject(
570 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel));
571 CHECK_EXCEPTION(jni(), "error during NewObject");
572 // Channel is now owned by Java object, and will be freed from
573 // DataChannel.dispose().
574 channel->AddRef();
575
576 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
577 "(Lorg/webrtc/DataChannel;)V");
578 jni()->CallVoidMethod(*j_observer_global_, m, *j_channel);
579 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
580 }
581
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 void SetConstraints(ConstraintsWrapper* constraints) {
583 CHECK(!constraints_.get(), "constraints already set!");
584 constraints_.reset(constraints);
585 }
586
587 const ConstraintsWrapper* constraints() { return constraints_.get(); }
588
589 private:
590 JNIEnv* jni() {
591 return AttachCurrentThreadIfNeeded();
592 }
593
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000594 const ScopedGlobalRef<jobject> j_observer_global_;
595 const ScopedGlobalRef<jclass> j_observer_class_;
596 const ScopedGlobalRef<jclass> j_media_stream_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000597 const jmethodID j_media_stream_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000598 const ScopedGlobalRef<jclass> j_audio_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000599 const jmethodID j_audio_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000600 const ScopedGlobalRef<jclass> j_video_track_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 const jmethodID j_video_track_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000602 const ScopedGlobalRef<jclass> j_data_channel_class_;
603 const jmethodID j_data_channel_ctor_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000604 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
605 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
606 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
607};
608
609// Wrapper for a Java MediaConstraints object. Copies all needed data so when
610// the constructor returns the Java object is no longer needed.
611class ConstraintsWrapper : public MediaConstraintsInterface {
612 public:
613 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
614 PopulateConstraintsFromJavaPairList(
615 jni, j_constraints, "mandatory", &mandatory_);
616 PopulateConstraintsFromJavaPairList(
617 jni, j_constraints, "optional", &optional_);
618 }
619
620 virtual ~ConstraintsWrapper() {}
621
622 // MediaConstraintsInterface.
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000623 virtual const Constraints& GetMandatory() const OVERRIDE {
624 return mandatory_;
625 }
626
627 virtual const Constraints& GetOptional() const OVERRIDE {
628 return optional_;
629 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630
631 private:
632 // Helper for translating a List<Pair<String, String>> to a Constraints.
633 static void PopulateConstraintsFromJavaPairList(
634 JNIEnv* jni, jobject j_constraints,
635 const char* field_name, Constraints* field) {
636 jfieldID j_id = GetFieldID(jni,
637 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
638 jobject j_list = GetObjectField(jni, j_constraints, j_id);
639 jmethodID j_iterator_id = GetMethodID(jni,
640 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
641 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
642 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
643 jmethodID j_has_next = GetMethodID(jni,
644 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
645 jmethodID j_next = GetMethodID(jni,
646 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
647 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
648 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
649 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
650 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
651 jmethodID get_key = GetMethodID(jni,
652 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
653 jstring j_key = reinterpret_cast<jstring>(
654 jni->CallObjectMethod(entry, get_key));
655 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
656 jmethodID get_value = GetMethodID(jni,
657 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
658 jstring j_value = reinterpret_cast<jstring>(
659 jni->CallObjectMethod(entry, get_value));
660 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
661 field->push_back(Constraint(JavaToStdString(jni, j_key),
662 JavaToStdString(jni, j_value)));
663 }
664 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
665 }
666
667 Constraints mandatory_;
668 Constraints optional_;
669};
670
671static jobject JavaSdpFromNativeSdp(
672 JNIEnv* jni, const SessionDescriptionInterface* desc) {
673 std::string sdp;
674 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
675 ScopedLocalRef<jstring> j_description(jni, JavaStringFromStdString(jni, sdp));
676
677 jclass j_type_class = FindClass(
678 jni, "org/webrtc/SessionDescription$Type");
679 jmethodID j_type_from_canonical = GetStaticMethodID(
680 jni, j_type_class, "fromCanonicalForm",
681 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
682 ScopedLocalRef<jstring> j_type_string(
683 jni, JavaStringFromStdString(jni, desc->type()));
684 jobject j_type = jni->CallStaticObjectMethod(
685 j_type_class, j_type_from_canonical, *j_type_string);
686 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
687
688 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
689 jmethodID j_sdp_ctor = GetMethodID(
690 jni, j_sdp_class, "<init>",
691 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
692 jobject j_sdp = jni->NewObject(
693 j_sdp_class, j_sdp_ctor, j_type, *j_description);
694 CHECK_EXCEPTION(jni, "error during NewObject");
695 return j_sdp;
696}
697
698template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
699class SdpObserverWrapper : public T {
700 public:
701 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
702 ConstraintsWrapper* constraints)
703 : constraints_(constraints),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000704 j_observer_global_(jni, j_observer),
705 j_observer_class_(jni, GetObjectClass(jni, j_observer)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706 }
707
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000708 virtual ~SdpObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000710 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711 virtual void OnSuccess() {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000712 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
713 jni()->CallVoidMethod(*j_observer_global_, m);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000714 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
715 }
716
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000717 // Can't mark OVERRIDE because of templating.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718 virtual void OnSuccess(SessionDescriptionInterface* desc) {
719 jmethodID m = GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000720 jni(), *j_observer_class_, "onCreateSuccess",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000721 "(Lorg/webrtc/SessionDescription;)V");
722 ScopedLocalRef<jobject> j_sdp(jni(), JavaSdpFromNativeSdp(jni(), desc));
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000723 jni()->CallVoidMethod(*j_observer_global_, m, *j_sdp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000724 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
725 }
726
727 protected:
728 // Common implementation for failure of Set & Create types, distinguished by
729 // |op| being "Set" or "Create".
730 void OnFailure(const std::string& op, const std::string& error) {
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000731 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
732 "(Ljava/lang/String;)V");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000733 ScopedLocalRef<jstring> j_error_string(
734 jni(), JavaStringFromStdString(jni(), error));
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000735 jni()->CallVoidMethod(*j_observer_global_, m, *j_error_string);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
737 }
738
739 private:
740 JNIEnv* jni() {
741 return AttachCurrentThreadIfNeeded();
742 }
743
744 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000745 const ScopedGlobalRef<jobject> j_observer_global_;
746 const ScopedGlobalRef<jclass> j_observer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747};
748
749class CreateSdpObserverWrapper
750 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
751 public:
752 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
753 ConstraintsWrapper* constraints)
754 : SdpObserverWrapper(jni, j_observer, constraints) {}
755
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000756 virtual void OnFailure(const std::string& error) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000757 SdpObserverWrapper::OnFailure(std::string("Create"), error);
758 }
759};
760
761class SetSdpObserverWrapper
762 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
763 public:
764 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
765 ConstraintsWrapper* constraints)
766 : SdpObserverWrapper(jni, j_observer, constraints) {}
767
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000768 virtual void OnFailure(const std::string& error) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 SdpObserverWrapper::OnFailure(std::string("Set"), error);
770 }
771};
772
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000773// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver
774// and dispatching the callback from C++ back to Java.
775class DataChannelObserverWrapper : public DataChannelObserver {
776 public:
777 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer)
778 : j_observer_global_(jni, j_observer),
779 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
780 j_on_state_change_mid_(GetMethodID(jni, *j_observer_class_,
781 "onStateChange", "()V")),
782 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage",
783 "(Lorg/webrtc/DataChannel$Buffer;)V")),
784 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")),
785 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_,
786 "<init>", "(Ljava/nio/ByteBuffer;Z)V")) {
787 }
788
789 virtual ~DataChannelObserverWrapper() {}
790
791 virtual void OnStateChange() OVERRIDE {
792 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
793 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
794 }
795
796 virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
797 jobject byte_buffer =
798 jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
799 buffer.data.length());
800 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_,
801 byte_buffer, buffer.binary);
802 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer);
803 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
804 }
805
806 private:
807 JNIEnv* jni() {
808 return AttachCurrentThreadIfNeeded();
809 }
810
811 const ScopedGlobalRef<jobject> j_observer_global_;
812 const ScopedGlobalRef<jclass> j_observer_class_;
813 const ScopedGlobalRef<jclass> j_buffer_class_;
814 const jmethodID j_on_state_change_mid_;
815 const jmethodID j_on_message_mid_;
816 const jmethodID j_buffer_ctor_;
817};
818
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000819// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
820// dispatching the callback from C++ back to Java.
821class StatsObserverWrapper : public StatsObserver {
822 public:
823 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000824 : j_observer_global_(jni, j_observer),
825 j_observer_class_(jni, GetObjectClass(jni, j_observer)),
826 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 j_stats_report_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000828 jni, *j_stats_report_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 "(Ljava/lang/String;Ljava/lang/String;D"
830 "[Lorg/webrtc/StatsReport$Value;)V")),
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000831 j_value_class_(jni, FindClass(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 jni, "org/webrtc/StatsReport$Value")),
833 j_value_ctor_(GetMethodID(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000834 jni, *j_value_class_, "<init>",
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835 "(Ljava/lang/String;Ljava/lang/String;)V")) {
836 }
837
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000838 virtual ~StatsObserverWrapper() {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000840 virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000841 ScopedLocalRef<jobjectArray> j_reports(jni(),
842 ReportsToJava(jni(), reports));
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000843 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
844 "([Lorg/webrtc/StatsReport;)V");
845 jni()->CallVoidMethod(*j_observer_global_, m, *j_reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
847 }
848
849 private:
850 jobjectArray ReportsToJava(
851 JNIEnv* jni, const std::vector<StatsReport>& reports) {
852 jobjectArray reports_array = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000853 reports.size(), *j_stats_report_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854 for (int i = 0; i < reports.size(); ++i) {
855 const StatsReport& report = reports[i];
856 ScopedLocalRef<jstring> j_id(
857 jni, JavaStringFromStdString(jni, report.id));
858 ScopedLocalRef<jstring> j_type(
859 jni, JavaStringFromStdString(jni, report.type));
860 ScopedLocalRef<jobjectArray> j_values(
861 jni, ValuesToJava(jni, report.values));
862 ScopedLocalRef<jobject> j_report(jni, jni->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000863 *j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864 report.timestamp, *j_values));
865 jni->SetObjectArrayElement(reports_array, i, *j_report);
866 }
867 return reports_array;
868 }
869
870 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
871 jobjectArray j_values = jni->NewObjectArray(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000872 values.size(), *j_value_class_, NULL);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873 for (int i = 0; i < values.size(); ++i) {
874 const StatsReport::Value& value = values[i];
875 ScopedLocalRef<jstring> j_name(
876 jni, JavaStringFromStdString(jni, value.name));
877 ScopedLocalRef<jstring> j_value(
878 jni, JavaStringFromStdString(jni, value.value));
879 ScopedLocalRef<jobject> j_element_value(jni, jni->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000880 *j_value_class_, j_value_ctor_, *j_name, *j_value));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 jni->SetObjectArrayElement(j_values, i, *j_element_value);
882 }
883 return j_values;
884 }
885
886 JNIEnv* jni() {
887 return AttachCurrentThreadIfNeeded();
888 }
889
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000890 const ScopedGlobalRef<jobject> j_observer_global_;
891 const ScopedGlobalRef<jclass> j_observer_class_;
892 const ScopedGlobalRef<jclass> j_stats_report_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893 const jmethodID j_stats_report_ctor_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000894 const ScopedGlobalRef<jclass> j_value_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000895 const jmethodID j_value_ctor_;
896};
897
898// Adapter presenting a cricket::VideoRenderer as a
899// webrtc::VideoRendererInterface.
900class VideoRendererWrapper : public VideoRendererInterface {
901 public:
902 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
903 if (renderer)
904 return new VideoRendererWrapper(renderer);
905 return NULL;
906 }
907
908 virtual ~VideoRendererWrapper() {}
909
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000910 virtual void SetSize(int width, int height) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 const bool kNotReserved = false; // What does this param mean??
912 renderer_->SetSize(width, height, kNotReserved);
913 }
914
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000915 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000916 renderer_->RenderFrame(frame);
917 }
918
919 private:
920 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
921 : renderer_(renderer) {}
922
923 talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
924};
925
926// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
927// instance.
928class JavaVideoRendererWrapper : public VideoRendererInterface {
929 public:
930 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000931 : j_callbacks_(jni, j_callbacks),
932 j_set_size_id_(GetMethodID(
933 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V")),
934 j_render_frame_id_(GetMethodID(
935 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
936 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")),
937 j_frame_class_(jni,
938 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")),
939 j_frame_ctor_id_(GetMethodID(
940 jni, *j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V")),
941 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000942 CHECK_EXCEPTION(jni, "");
943 }
944
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000945 virtual ~JavaVideoRendererWrapper() {}
946
947 virtual void SetSize(int width, int height) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000948 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
949 CHECK_EXCEPTION(jni(), "");
950 }
951
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000952 virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000953 ScopedLocalRef<jobject> j_frame(jni(), CricketToJavaFrame(frame));
954 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, *j_frame);
955 CHECK_EXCEPTION(jni(), "");
956 }
957
958 private:
959 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
960 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
961 ScopedLocalRef<jintArray> strides(jni(), jni()->NewIntArray(3));
962 jint* strides_array = jni()->GetIntArrayElements(*strides, NULL);
963 strides_array[0] = frame->GetYPitch();
964 strides_array[1] = frame->GetUPitch();
965 strides_array[2] = frame->GetVPitch();
966 jni()->ReleaseIntArrayElements(*strides, strides_array, 0);
967 ScopedLocalRef<jobjectArray> planes(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000968 jni(), jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000969 ScopedLocalRef<jobject> y_buffer(jni(), jni()->NewDirectByteBuffer(
970 const_cast<uint8*>(frame->GetYPlane()),
971 frame->GetYPitch() * frame->GetHeight()));
972 ScopedLocalRef<jobject> u_buffer(jni(), jni()->NewDirectByteBuffer(
973 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize()));
974 ScopedLocalRef<jobject> v_buffer(jni(), jni()->NewDirectByteBuffer(
975 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize()));
976 jni()->SetObjectArrayElement(*planes, 0, *y_buffer);
977 jni()->SetObjectArrayElement(*planes, 1, *u_buffer);
978 jni()->SetObjectArrayElement(*planes, 2, *v_buffer);
979 return jni()->NewObject(
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000980 *j_frame_class_, j_frame_ctor_id_,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981 frame->GetWidth(), frame->GetHeight(), *strides, *planes);
982 }
983
984 JNIEnv* jni() {
985 return AttachCurrentThreadIfNeeded();
986 }
987
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000988 ScopedGlobalRef<jobject> j_callbacks_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000989 jmethodID j_set_size_id_;
990 jmethodID j_render_frame_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000991 ScopedGlobalRef<jclass> j_frame_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000992 jmethodID j_frame_ctor_id_;
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000993 ScopedGlobalRef<jclass> j_byte_buffer_class_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000994};
995
996} // anonymous namespace
997
998
999// Convenience macro defining JNI-accessible methods in the org.webrtc package.
1000// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
1001#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
1002 Java_org_webrtc_##name
1003
1004extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
1005 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
1006 g_jvm = jvm;
1007 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
1008
1009 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
1010
1011 JNIEnv* jni;
1012 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
1013 return -1;
1014 g_class_reference_holder = new ClassReferenceHolder(jni);
1015
1016#ifdef ANDROID
1017 webrtc::Trace::CreateTrace();
1018 CHECK(!webrtc::Trace::SetTraceFile("/sdcard/trace.txt", false),
1019 "SetTraceFile failed");
1020 CHECK(!webrtc::Trace::SetLevelFilter(webrtc::kTraceAll),
1021 "SetLevelFilter failed");
1022#endif // ANDROID
1023
1024 // Uncomment to get sensitive logs emitted (to stderr or logcat).
1025 // talk_base::LogMessage::LogToDebug(talk_base::LS_SENSITIVE);
1026
1027 return JNI_VERSION_1_6;
1028}
1029
1030extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
1031 webrtc::Trace::ReturnTrace();
1032 delete g_class_reference_holder;
1033 g_class_reference_holder = NULL;
1034 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
1035}
1036
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001037static talk_base::scoped_refptr<DataChannelInterface> ExtractNativeDC(
1038 JNIEnv* jni, jobject j_dc) {
1039 jfieldID native_dc_id = GetFieldID(jni,
1040 GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
1041 jlong j_d = GetLongField(jni, j_dc, native_dc_id);
1042 return talk_base::scoped_refptr<DataChannelInterface>(
1043 reinterpret_cast<DataChannelInterface*>(j_d));
1044}
1045
1046JOW(jlong, DataChannel_registerObserverNative)(
1047 JNIEnv* jni, jobject j_dc, jobject j_observer) {
1048 talk_base::scoped_ptr<DataChannelObserverWrapper> observer(
1049 new DataChannelObserverWrapper(jni, j_observer));
1050 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get());
1051 return reinterpret_cast<jlong>(observer.release());
1052}
1053
1054JOW(void, DataChannel_unregisterObserverNative)(
1055 JNIEnv* jni, jobject j_dc, jlong native_observer) {
1056 ExtractNativeDC(jni, j_dc)->UnregisterObserver();
1057 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer);
1058}
1059
1060JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) {
1061 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label());
1062}
1063
1064JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) {
1065 return JavaEnumFromIndex(
1066 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state());
1067}
1068
1069JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) {
1070 uint64 buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount();
1071 CHECK(buffered_amount <= std::numeric_limits<int64>::max(),
1072 "buffered_amount overflowed jlong!");
1073 return static_cast<jlong>(buffered_amount);
1074}
1075
1076JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) {
1077 ExtractNativeDC(jni, j_dc)->Close();
1078}
1079
1080JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc,
1081 jbyteArray data, jboolean binary) {
1082 jbyte* bytes = jni->GetByteArrayElements(data, NULL);
1083 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer(
1084 talk_base::Buffer(bytes, jni->GetArrayLength(data)),
1085 binary));
1086 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
1087 return ret;
1088}
1089
1090JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) {
1091 ExtractNativeDC(jni, j_dc)->Release();
1092}
1093
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001094JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
1095 reinterpret_cast<PeerConnectionInterface*>(j_p)->Release();
1096}
1097
1098JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
1099 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
1100 delete p;
1101}
1102
1103JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
1104 reinterpret_cast<MediaSourceInterface*>(j_p)->Release();
1105}
1106
1107JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
1108 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
1109}
1110
1111JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
1112 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
1113}
1114
1115JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
1116 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->Release();
1117}
1118
1119JOW(jboolean, MediaStream_nativeAddAudioTrack)(
1120 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1121 talk_base::scoped_refptr<MediaStreamInterface> stream(
1122 reinterpret_cast<MediaStreamInterface*>(pointer));
1123 talk_base::scoped_refptr<AudioTrackInterface> track(
1124 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1125 return stream->AddTrack(track);
1126}
1127
1128JOW(jboolean, MediaStream_nativeAddVideoTrack)(
1129 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1130 talk_base::scoped_refptr<MediaStreamInterface> stream(
1131 reinterpret_cast<MediaStreamInterface*>(pointer));
1132 talk_base::scoped_refptr<VideoTrackInterface> track(
1133 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1134 return stream->AddTrack(track);
1135}
1136
1137JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
1138 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
1139 talk_base::scoped_refptr<MediaStreamInterface> stream(
1140 reinterpret_cast<MediaStreamInterface*>(pointer));
1141 talk_base::scoped_refptr<AudioTrackInterface> track(
1142 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
1143 return stream->RemoveTrack(track);
1144}
1145
1146JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
1147 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
1148 talk_base::scoped_refptr<MediaStreamInterface> stream(
1149 reinterpret_cast<MediaStreamInterface*>(pointer));
1150 talk_base::scoped_refptr<VideoTrackInterface> track(
1151 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1152 return stream->RemoveTrack(track);
1153}
1154
1155JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
1156 return JavaStringFromStdString(
1157 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
1158}
1159
1160JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
1161 reinterpret_cast<MediaStreamInterface*>(j_p)->Release();
1162}
1163
1164JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
1165 JNIEnv * jni, jclass, jobject j_observer) {
1166 return (jlong)new PCOJava(jni, j_observer);
1167}
1168
1169#ifdef ANDROID
1170JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1171 JNIEnv* jni, jclass, jobject context) {
1172 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1173 bool failure = false;
1174 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
1175 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1176 return !failure;
1177}
1178#endif // ANDROID
1179
1180JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1181 JNIEnv* jni, jclass) {
1182 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1183 webrtc::CreatePeerConnectionFactory());
1184 return (jlong)factory.release();
1185}
1186
1187JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
1188 reinterpret_cast<PeerConnectionFactoryInterface*>(j_p)->Release();
1189}
1190
1191JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1192 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1193 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1194 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1195 talk_base::scoped_refptr<MediaStreamInterface> stream(
1196 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1197 return (jlong)stream.release();
1198}
1199
1200JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1201 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1202 jobject j_constraints) {
1203 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1204 new ConstraintsWrapper(jni, j_constraints));
1205 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1206 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1207 talk_base::scoped_refptr<VideoSourceInterface> source(
1208 factory->CreateVideoSource(
1209 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1210 constraints.get()));
1211 return (jlong)source.release();
1212}
1213
1214JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1215 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1216 jlong native_source) {
1217 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1218 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1219 talk_base::scoped_refptr<VideoTrackInterface> track(
1220 factory->CreateVideoTrack(
1221 JavaToStdString(jni, id),
1222 reinterpret_cast<VideoSourceInterface*>(native_source)));
1223 return (jlong)track.release();
1224}
1225
1226JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1227 JNIEnv* jni, jclass, jlong native_factory, jstring id) {
1228 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1229 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1230 talk_base::scoped_refptr<AudioTrackInterface> track(
1231 factory->CreateAudioTrack(JavaToStdString(jni, id), NULL));
1232 return (jlong)track.release();
1233}
1234
1235static void JavaIceServersToJsepIceServers(
1236 JNIEnv* jni, jobject j_ice_servers,
1237 PeerConnectionInterface::IceServers* ice_servers) {
1238 jclass list_class = GetObjectClass(jni, j_ice_servers);
1239 jmethodID iterator_id = GetMethodID(
1240 jni, list_class, "iterator", "()Ljava/util/Iterator;");
1241 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
1242 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1243 jmethodID iterator_has_next = GetMethodID(
1244 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
1245 jmethodID iterator_next = GetMethodID(
1246 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
1247 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
1248 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1249 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
1250 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1251 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
1252 jfieldID j_ice_server_uri_id =
1253 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
1254 jfieldID j_ice_server_username_id =
1255 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
1256 jfieldID j_ice_server_password_id =
1257 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
1258 jstring uri = reinterpret_cast<jstring>(
1259 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
1260 jstring username = reinterpret_cast<jstring>(
1261 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
1262 jstring password = reinterpret_cast<jstring>(
1263 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
1264 PeerConnectionInterface::IceServer server;
1265 server.uri = JavaToStdString(jni, uri);
1266 server.username = JavaToStdString(jni, username);
1267 server.password = JavaToStdString(jni, password);
1268 ice_servers->push_back(server);
1269 }
1270 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1271}
1272
1273JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
1274 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
1275 jobject j_constraints, jlong observer_p) {
1276 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
1277 reinterpret_cast<PeerConnectionFactoryInterface*>(factory));
1278 PeerConnectionInterface::IceServers servers;
1279 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
1280 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
1281 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
1282 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
1283 servers, observer->constraints(), NULL, observer));
1284 return (jlong)pc.release();
1285}
1286
1287static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
1288 JNIEnv* jni, jobject j_pc) {
1289 jfieldID native_pc_id = GetFieldID(jni,
1290 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
1291 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
1292 return talk_base::scoped_refptr<PeerConnectionInterface>(
1293 reinterpret_cast<PeerConnectionInterface*>(j_p));
1294}
1295
1296JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
1297 const SessionDescriptionInterface* sdp =
1298 ExtractNativePC(jni, j_pc)->local_description();
1299 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1300}
1301
1302JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
1303 const SessionDescriptionInterface* sdp =
1304 ExtractNativePC(jni, j_pc)->remote_description();
1305 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1306}
1307
henrike@webrtc.org723d6832013-07-12 16:04:50 +00001308JOW(jobject, PeerConnection_createDataChannel)(
1309 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) {
1310 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init);
1311 talk_base::scoped_refptr<DataChannelInterface> channel(
1312 ExtractNativePC(jni, j_pc)->CreateDataChannel(
1313 JavaToStdString(jni, j_label), &init));
1314 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel");
1315 jmethodID j_data_channel_ctor = GetMethodID(
1316 jni, j_data_channel_class, "<init>", "(J)V");
1317 jobject j_channel = jni->NewObject(
1318 j_data_channel_class, j_data_channel_ctor, channel.get());
1319 CHECK_EXCEPTION(jni, "error during NewObject");
1320 // Channel is now owned by Java object, and will be freed from there.
1321 channel->AddRef();
1322 return j_channel;
1323}
1324
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325JOW(void, PeerConnection_createOffer)(
1326 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1327 ConstraintsWrapper* constraints =
1328 new ConstraintsWrapper(jni, j_constraints);
1329 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1330 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1331 jni, j_observer, constraints));
1332 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
1333}
1334
1335JOW(void, PeerConnection_createAnswer)(
1336 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1337 ConstraintsWrapper* constraints =
1338 new ConstraintsWrapper(jni, j_constraints);
1339 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1340 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1341 jni, j_observer, constraints));
1342 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
1343}
1344
1345// Helper to create a SessionDescriptionInterface from a SessionDescription.
1346static SessionDescriptionInterface* JavaSdpToNativeSdp(
1347 JNIEnv* jni, jobject j_sdp) {
1348 jfieldID j_type_id = GetFieldID(
1349 jni, GetObjectClass(jni, j_sdp), "type",
1350 "Lorg/webrtc/SessionDescription$Type;");
1351 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
1352 jmethodID j_canonical_form_id = GetMethodID(
1353 jni, GetObjectClass(jni, j_type), "canonicalForm",
1354 "()Ljava/lang/String;");
1355 jstring j_type_string = (jstring)jni->CallObjectMethod(
1356 j_type, j_canonical_form_id);
1357 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1358 std::string std_type = JavaToStdString(jni, j_type_string);
1359
1360 jfieldID j_description_id = GetFieldID(
1361 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
1362 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
1363 std::string std_description = JavaToStdString(jni, j_description);
1364
1365 return webrtc::CreateSessionDescription(
1366 std_type, std_description, NULL);
1367}
1368
1369JOW(void, PeerConnection_setLocalDescription)(
1370 JNIEnv* jni, jobject j_pc,
1371 jobject j_observer, jobject j_sdp) {
1372 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1373 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1374 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1375 ExtractNativePC(jni, j_pc)->SetLocalDescription(
1376 observer, JavaSdpToNativeSdp(jni, j_sdp));
1377}
1378
1379JOW(void, PeerConnection_setRemoteDescription)(
1380 JNIEnv* jni, jobject j_pc,
1381 jobject j_observer, jobject j_sdp) {
1382 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1383 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1384 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1385 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
1386 observer, JavaSdpToNativeSdp(jni, j_sdp));
1387}
1388
1389JOW(jboolean, PeerConnection_updateIce)(
1390 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
1391 PeerConnectionInterface::IceServers ice_servers;
1392 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
1393 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1394 new ConstraintsWrapper(jni, j_constraints));
1395 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
1396}
1397
1398JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
1399 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
1400 jint j_sdp_mline_index, jstring j_candidate_sdp) {
1401 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
1402 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
1403 talk_base::scoped_ptr<IceCandidateInterface> candidate(
1404 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
1405 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
1406}
1407
1408JOW(jboolean, PeerConnection_nativeAddLocalStream)(
1409 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
1410 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1411 new ConstraintsWrapper(jni, j_constraints));
1412 return ExtractNativePC(jni, j_pc)->AddStream(
1413 reinterpret_cast<MediaStreamInterface*>(native_stream),
1414 constraints.get());
1415}
1416
1417JOW(void, PeerConnection_nativeRemoveLocalStream)(
1418 JNIEnv* jni, jobject j_pc, jlong native_stream) {
1419 ExtractNativePC(jni, j_pc)->RemoveStream(
1420 reinterpret_cast<MediaStreamInterface*>(native_stream));
1421}
1422
1423JOW(bool, PeerConnection_nativeGetStats)(
1424 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
1425 talk_base::scoped_refptr<StatsObserverWrapper> observer(
1426 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
1427 return ExtractNativePC(jni, j_pc)->GetStats(
1428 observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
1429}
1430
1431JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
1432 PeerConnectionInterface::SignalingState state =
1433 ExtractNativePC(jni, j_pc)->signaling_state();
1434 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
1435}
1436
1437JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
1438 PeerConnectionInterface::IceConnectionState state =
1439 ExtractNativePC(jni, j_pc)->ice_connection_state();
1440 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
1441}
1442
1443JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
1444 PeerConnectionInterface::IceGatheringState state =
1445 ExtractNativePC(jni, j_pc)->ice_gathering_state();
1446 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
1447}
1448
1449JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1450 ExtractNativePC(jni, j_pc)->Close();
1451 return;
1452}
1453
1454JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1455 talk_base::scoped_refptr<MediaSourceInterface> p(
1456 reinterpret_cast<MediaSourceInterface*>(j_p));
1457 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
1458}
1459
1460JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
1461 JNIEnv* jni, jclass, jstring j_device_name) {
1462 std::string device_name = JavaToStdString(jni, j_device_name);
1463 talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
1464 cricket::DeviceManagerFactory::Create());
1465 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
1466 cricket::Device device;
1467 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
1468 LOG(LS_ERROR) << "GetVideoCaptureDevice failed";
1469 return 0;
1470 }
1471 talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1472 device_manager->CreateVideoCapturer(device));
1473 return (jlong)capturer.release();
1474}
1475
1476JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
1477 JNIEnv* jni, jclass, int x, int y) {
1478 talk_base::scoped_ptr<VideoRendererWrapper> renderer(
1479 VideoRendererWrapper::Create(
1480 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
1481 return (jlong)renderer.release();
1482}
1483
1484JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
1485 JNIEnv* jni, jclass, jobject j_callbacks) {
1486 talk_base::scoped_ptr<JavaVideoRendererWrapper> renderer(
1487 new JavaVideoRendererWrapper(jni, j_callbacks));
1488 return (jlong)renderer.release();
1489}
1490
1491JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
1492 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1493 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1494 return JavaStringFromStdString(jni, p->id());
1495}
1496
1497JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
1498 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1499 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1500 return JavaStringFromStdString(jni, p->kind());
1501}
1502
1503JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
1504 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1505 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1506 return p->enabled();
1507}
1508
1509JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1510 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1511 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1512 return JavaEnumFromIndex(jni, "MediaStreamTrack$State", p->state());
1513}
1514
1515JOW(jboolean, MediaStreamTrack_nativeSetState)(
1516 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
1517 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1518 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1519 MediaStreamTrackInterface::TrackState new_state =
1520 (MediaStreamTrackInterface::TrackState)j_new_state;
1521 return p->set_state(new_state);
1522}
1523
1524JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
1525 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
1526 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1527 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1528 return p->set_enabled(enabled);
1529}
1530
1531JOW(void, VideoTrack_nativeAddRenderer)(
1532 JNIEnv* jni, jclass,
1533 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1534 talk_base::scoped_refptr<VideoTrackInterface> track(
1535 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1536 track->AddRenderer(
1537 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1538}
1539
1540JOW(void, VideoTrack_nativeRemoveRenderer)(
1541 JNIEnv* jni, jclass,
1542 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1543 talk_base::scoped_refptr<VideoTrackInterface> track(
1544 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1545 track->RemoveRenderer(
1546 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1547}