blob: 6b5a6a48c8ea8f83def219cab63bea70953bcd92 [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
59#include <map>
60
61#include "talk/app/webrtc/mediaconstraintsinterface.h"
62#include "talk/app/webrtc/peerconnectioninterface.h"
63#include "talk/app/webrtc/videosourceinterface.h"
64#include "talk/base/logging.h"
65#include "talk/base/ssladapter.h"
66#include "talk/media/base/videocapturer.h"
67#include "talk/media/base/videorenderer.h"
68#include "talk/media/devices/videorendererfactory.h"
69#include "talk/media/webrtc/webrtcvideocapturer.h"
70#include "third_party/icu/public/common/unicode/unistr.h"
71#include "third_party/webrtc/system_wrappers/interface/trace.h"
72#include "third_party/webrtc/video_engine/include/vie_base.h"
73#include "third_party/webrtc/voice_engine/include/voe_base.h"
74
75using icu::UnicodeString;
76using webrtc::AudioSourceInterface;
77using webrtc::AudioTrackInterface;
78using webrtc::AudioTrackVector;
79using webrtc::CreateSessionDescriptionObserver;
80using webrtc::IceCandidateInterface;
81using webrtc::MediaConstraintsInterface;
82using webrtc::MediaSourceInterface;
83using webrtc::MediaStreamInterface;
84using webrtc::MediaStreamTrackInterface;
85using webrtc::PeerConnectionFactoryInterface;
86using webrtc::PeerConnectionInterface;
87using webrtc::PeerConnectionObserver;
88using webrtc::SessionDescriptionInterface;
89using webrtc::SetSessionDescriptionObserver;
90using webrtc::StatsObserver;
91using webrtc::StatsReport;
92using webrtc::VideoRendererInterface;
93using webrtc::VideoSourceInterface;
94using webrtc::VideoTrackInterface;
95using webrtc::VideoTrackVector;
96using webrtc::VideoRendererInterface;
97
98// Abort the process if |x| is false, emitting |msg|.
99#define CHECK(x, msg) \
100 if (x) {} else { \
101 LOG(LS_ERROR) << __FILE__ << ":" << __LINE__ << ": " << msg; \
102 abort(); \
103 }
104// Abort the process if |jni| has a Java exception pending, emitting |msg|.
105#define CHECK_EXCEPTION(jni, msg) \
106 if (0) {} else { \
107 if (jni->ExceptionCheck()) { \
108 jni->ExceptionDescribe(); \
109 jni->ExceptionClear(); \
110 CHECK(0, msg); \
111 } \
112 }
113
114namespace {
115
116static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
117
118static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
119static pthread_key_t g_jni_ptr; // Key for per-thread JNIEnv* data.
120
121static void ThreadDestructor(void* unused) {
122 jint status = g_jvm->DetachCurrentThread();
123 CHECK(status == JNI_OK, "Failed to detach thread: " << status);
124}
125
126static void CreateJNIPtrKey() {
127 CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor),
128 "pthread_key_create");
129}
130
131// Deal with difference in signatures between Oracle's jni.h and Android's.
132static JNIEnv* AttachCurrentThreadIfNeeded() {
133 CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey),
134 "pthread_once");
135 JNIEnv* jni = reinterpret_cast<JNIEnv*>(pthread_getspecific(g_jni_ptr));
136 if (jni == NULL) {
137#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
138 void* env;
139#else
140 JNIEnv* env;
141#endif
142 CHECK(!g_jvm->AttachCurrentThread(&env, NULL), "Failed to attach thread");
143 CHECK(env, "AttachCurrentThread handed back NULL!");
144 jni = reinterpret_cast<JNIEnv*>(env);
145 CHECK(!pthread_setspecific(g_jni_ptr, jni), "pthread_setspecific");
146 }
147 return jni;
148}
149
150// Android's FindClass() is trickier than usual because the app-specific
151// ClassLoader is not consulted when there is no app-specific frame on the
152// stack. Consequently, we only look up classes once in JNI_OnLoad.
153// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
154class ClassReferenceHolder {
155 public:
156 explicit ClassReferenceHolder(JNIEnv* jni) {
157 LoadClass(jni, "java/nio/ByteBuffer");
158 LoadClass(jni, "org/webrtc/AudioTrack");
159 LoadClass(jni, "org/webrtc/IceCandidate");
160 LoadClass(jni, "org/webrtc/MediaSource$State");
161 LoadClass(jni, "org/webrtc/MediaStream");
162 LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
163 LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
164 LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
165 LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
166 LoadClass(jni, "org/webrtc/SessionDescription");
167 LoadClass(jni, "org/webrtc/SessionDescription$Type");
168 LoadClass(jni, "org/webrtc/StatsReport");
169 LoadClass(jni, "org/webrtc/StatsReport$Value");
170 LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
171 LoadClass(jni, "org/webrtc/VideoTrack");
172 }
173
174 ~ClassReferenceHolder() {
175 CHECK(classes_.empty(), "Must call FreeReferences() before dtor!");
176 }
177
178 void FreeReferences(JNIEnv* jni) {
179 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
180 it != classes_.end(); ++it) {
181 jni->DeleteGlobalRef(it->second);
182 }
183 classes_.clear();
184 }
185
186 jclass GetClass(const std::string& name) {
187 std::map<std::string, jclass>::iterator it = classes_.find(name);
188 CHECK(it != classes_.end(), "Unexpected GetClass() call for: " << name);
189 return it->second;
190 }
191
192 private:
193 void LoadClass(JNIEnv* jni, const std::string& name) {
194 jclass localRef = jni->FindClass(name.c_str());
195 CHECK_EXCEPTION(jni, "error during FindClass: " << name);
196 CHECK(localRef, name);
197 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
198 CHECK_EXCEPTION(jni, "error during NewGlobalRef: " << name);
199 CHECK(globalRef, name);
200 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
201 CHECK(inserted, "Duplicate class name: " << name);
202 }
203
204 std::map<std::string, jclass> classes_;
205};
206
207// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
208static ClassReferenceHolder* g_class_reference_holder = NULL;
209
210// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
211// object/class/method/field is non-null.
212jmethodID GetMethodID(
213 JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
214 jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
215 CHECK_EXCEPTION(jni,
216 "error during GetMethodID: " << name << ", " << signature);
217 CHECK(m, name << ", " << signature);
218 return m;
219}
220
221jmethodID GetStaticMethodID(
222 JNIEnv* jni, jclass c, const char* name, const char* signature) {
223 jmethodID m = jni->GetStaticMethodID(c, name, signature);
224 CHECK_EXCEPTION(jni,
225 "error during GetStaticMethodID: "
226 << name << ", " << signature);
227 CHECK(m, name << ", " << signature);
228 return m;
229}
230
231jfieldID GetFieldID(
232 JNIEnv* jni, jclass c, const char* name, const char* signature) {
233 jfieldID f = jni->GetFieldID(c, name, signature);
234 CHECK_EXCEPTION(jni, "error during GetFieldID");
235 CHECK(f, name << ", " << signature);
236 return f;
237}
238
239jclass FindClass(JNIEnv* jni, const char* name) {
240 return g_class_reference_holder->GetClass(name);
241}
242
243jclass GetObjectClass(JNIEnv* jni, jobject object) {
244 jclass c = jni->GetObjectClass(object);
245 CHECK_EXCEPTION(jni, "error during GetObjectClass");
246 CHECK(c, "");
247 return c;
248}
249
250jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
251 jobject o = jni->GetObjectField(object, id);
252 CHECK_EXCEPTION(jni, "error during GetObjectField");
253 CHECK(o, "");
254 return o;
255}
256
257jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
258 jlong l = jni->GetLongField(object, id);
259 CHECK_EXCEPTION(jni, "error during GetLongField");
260 CHECK(l, "");
261 return l;
262}
263
264jobject NewGlobalRef(JNIEnv* jni, jobject o) {
265 jobject ret = jni->NewGlobalRef(o);
266 CHECK_EXCEPTION(jni, "error during NewGlobalRef");
267 CHECK(ret, "");
268 return ret;
269}
270
271void DeleteGlobalRef(JNIEnv* jni, jobject o) {
272 jni->DeleteGlobalRef(o);
273 CHECK_EXCEPTION(jni, "error during DeleteGlobalRef");
274}
275
276// Given a jweak reference, allocate a (strong) local reference scoped to the
277// lifetime of this object if the weak reference is still valid, or NULL
278// otherwise.
279class WeakRef {
280 public:
281 WeakRef(JNIEnv* jni, jweak ref)
282 : jni_(jni), obj_(jni_->NewLocalRef(ref)) {
283 CHECK_EXCEPTION(jni, "error during NewLocalRef");
284 }
285 ~WeakRef() {
286 if (obj_) {
287 jni_->DeleteLocalRef(obj_);
288 CHECK_EXCEPTION(jni_, "error during DeleteLocalRef");
289 }
290 }
291 jobject obj() { return obj_; }
292
293 private:
294 JNIEnv* const jni_;
295 jobject const obj_;
296};
297
298// Given a local ref, take ownership of it and delete the ref when this goes out
299// of scope.
300template<class T> // T is jclass, jobject, jintArray, etc.
301class ScopedLocalRef {
302 public:
303 ScopedLocalRef(JNIEnv* jni, T obj)
304 : jni_(jni), obj_(obj) {}
305 ~ScopedLocalRef() {
306 jni_->DeleteLocalRef(obj_);
307 }
308 T operator*() const {
309 return obj_;
310 }
311 private:
312 JNIEnv* jni_;
313 T obj_;
314};
315
316// Scoped holder for global Java refs.
317class ScopedGlobalRef {
318 public:
319 explicit ScopedGlobalRef(JNIEnv* jni, jobject obj)
320 : obj_(jni->NewGlobalRef(obj)) {}
321 ~ScopedGlobalRef() {
322 DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
323 }
324 jobject operator*() const {
325 return obj_;
326 }
327 private:
328 jobject obj_;
329};
330
331// Return the (singleton) Java Enum object corresponding to |index|;
332// |state_class_fragment| is something like "MediaSource$State".
333jobject JavaEnumFromIndex(
334 JNIEnv* jni, const std::string& state_class_fragment, int index) {
335 std::string state_class_name = "org/webrtc/" + state_class_fragment;
336 jclass state_class = FindClass(jni, state_class_name.c_str());
337 jmethodID state_values_id = GetStaticMethodID(
338 jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
339 ScopedLocalRef<jobjectArray> state_values(
340 jni,
341 (jobjectArray)jni->CallStaticObjectMethod(state_class, state_values_id));
342 CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
343 jobject ret = jni->GetObjectArrayElement(*state_values, index);
344 CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
345 return ret;
346}
347
348// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
349static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
350 UnicodeString ustr(UnicodeString::fromUTF8(native));
351 jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
352 CHECK_EXCEPTION(jni, "error during NewString");
353 return jstr;
354}
355
356// Given a (UTF-16) jstring return a new UTF-8 native string.
357static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
358 const jchar* jchars = jni->GetStringChars(j_string, NULL);
359 CHECK_EXCEPTION(jni, "Error during GetStringChars");
360 UnicodeString ustr(jchars, jni->GetStringLength(j_string));
361 CHECK_EXCEPTION(jni, "Error during GetStringLength");
362 jni->ReleaseStringChars(j_string, jchars);
363 CHECK_EXCEPTION(jni, "Error during ReleaseStringChars");
364 std::string ret;
365 return ustr.toUTF8String(ret);
366}
367
368class ConstraintsWrapper;
369
370// Adapter between the C++ PeerConnectionObserver interface and the Java
371// PeerConnection.Observer interface. Wraps an instance of the Java interface
372// and dispatches C++ callbacks to Java.
373class PCOJava : public PeerConnectionObserver {
374 public:
375 PCOJava(JNIEnv* jni, jobject j_observer)
376 : j_observer_global_(jni, j_observer),
377 j_observer_class_((jclass)NewGlobalRef(
378 jni, GetObjectClass(jni, *j_observer_global_))),
379 j_media_stream_class_((jclass)NewGlobalRef(
380 jni, FindClass(jni, "org/webrtc/MediaStream"))),
381 j_media_stream_ctor_(GetMethodID(jni,
382 j_media_stream_class_, "<init>", "(J)V")),
383 j_audio_track_class_((jclass)NewGlobalRef(
384 jni, FindClass(jni, "org/webrtc/AudioTrack"))),
385 j_audio_track_ctor_(GetMethodID(
386 jni, j_audio_track_class_, "<init>", "(J)V")),
387 j_video_track_class_((jclass)NewGlobalRef(
388 jni, FindClass(jni, "org/webrtc/VideoTrack"))),
389 j_video_track_ctor_(GetMethodID(jni,
390 j_video_track_class_, "<init>", "(J)V")) {
391 }
392
393 virtual ~PCOJava() {}
394
395 virtual void OnIceCandidate(const IceCandidateInterface* candidate) {
396 std::string sdp;
397 CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
398 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
399 jmethodID ctor = GetMethodID(jni(), candidate_class,
400 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
401 ScopedLocalRef<jstring> j_mid(
402 jni(), JavaStringFromStdString(jni(), candidate->sdp_mid()));
403 ScopedLocalRef<jstring> j_sdp(jni(), JavaStringFromStdString(jni(), sdp));
404 ScopedLocalRef<jobject> j_candidate(jni(), jni()->NewObject(
405 candidate_class, ctor, *j_mid, candidate->sdp_mline_index(), *j_sdp));
406 CHECK_EXCEPTION(jni(), "error during NewObject");
407 jmethodID m = GetMethodID(jni(), j_observer_class_,
408 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
409 jni()->CallVoidMethod(*j_observer_global_, m, *j_candidate);
410 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
411 }
412
413 virtual void OnError() {
414 jmethodID m = GetMethodID(jni(), j_observer_class_, "onError", "(V)V");
415 jni()->CallVoidMethod(*j_observer_global_, m);
416 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
417 }
418
419 virtual void OnSignalingChange(
420 PeerConnectionInterface::SignalingState new_state) {
421 jmethodID m = GetMethodID(
422 jni(), j_observer_class_, "onSignalingChange",
423 "(Lorg/webrtc/PeerConnection$SignalingState;)V");
424 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
425 jni(), "PeerConnection$SignalingState", new_state));
426 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
427 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
428 }
429
430 virtual void OnIceConnectionChange(
431 PeerConnectionInterface::IceConnectionState new_state) {
432 jmethodID m = GetMethodID(
433 jni(), j_observer_class_, "onIceConnectionChange",
434 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
435 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
436 jni(), "PeerConnection$IceConnectionState", new_state));
437 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
438 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
439 }
440
441 virtual void OnIceGatheringChange(
442 PeerConnectionInterface::IceGatheringState new_state) {
443 jmethodID m = GetMethodID(
444 jni(), j_observer_class_, "onIceGatheringChange",
445 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
446 ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex(
447 jni(), "PeerConnection$IceGatheringState", new_state));
448 jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum);
449 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
450 }
451
452 virtual void OnAddStream(MediaStreamInterface* stream) {
453 ScopedLocalRef<jobject> j_stream(jni(), jni()->NewObject(
454 j_media_stream_class_, j_media_stream_ctor_, (jlong)stream));
455 CHECK_EXCEPTION(jni(), "error during NewObject");
456
457 AudioTrackVector audio_tracks = stream->GetAudioTracks();
458 for (size_t i = 0; i < audio_tracks.size(); ++i) {
459 AudioTrackInterface* track = audio_tracks[i];
460 ScopedLocalRef<jstring> id(
461 jni(), JavaStringFromStdString(jni(), track->id()));
462 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
463 j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
464 CHECK_EXCEPTION(jni(), "error during NewObject");
465 jfieldID audio_tracks_id = GetFieldID(jni(),
466 j_media_stream_class_, "audioTracks", "Ljava/util/List;");
467 ScopedLocalRef<jobject> audio_tracks(jni(), GetObjectField(
468 jni(), *j_stream, audio_tracks_id));
469 jmethodID add = GetMethodID(jni(),
470 GetObjectClass(jni(), *audio_tracks), "add", "(Ljava/lang/Object;)Z");
471 jboolean added = jni()->CallBooleanMethod(*audio_tracks, add, *j_track);
472 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
473 CHECK(added, "");
474 }
475
476 VideoTrackVector video_tracks = stream->GetVideoTracks();
477 for (size_t i = 0; i < video_tracks.size(); ++i) {
478 VideoTrackInterface* track = video_tracks[i];
479 ScopedLocalRef<jstring> id(
480 jni(), JavaStringFromStdString(jni(), track->id()));
481 ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject(
482 j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
483 CHECK_EXCEPTION(jni(), "error during NewObject");
484 jfieldID video_tracks_id = GetFieldID(jni(),
485 j_media_stream_class_, "videoTracks", "Ljava/util/List;");
486 ScopedLocalRef<jobject> video_tracks(jni(), GetObjectField(
487 jni(), *j_stream, video_tracks_id));
488 jmethodID add = GetMethodID(jni(),
489 GetObjectClass(jni(), *video_tracks), "add", "(Ljava/lang/Object;)Z");
490 jboolean added = jni()->CallBooleanMethod(*video_tracks, add, *j_track);
491 CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
492 CHECK(added, "");
493 }
494 streams_[stream] = jni()->NewWeakGlobalRef(*j_stream);
495 CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
496
497 jmethodID m = GetMethodID(jni(),
498 j_observer_class_, "onAddStream", "(Lorg/webrtc/MediaStream;)V");
499 jni()->CallVoidMethod(*j_observer_global_, m, *j_stream);
500 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
501 }
502
503 virtual void OnRemoveStream(MediaStreamInterface* stream) {
504 NativeToJavaStreamsMap::iterator it = streams_.find(stream);
505 CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
506
507 WeakRef s(jni(), it->second);
508 streams_.erase(it);
509 if (!s.obj())
510 return;
511
512 jmethodID m = GetMethodID(jni(),
513 j_observer_class_, "onRemoveStream", "(Lorg/webrtc/MediaStream;)V");
514 jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
515 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
516 }
517
518 void SetConstraints(ConstraintsWrapper* constraints) {
519 CHECK(!constraints_.get(), "constraints already set!");
520 constraints_.reset(constraints);
521 }
522
523 const ConstraintsWrapper* constraints() { return constraints_.get(); }
524
525 private:
526 JNIEnv* jni() {
527 return AttachCurrentThreadIfNeeded();
528 }
529
530 const ScopedGlobalRef j_observer_global_;
531 const jclass j_observer_class_;
532 const jclass j_media_stream_class_;
533 const jmethodID j_media_stream_ctor_;
534 const jclass j_audio_track_class_;
535 const jmethodID j_audio_track_ctor_;
536 const jclass j_video_track_class_;
537 const jmethodID j_video_track_ctor_;
538 typedef std::map<void*, jweak> NativeToJavaStreamsMap;
539 NativeToJavaStreamsMap streams_; // C++ -> Java streams.
540 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
541};
542
543// Wrapper for a Java MediaConstraints object. Copies all needed data so when
544// the constructor returns the Java object is no longer needed.
545class ConstraintsWrapper : public MediaConstraintsInterface {
546 public:
547 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
548 PopulateConstraintsFromJavaPairList(
549 jni, j_constraints, "mandatory", &mandatory_);
550 PopulateConstraintsFromJavaPairList(
551 jni, j_constraints, "optional", &optional_);
552 }
553
554 virtual ~ConstraintsWrapper() {}
555
556 // MediaConstraintsInterface.
557 virtual const Constraints& GetMandatory() const { return mandatory_; }
558 virtual const Constraints& GetOptional() const { return optional_; }
559
560 private:
561 // Helper for translating a List<Pair<String, String>> to a Constraints.
562 static void PopulateConstraintsFromJavaPairList(
563 JNIEnv* jni, jobject j_constraints,
564 const char* field_name, Constraints* field) {
565 jfieldID j_id = GetFieldID(jni,
566 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;");
567 jobject j_list = GetObjectField(jni, j_constraints, j_id);
568 jmethodID j_iterator_id = GetMethodID(jni,
569 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;");
570 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id);
571 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
572 jmethodID j_has_next = GetMethodID(jni,
573 GetObjectClass(jni, j_iterator), "hasNext", "()Z");
574 jmethodID j_next = GetMethodID(jni,
575 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;");
576 while (jni->CallBooleanMethod(j_iterator, j_has_next)) {
577 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
578 jobject entry = jni->CallObjectMethod(j_iterator, j_next);
579 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
580 jmethodID get_key = GetMethodID(jni,
581 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;");
582 jstring j_key = reinterpret_cast<jstring>(
583 jni->CallObjectMethod(entry, get_key));
584 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
585 jmethodID get_value = GetMethodID(jni,
586 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;");
587 jstring j_value = reinterpret_cast<jstring>(
588 jni->CallObjectMethod(entry, get_value));
589 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
590 field->push_back(Constraint(JavaToStdString(jni, j_key),
591 JavaToStdString(jni, j_value)));
592 }
593 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
594 }
595
596 Constraints mandatory_;
597 Constraints optional_;
598};
599
600static jobject JavaSdpFromNativeSdp(
601 JNIEnv* jni, const SessionDescriptionInterface* desc) {
602 std::string sdp;
603 CHECK(desc->ToString(&sdp), "got so far: " << sdp);
604 ScopedLocalRef<jstring> j_description(jni, JavaStringFromStdString(jni, sdp));
605
606 jclass j_type_class = FindClass(
607 jni, "org/webrtc/SessionDescription$Type");
608 jmethodID j_type_from_canonical = GetStaticMethodID(
609 jni, j_type_class, "fromCanonicalForm",
610 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
611 ScopedLocalRef<jstring> j_type_string(
612 jni, JavaStringFromStdString(jni, desc->type()));
613 jobject j_type = jni->CallStaticObjectMethod(
614 j_type_class, j_type_from_canonical, *j_type_string);
615 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
616
617 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
618 jmethodID j_sdp_ctor = GetMethodID(
619 jni, j_sdp_class, "<init>",
620 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
621 jobject j_sdp = jni->NewObject(
622 j_sdp_class, j_sdp_ctor, j_type, *j_description);
623 CHECK_EXCEPTION(jni, "error during NewObject");
624 return j_sdp;
625}
626
627template <class T> // T is one of {Create,Set}SessionDescriptionObserver.
628class SdpObserverWrapper : public T {
629 public:
630 SdpObserverWrapper(JNIEnv* jni, jobject j_observer,
631 ConstraintsWrapper* constraints)
632 : constraints_(constraints),
633 j_observer_global_(NewGlobalRef(jni, j_observer)),
634 j_observer_class_((jclass)NewGlobalRef(
635 jni, GetObjectClass(jni, j_observer))) {
636 }
637
638 virtual ~SdpObserverWrapper() {
639 DeleteGlobalRef(jni(), j_observer_global_);
640 DeleteGlobalRef(jni(), j_observer_class_);
641 }
642
643 virtual void OnSuccess() {
644 jmethodID m = GetMethodID(jni(), j_observer_class_, "onSetSuccess", "()V");
645 jni()->CallVoidMethod(j_observer_global_, m);
646 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
647 }
648
649 virtual void OnSuccess(SessionDescriptionInterface* desc) {
650 jmethodID m = GetMethodID(
651 jni(), j_observer_class_, "onCreateSuccess",
652 "(Lorg/webrtc/SessionDescription;)V");
653 ScopedLocalRef<jobject> j_sdp(jni(), JavaSdpFromNativeSdp(jni(), desc));
654 jni()->CallVoidMethod(j_observer_global_, m, *j_sdp);
655 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
656 }
657
658 protected:
659 // Common implementation for failure of Set & Create types, distinguished by
660 // |op| being "Set" or "Create".
661 void OnFailure(const std::string& op, const std::string& error) {
662 jmethodID m = GetMethodID(jni(),
663 j_observer_class_, "on" + op + "Failure", "(Ljava/lang/String;)V");
664 ScopedLocalRef<jstring> j_error_string(
665 jni(), JavaStringFromStdString(jni(), error));
666 jni()->CallVoidMethod(j_observer_global_, m, *j_error_string);
667 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
668 }
669
670 private:
671 JNIEnv* jni() {
672 return AttachCurrentThreadIfNeeded();
673 }
674
675 talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
676 const jobject j_observer_global_;
677 const jclass j_observer_class_;
678};
679
680class CreateSdpObserverWrapper
681 : public SdpObserverWrapper<CreateSessionDescriptionObserver> {
682 public:
683 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
684 ConstraintsWrapper* constraints)
685 : SdpObserverWrapper(jni, j_observer, constraints) {}
686
687 virtual void OnFailure(const std::string& error) {
688 SdpObserverWrapper::OnFailure(std::string("Create"), error);
689 }
690};
691
692class SetSdpObserverWrapper
693 : public SdpObserverWrapper<SetSessionDescriptionObserver> {
694 public:
695 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer,
696 ConstraintsWrapper* constraints)
697 : SdpObserverWrapper(jni, j_observer, constraints) {}
698
699 virtual void OnFailure(const std::string& error) {
700 SdpObserverWrapper::OnFailure(std::string("Set"), error);
701 }
702};
703
704// Adapter for a Java StatsObserver presenting a C++ StatsObserver and
705// dispatching the callback from C++ back to Java.
706class StatsObserverWrapper : public StatsObserver {
707 public:
708 StatsObserverWrapper(JNIEnv* jni, jobject j_observer)
709 : j_observer_global_(NewGlobalRef(jni, j_observer)),
710 j_observer_class_((jclass)NewGlobalRef(
711 jni, GetObjectClass(jni, j_observer))),
712 j_stats_report_class_(FindClass(jni, "org/webrtc/StatsReport")),
713 j_stats_report_ctor_(GetMethodID(
714 jni, j_stats_report_class_, "<init>",
715 "(Ljava/lang/String;Ljava/lang/String;D"
716 "[Lorg/webrtc/StatsReport$Value;)V")),
717 j_value_class_(FindClass(
718 jni, "org/webrtc/StatsReport$Value")),
719 j_value_ctor_(GetMethodID(
720 jni, j_value_class_, "<init>",
721 "(Ljava/lang/String;Ljava/lang/String;)V")) {
722 }
723
724 virtual ~StatsObserverWrapper() {
725 DeleteGlobalRef(jni(), j_observer_global_);
726 DeleteGlobalRef(jni(), j_observer_class_);
727 }
728
729 virtual void OnComplete(const std::vector<StatsReport>& reports) {
730 ScopedLocalRef<jobjectArray> j_reports(jni(),
731 ReportsToJava(jni(), reports));
732 jmethodID m = GetMethodID(
733 jni(), j_observer_class_, "onComplete", "([Lorg/webrtc/StatsReport;)V");
734 jni()->CallVoidMethod(j_observer_global_, m, *j_reports);
735 CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
736 }
737
738 private:
739 jobjectArray ReportsToJava(
740 JNIEnv* jni, const std::vector<StatsReport>& reports) {
741 jobjectArray reports_array = jni->NewObjectArray(
742 reports.size(), j_stats_report_class_, NULL);
743 for (int i = 0; i < reports.size(); ++i) {
744 const StatsReport& report = reports[i];
745 ScopedLocalRef<jstring> j_id(
746 jni, JavaStringFromStdString(jni, report.id));
747 ScopedLocalRef<jstring> j_type(
748 jni, JavaStringFromStdString(jni, report.type));
749 ScopedLocalRef<jobjectArray> j_values(
750 jni, ValuesToJava(jni, report.values));
751 ScopedLocalRef<jobject> j_report(jni, jni->NewObject(
752 j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type,
753 report.timestamp, *j_values));
754 jni->SetObjectArrayElement(reports_array, i, *j_report);
755 }
756 return reports_array;
757 }
758
759 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) {
760 jobjectArray j_values = jni->NewObjectArray(
761 values.size(), j_value_class_, NULL);
762 for (int i = 0; i < values.size(); ++i) {
763 const StatsReport::Value& value = values[i];
764 ScopedLocalRef<jstring> j_name(
765 jni, JavaStringFromStdString(jni, value.name));
766 ScopedLocalRef<jstring> j_value(
767 jni, JavaStringFromStdString(jni, value.value));
768 ScopedLocalRef<jobject> j_element_value(jni, jni->NewObject(
769 j_value_class_, j_value_ctor_, *j_name, *j_value));
770 jni->SetObjectArrayElement(j_values, i, *j_element_value);
771 }
772 return j_values;
773 }
774
775 JNIEnv* jni() {
776 return AttachCurrentThreadIfNeeded();
777 }
778
779 const jobject j_observer_global_;
780 const jclass j_observer_class_;
781 const jclass j_stats_report_class_;
782 const jmethodID j_stats_report_ctor_;
783 const jclass j_value_class_;
784 const jmethodID j_value_ctor_;
785};
786
787// Adapter presenting a cricket::VideoRenderer as a
788// webrtc::VideoRendererInterface.
789class VideoRendererWrapper : public VideoRendererInterface {
790 public:
791 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) {
792 if (renderer)
793 return new VideoRendererWrapper(renderer);
794 return NULL;
795 }
796
797 virtual ~VideoRendererWrapper() {}
798
799 virtual void SetSize(int width, int height) {
800 const bool kNotReserved = false; // What does this param mean??
801 renderer_->SetSize(width, height, kNotReserved);
802 }
803
804 virtual void RenderFrame(const cricket::VideoFrame* frame) {
805 renderer_->RenderFrame(frame);
806 }
807
808 private:
809 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer)
810 : renderer_(renderer) {}
811
812 talk_base::scoped_ptr<cricket::VideoRenderer> renderer_;
813};
814
815// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer
816// instance.
817class JavaVideoRendererWrapper : public VideoRendererInterface {
818 public:
819 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks)
820 : j_callbacks_(jni, j_callbacks) {
821 j_set_size_id_ = GetMethodID(
822 jni, GetObjectClass(jni, j_callbacks), "setSize", "(II)V");
823 j_render_frame_id_ = GetMethodID(
824 jni, GetObjectClass(jni, j_callbacks), "renderFrame",
825 "(Lorg/webrtc/VideoRenderer$I420Frame;)V");
826 j_frame_class_ = FindClass(jni, "org/webrtc/VideoRenderer$I420Frame");
827 j_frame_ctor_id_ = GetMethodID(
828 jni, j_frame_class_, "<init>", "(II[I[Ljava/nio/ByteBuffer;)V");
829 j_byte_buffer_class_ = FindClass(jni, "java/nio/ByteBuffer");
830 CHECK_EXCEPTION(jni, "");
831 }
832
833 virtual void SetSize(int width, int height) {
834 jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
835 CHECK_EXCEPTION(jni(), "");
836 }
837
838 virtual void RenderFrame(const cricket::VideoFrame* frame) {
839 ScopedLocalRef<jobject> j_frame(jni(), CricketToJavaFrame(frame));
840 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, *j_frame);
841 CHECK_EXCEPTION(jni(), "");
842 }
843
844 private:
845 // Return a VideoRenderer.I420Frame referring to the data in |frame|.
846 jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
847 ScopedLocalRef<jintArray> strides(jni(), jni()->NewIntArray(3));
848 jint* strides_array = jni()->GetIntArrayElements(*strides, NULL);
849 strides_array[0] = frame->GetYPitch();
850 strides_array[1] = frame->GetUPitch();
851 strides_array[2] = frame->GetVPitch();
852 jni()->ReleaseIntArrayElements(*strides, strides_array, 0);
853 ScopedLocalRef<jobjectArray> planes(
854 jni(), jni()->NewObjectArray(3, j_byte_buffer_class_, NULL));
855 ScopedLocalRef<jobject> y_buffer(jni(), jni()->NewDirectByteBuffer(
856 const_cast<uint8*>(frame->GetYPlane()),
857 frame->GetYPitch() * frame->GetHeight()));
858 ScopedLocalRef<jobject> u_buffer(jni(), jni()->NewDirectByteBuffer(
859 const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize()));
860 ScopedLocalRef<jobject> v_buffer(jni(), jni()->NewDirectByteBuffer(
861 const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize()));
862 jni()->SetObjectArrayElement(*planes, 0, *y_buffer);
863 jni()->SetObjectArrayElement(*planes, 1, *u_buffer);
864 jni()->SetObjectArrayElement(*planes, 2, *v_buffer);
865 return jni()->NewObject(
866 j_frame_class_, j_frame_ctor_id_,
867 frame->GetWidth(), frame->GetHeight(), *strides, *planes);
868 }
869
870 JNIEnv* jni() {
871 return AttachCurrentThreadIfNeeded();
872 }
873
874 ScopedGlobalRef j_callbacks_;
875 jmethodID j_set_size_id_;
876 jmethodID j_render_frame_id_;
877 jclass j_frame_class_;
878 jmethodID j_frame_ctor_id_;
879 jclass j_byte_buffer_class_;
880};
881
882} // anonymous namespace
883
884
885// Convenience macro defining JNI-accessible methods in the org.webrtc package.
886// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
887#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
888 Java_org_webrtc_##name
889
890extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
891 CHECK(!g_jvm, "JNI_OnLoad called more than once!");
892 g_jvm = jvm;
893 CHECK(g_jvm, "JNI_OnLoad handed NULL?");
894
895 CHECK(talk_base::InitializeSSL(), "Failed to InitializeSSL()");
896
897 JNIEnv* jni;
898 if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
899 return -1;
900 g_class_reference_holder = new ClassReferenceHolder(jni);
901
902#ifdef ANDROID
903 webrtc::Trace::CreateTrace();
904 CHECK(!webrtc::Trace::SetTraceFile("/sdcard/trace.txt", false),
905 "SetTraceFile failed");
906 CHECK(!webrtc::Trace::SetLevelFilter(webrtc::kTraceAll),
907 "SetLevelFilter failed");
908#endif // ANDROID
909
910 // Uncomment to get sensitive logs emitted (to stderr or logcat).
911 // talk_base::LogMessage::LogToDebug(talk_base::LS_SENSITIVE);
912
913 return JNI_VERSION_1_6;
914}
915
916extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
917 webrtc::Trace::ReturnTrace();
918 delete g_class_reference_holder;
919 g_class_reference_holder = NULL;
920 CHECK(talk_base::CleanupSSL(), "Failed to CleanupSSL()");
921}
922
923JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) {
924 reinterpret_cast<PeerConnectionInterface*>(j_p)->Release();
925}
926
927JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) {
928 PCOJava* p = reinterpret_cast<PCOJava*>(j_p);
929 delete p;
930}
931
932JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) {
933 reinterpret_cast<MediaSourceInterface*>(j_p)->Release();
934}
935
936JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
937 delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
938}
939
940JOW(void, VideoRenderer_free)(JNIEnv*, jclass, jlong j_p) {
941 delete reinterpret_cast<VideoRendererWrapper*>(j_p);
942}
943
944JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) {
945 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->Release();
946}
947
948JOW(jboolean, MediaStream_nativeAddAudioTrack)(
949 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
950 talk_base::scoped_refptr<MediaStreamInterface> stream(
951 reinterpret_cast<MediaStreamInterface*>(pointer));
952 talk_base::scoped_refptr<AudioTrackInterface> track(
953 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
954 return stream->AddTrack(track);
955}
956
957JOW(jboolean, MediaStream_nativeAddVideoTrack)(
958 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
959 talk_base::scoped_refptr<MediaStreamInterface> stream(
960 reinterpret_cast<MediaStreamInterface*>(pointer));
961 talk_base::scoped_refptr<VideoTrackInterface> track(
962 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
963 return stream->AddTrack(track);
964}
965
966JOW(jboolean, MediaStream_nativeRemoveAudioTrack)(
967 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) {
968 talk_base::scoped_refptr<MediaStreamInterface> stream(
969 reinterpret_cast<MediaStreamInterface*>(pointer));
970 talk_base::scoped_refptr<AudioTrackInterface> track(
971 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer));
972 return stream->RemoveTrack(track);
973}
974
975JOW(jboolean, MediaStream_nativeRemoveVideoTrack)(
976 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) {
977 talk_base::scoped_refptr<MediaStreamInterface> stream(
978 reinterpret_cast<MediaStreamInterface*>(pointer));
979 talk_base::scoped_refptr<VideoTrackInterface> track(
980 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
981 return stream->RemoveTrack(track);
982}
983
984JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) {
985 return JavaStringFromStdString(
986 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label());
987}
988
989JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) {
990 reinterpret_cast<MediaStreamInterface*>(j_p)->Release();
991}
992
993JOW(jlong, PeerConnectionFactory_nativeCreateObserver)(
994 JNIEnv * jni, jclass, jobject j_observer) {
995 return (jlong)new PCOJava(jni, j_observer);
996}
997
998#ifdef ANDROID
999JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
1000 JNIEnv* jni, jclass, jobject context) {
1001 CHECK(g_jvm, "JNI_OnLoad failed to run?");
1002 bool failure = false;
1003 failure |= webrtc::VideoEngine::SetAndroidObjects(g_jvm, context);
1004 failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
1005 return !failure;
1006}
1007#endif // ANDROID
1008
1009JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)(
1010 JNIEnv* jni, jclass) {
1011 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1012 webrtc::CreatePeerConnectionFactory());
1013 return (jlong)factory.release();
1014}
1015
1016JOW(void, PeerConnectionFactory_freeFactory)(JNIEnv*, jclass, jlong j_p) {
1017 reinterpret_cast<PeerConnectionFactoryInterface*>(j_p)->Release();
1018}
1019
1020JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)(
1021 JNIEnv* jni, jclass, jlong native_factory, jstring label) {
1022 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1023 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1024 talk_base::scoped_refptr<MediaStreamInterface> stream(
1025 factory->CreateLocalMediaStream(JavaToStdString(jni, label)));
1026 return (jlong)stream.release();
1027}
1028
1029JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
1030 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
1031 jobject j_constraints) {
1032 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1033 new ConstraintsWrapper(jni, j_constraints));
1034 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1035 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1036 talk_base::scoped_refptr<VideoSourceInterface> source(
1037 factory->CreateVideoSource(
1038 reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
1039 constraints.get()));
1040 return (jlong)source.release();
1041}
1042
1043JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)(
1044 JNIEnv* jni, jclass, jlong native_factory, jstring id,
1045 jlong native_source) {
1046 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1047 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1048 talk_base::scoped_refptr<VideoTrackInterface> track(
1049 factory->CreateVideoTrack(
1050 JavaToStdString(jni, id),
1051 reinterpret_cast<VideoSourceInterface*>(native_source)));
1052 return (jlong)track.release();
1053}
1054
1055JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)(
1056 JNIEnv* jni, jclass, jlong native_factory, jstring id) {
1057 talk_base::scoped_refptr<PeerConnectionFactoryInterface> factory(
1058 reinterpret_cast<PeerConnectionFactoryInterface*>(native_factory));
1059 talk_base::scoped_refptr<AudioTrackInterface> track(
1060 factory->CreateAudioTrack(JavaToStdString(jni, id), NULL));
1061 return (jlong)track.release();
1062}
1063
1064static void JavaIceServersToJsepIceServers(
1065 JNIEnv* jni, jobject j_ice_servers,
1066 PeerConnectionInterface::IceServers* ice_servers) {
1067 jclass list_class = GetObjectClass(jni, j_ice_servers);
1068 jmethodID iterator_id = GetMethodID(
1069 jni, list_class, "iterator", "()Ljava/util/Iterator;");
1070 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id);
1071 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1072 jmethodID iterator_has_next = GetMethodID(
1073 jni, GetObjectClass(jni, iterator), "hasNext", "()Z");
1074 jmethodID iterator_next = GetMethodID(
1075 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;");
1076 while (jni->CallBooleanMethod(iterator, iterator_has_next)) {
1077 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1078 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next);
1079 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1080 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server);
1081 jfieldID j_ice_server_uri_id =
1082 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;");
1083 jfieldID j_ice_server_username_id =
1084 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;");
1085 jfieldID j_ice_server_password_id =
1086 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;");
1087 jstring uri = reinterpret_cast<jstring>(
1088 GetObjectField(jni, j_ice_server, j_ice_server_uri_id));
1089 jstring username = reinterpret_cast<jstring>(
1090 GetObjectField(jni, j_ice_server, j_ice_server_username_id));
1091 jstring password = reinterpret_cast<jstring>(
1092 GetObjectField(jni, j_ice_server, j_ice_server_password_id));
1093 PeerConnectionInterface::IceServer server;
1094 server.uri = JavaToStdString(jni, uri);
1095 server.username = JavaToStdString(jni, username);
1096 server.password = JavaToStdString(jni, password);
1097 ice_servers->push_back(server);
1098 }
1099 CHECK_EXCEPTION(jni, "error during CallBooleanMethod");
1100}
1101
1102JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)(
1103 JNIEnv *jni, jclass, jlong factory, jobject j_ice_servers,
1104 jobject j_constraints, jlong observer_p) {
1105 talk_base::scoped_refptr<PeerConnectionFactoryInterface> f(
1106 reinterpret_cast<PeerConnectionFactoryInterface*>(factory));
1107 PeerConnectionInterface::IceServers servers;
1108 JavaIceServersToJsepIceServers(jni, j_ice_servers, &servers);
1109 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p);
1110 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints));
1111 talk_base::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection(
1112 servers, observer->constraints(), NULL, observer));
1113 return (jlong)pc.release();
1114}
1115
1116static talk_base::scoped_refptr<PeerConnectionInterface> ExtractNativePC(
1117 JNIEnv* jni, jobject j_pc) {
1118 jfieldID native_pc_id = GetFieldID(jni,
1119 GetObjectClass(jni, j_pc), "nativePeerConnection", "J");
1120 jlong j_p = GetLongField(jni, j_pc, native_pc_id);
1121 return talk_base::scoped_refptr<PeerConnectionInterface>(
1122 reinterpret_cast<PeerConnectionInterface*>(j_p));
1123}
1124
1125JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) {
1126 const SessionDescriptionInterface* sdp =
1127 ExtractNativePC(jni, j_pc)->local_description();
1128 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1129}
1130
1131JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) {
1132 const SessionDescriptionInterface* sdp =
1133 ExtractNativePC(jni, j_pc)->remote_description();
1134 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL;
1135}
1136
1137JOW(void, PeerConnection_createOffer)(
1138 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1139 ConstraintsWrapper* constraints =
1140 new ConstraintsWrapper(jni, j_constraints);
1141 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1142 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1143 jni, j_observer, constraints));
1144 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints);
1145}
1146
1147JOW(void, PeerConnection_createAnswer)(
1148 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) {
1149 ConstraintsWrapper* constraints =
1150 new ConstraintsWrapper(jni, j_constraints);
1151 talk_base::scoped_refptr<CreateSdpObserverWrapper> observer(
1152 new talk_base::RefCountedObject<CreateSdpObserverWrapper>(
1153 jni, j_observer, constraints));
1154 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints);
1155}
1156
1157// Helper to create a SessionDescriptionInterface from a SessionDescription.
1158static SessionDescriptionInterface* JavaSdpToNativeSdp(
1159 JNIEnv* jni, jobject j_sdp) {
1160 jfieldID j_type_id = GetFieldID(
1161 jni, GetObjectClass(jni, j_sdp), "type",
1162 "Lorg/webrtc/SessionDescription$Type;");
1163 jobject j_type = GetObjectField(jni, j_sdp, j_type_id);
1164 jmethodID j_canonical_form_id = GetMethodID(
1165 jni, GetObjectClass(jni, j_type), "canonicalForm",
1166 "()Ljava/lang/String;");
1167 jstring j_type_string = (jstring)jni->CallObjectMethod(
1168 j_type, j_canonical_form_id);
1169 CHECK_EXCEPTION(jni, "error during CallObjectMethod");
1170 std::string std_type = JavaToStdString(jni, j_type_string);
1171
1172 jfieldID j_description_id = GetFieldID(
1173 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;");
1174 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id);
1175 std::string std_description = JavaToStdString(jni, j_description);
1176
1177 return webrtc::CreateSessionDescription(
1178 std_type, std_description, NULL);
1179}
1180
1181JOW(void, PeerConnection_setLocalDescription)(
1182 JNIEnv* jni, jobject j_pc,
1183 jobject j_observer, jobject j_sdp) {
1184 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1185 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1186 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1187 ExtractNativePC(jni, j_pc)->SetLocalDescription(
1188 observer, JavaSdpToNativeSdp(jni, j_sdp));
1189}
1190
1191JOW(void, PeerConnection_setRemoteDescription)(
1192 JNIEnv* jni, jobject j_pc,
1193 jobject j_observer, jobject j_sdp) {
1194 talk_base::scoped_refptr<SetSdpObserverWrapper> observer(
1195 new talk_base::RefCountedObject<SetSdpObserverWrapper>(
1196 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL)));
1197 ExtractNativePC(jni, j_pc)->SetRemoteDescription(
1198 observer, JavaSdpToNativeSdp(jni, j_sdp));
1199}
1200
1201JOW(jboolean, PeerConnection_updateIce)(
1202 JNIEnv* jni, jobject j_pc, jobject j_ice_servers, jobject j_constraints) {
1203 PeerConnectionInterface::IceServers ice_servers;
1204 JavaIceServersToJsepIceServers(jni, j_ice_servers, &ice_servers);
1205 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1206 new ConstraintsWrapper(jni, j_constraints));
1207 return ExtractNativePC(jni, j_pc)->UpdateIce(ice_servers, constraints.get());
1208}
1209
1210JOW(jboolean, PeerConnection_nativeAddIceCandidate)(
1211 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid,
1212 jint j_sdp_mline_index, jstring j_candidate_sdp) {
1213 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid);
1214 std::string sdp = JavaToStdString(jni, j_candidate_sdp);
1215 talk_base::scoped_ptr<IceCandidateInterface> candidate(
1216 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL));
1217 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get());
1218}
1219
1220JOW(jboolean, PeerConnection_nativeAddLocalStream)(
1221 JNIEnv* jni, jobject j_pc, jlong native_stream, jobject j_constraints) {
1222 talk_base::scoped_ptr<ConstraintsWrapper> constraints(
1223 new ConstraintsWrapper(jni, j_constraints));
1224 return ExtractNativePC(jni, j_pc)->AddStream(
1225 reinterpret_cast<MediaStreamInterface*>(native_stream),
1226 constraints.get());
1227}
1228
1229JOW(void, PeerConnection_nativeRemoveLocalStream)(
1230 JNIEnv* jni, jobject j_pc, jlong native_stream) {
1231 ExtractNativePC(jni, j_pc)->RemoveStream(
1232 reinterpret_cast<MediaStreamInterface*>(native_stream));
1233}
1234
1235JOW(bool, PeerConnection_nativeGetStats)(
1236 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
1237 talk_base::scoped_refptr<StatsObserverWrapper> observer(
1238 new talk_base::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
1239 return ExtractNativePC(jni, j_pc)->GetStats(
1240 observer, reinterpret_cast<MediaStreamTrackInterface*>(native_track));
1241}
1242
1243JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) {
1244 PeerConnectionInterface::SignalingState state =
1245 ExtractNativePC(jni, j_pc)->signaling_state();
1246 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state);
1247}
1248
1249JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) {
1250 PeerConnectionInterface::IceConnectionState state =
1251 ExtractNativePC(jni, j_pc)->ice_connection_state();
1252 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state);
1253}
1254
1255JOW(jobject, PeerGathering_iceGatheringState)(JNIEnv* jni, jobject j_pc) {
1256 PeerConnectionInterface::IceGatheringState state =
1257 ExtractNativePC(jni, j_pc)->ice_gathering_state();
1258 return JavaEnumFromIndex(jni, "PeerGathering$IceGatheringState", state);
1259}
1260
1261JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) {
1262 ExtractNativePC(jni, j_pc)->Close();
1263 return;
1264}
1265
1266JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1267 talk_base::scoped_refptr<MediaSourceInterface> p(
1268 reinterpret_cast<MediaSourceInterface*>(j_p));
1269 return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
1270}
1271
1272JOW(jlong, VideoCapturer_nativeCreateVideoCapturer)(
1273 JNIEnv* jni, jclass, jstring j_device_name) {
1274 std::string device_name = JavaToStdString(jni, j_device_name);
1275 talk_base::scoped_ptr<cricket::DeviceManagerInterface> device_manager(
1276 cricket::DeviceManagerFactory::Create());
1277 CHECK(device_manager->Init(), "DeviceManager::Init() failed");
1278 cricket::Device device;
1279 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
1280 LOG(LS_ERROR) << "GetVideoCaptureDevice failed";
1281 return 0;
1282 }
1283 talk_base::scoped_ptr<cricket::VideoCapturer> capturer(
1284 device_manager->CreateVideoCapturer(device));
1285 return (jlong)capturer.release();
1286}
1287
1288JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
1289 JNIEnv* jni, jclass, int x, int y) {
1290 talk_base::scoped_ptr<VideoRendererWrapper> renderer(
1291 VideoRendererWrapper::Create(
1292 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
1293 return (jlong)renderer.release();
1294}
1295
1296JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
1297 JNIEnv* jni, jclass, jobject j_callbacks) {
1298 talk_base::scoped_ptr<JavaVideoRendererWrapper> renderer(
1299 new JavaVideoRendererWrapper(jni, j_callbacks));
1300 return (jlong)renderer.release();
1301}
1302
1303JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) {
1304 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1305 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1306 return JavaStringFromStdString(jni, p->id());
1307}
1308
1309JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) {
1310 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1311 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1312 return JavaStringFromStdString(jni, p->kind());
1313}
1314
1315JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) {
1316 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1317 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1318 return p->enabled();
1319}
1320
1321JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) {
1322 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1323 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1324 return JavaEnumFromIndex(jni, "MediaStreamTrack$State", p->state());
1325}
1326
1327JOW(jboolean, MediaStreamTrack_nativeSetState)(
1328 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) {
1329 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1330 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1331 MediaStreamTrackInterface::TrackState new_state =
1332 (MediaStreamTrackInterface::TrackState)j_new_state;
1333 return p->set_state(new_state);
1334}
1335
1336JOW(jboolean, MediaStreamTrack_nativeSetEnabled)(
1337 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) {
1338 talk_base::scoped_refptr<MediaStreamTrackInterface> p(
1339 reinterpret_cast<MediaStreamTrackInterface*>(j_p));
1340 return p->set_enabled(enabled);
1341}
1342
1343JOW(void, VideoTrack_nativeAddRenderer)(
1344 JNIEnv* jni, jclass,
1345 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1346 talk_base::scoped_refptr<VideoTrackInterface> track(
1347 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1348 track->AddRenderer(
1349 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1350}
1351
1352JOW(void, VideoTrack_nativeRemoveRenderer)(
1353 JNIEnv* jni, jclass,
1354 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1355 talk_base::scoped_refptr<VideoTrackInterface> track(
1356 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer));
1357 track->RemoveRenderer(
1358 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1359}