1/* 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 <limits> 60#include <utility> 61 62#include "talk/app/webrtc/java/jni/classreferenceholder.h" 63#include "talk/app/webrtc/java/jni/jni_helpers.h" 64#include "talk/app/webrtc/java/jni/native_handle_impl.h" 65#include "talk/app/webrtc/dtlsidentitystore.h" 66#include "talk/app/webrtc/mediaconstraintsinterface.h" 67#include "talk/app/webrtc/peerconnectioninterface.h" 68#include "talk/app/webrtc/rtpreceiverinterface.h" 69#include "talk/app/webrtc/rtpsenderinterface.h" 70#include "talk/app/webrtc/videosourceinterface.h" 71#include "talk/media/base/videocapturer.h" 72#include "talk/media/base/videorenderer.h" 73#include "talk/media/devices/videorendererfactory.h" 74#include "talk/media/webrtc/webrtcvideodecoderfactory.h" 75#include "talk/media/webrtc/webrtcvideoencoderfactory.h" 76#include "webrtc/base/bind.h" 77#include "webrtc/base/checks.h" 78#include "webrtc/base/event_tracer.h" 79#include "webrtc/base/logging.h" 80#include "webrtc/base/logsinks.h" 81#include "webrtc/base/messagequeue.h" 82#include "webrtc/base/networkmonitor.h" 83#include "webrtc/base/ssladapter.h" 84#include "webrtc/base/stringutils.h" 85#include "webrtc/system_wrappers/include/field_trial_default.h" 86#include "webrtc/system_wrappers/include/trace.h" 87#include "webrtc/voice_engine/include/voe_base.h" 88 89#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 90#include "talk/app/webrtc/androidvideocapturer.h" 91#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h" 92#include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h" 93#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h" 94#include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h" 95#include "webrtc/modules/video_render/video_render_internal.h" 96#include "webrtc/system_wrappers/include/logcat_trace_context.h" 97using webrtc::LogcatTraceContext; 98#endif 99 100using cricket::WebRtcVideoDecoderFactory; 101using cricket::WebRtcVideoEncoderFactory; 102using rtc::Bind; 103using rtc::Thread; 104using rtc::ThreadManager; 105using rtc::scoped_ptr; 106using webrtc::AudioSourceInterface; 107using webrtc::AudioTrackInterface; 108using webrtc::AudioTrackVector; 109using webrtc::CreateSessionDescriptionObserver; 110using webrtc::DataBuffer; 111using webrtc::DataChannelInit; 112using webrtc::DataChannelInterface; 113using webrtc::DataChannelObserver; 114using webrtc::IceCandidateInterface; 115using webrtc::MediaConstraintsInterface; 116using webrtc::MediaSourceInterface; 117using webrtc::MediaStreamInterface; 118using webrtc::MediaStreamTrackInterface; 119using webrtc::PeerConnectionFactoryInterface; 120using webrtc::PeerConnectionInterface; 121using webrtc::PeerConnectionObserver; 122using webrtc::RtpReceiverInterface; 123using webrtc::RtpSenderInterface; 124using webrtc::SessionDescriptionInterface; 125using webrtc::SetSessionDescriptionObserver; 126using webrtc::StatsObserver; 127using webrtc::StatsReport; 128using webrtc::StatsReports; 129using webrtc::VideoRendererInterface; 130using webrtc::VideoSourceInterface; 131using webrtc::VideoTrackInterface; 132using webrtc::VideoTrackVector; 133using webrtc::kVideoCodecVP8; 134 135namespace webrtc_jni { 136 137// Field trials initialization string 138static char *field_trials_init_string = NULL; 139 140#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 141// Set in PeerConnectionFactory_initializeAndroidGlobals(). 142static bool factory_static_initialized = false; 143static bool video_hw_acceleration_enabled = true; 144#endif 145 146// Return the (singleton) Java Enum object corresponding to |index|; 147// |state_class_fragment| is something like "MediaSource$State". 148static jobject JavaEnumFromIndex( 149 JNIEnv* jni, const std::string& state_class_fragment, int index) { 150 const std::string state_class = "org/webrtc/" + state_class_fragment; 151 return JavaEnumFromIndex(jni, FindClass(jni, state_class.c_str()), 152 state_class, index); 153} 154 155static DataChannelInit JavaDataChannelInitToNative( 156 JNIEnv* jni, jobject j_init) { 157 DataChannelInit init; 158 159 jclass j_init_class = FindClass(jni, "org/webrtc/DataChannel$Init"); 160 jfieldID ordered_id = GetFieldID(jni, j_init_class, "ordered", "Z"); 161 jfieldID max_retransmit_time_id = 162 GetFieldID(jni, j_init_class, "maxRetransmitTimeMs", "I"); 163 jfieldID max_retransmits_id = 164 GetFieldID(jni, j_init_class, "maxRetransmits", "I"); 165 jfieldID protocol_id = 166 GetFieldID(jni, j_init_class, "protocol", "Ljava/lang/String;"); 167 jfieldID negotiated_id = GetFieldID(jni, j_init_class, "negotiated", "Z"); 168 jfieldID id_id = GetFieldID(jni, j_init_class, "id", "I"); 169 170 init.ordered = GetBooleanField(jni, j_init, ordered_id); 171 init.maxRetransmitTime = GetIntField(jni, j_init, max_retransmit_time_id); 172 init.maxRetransmits = GetIntField(jni, j_init, max_retransmits_id); 173 init.protocol = JavaToStdString( 174 jni, GetStringField(jni, j_init, protocol_id)); 175 init.negotiated = GetBooleanField(jni, j_init, negotiated_id); 176 init.id = GetIntField(jni, j_init, id_id); 177 178 return init; 179} 180 181class ConstraintsWrapper; 182 183// Adapter between the C++ PeerConnectionObserver interface and the Java 184// PeerConnection.Observer interface. Wraps an instance of the Java interface 185// and dispatches C++ callbacks to Java. 186class PCOJava : public PeerConnectionObserver { 187 public: 188 PCOJava(JNIEnv* jni, jobject j_observer) 189 : j_observer_global_(jni, j_observer), 190 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)), 191 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")), 192 j_media_stream_ctor_(GetMethodID( 193 jni, *j_media_stream_class_, "<init>", "(J)V")), 194 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")), 195 j_audio_track_ctor_(GetMethodID( 196 jni, *j_audio_track_class_, "<init>", "(J)V")), 197 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")), 198 j_video_track_ctor_(GetMethodID( 199 jni, *j_video_track_class_, "<init>", "(J)V")), 200 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")), 201 j_data_channel_ctor_(GetMethodID( 202 jni, *j_data_channel_class_, "<init>", "(J)V")) { 203 } 204 205 virtual ~PCOJava() { 206 ScopedLocalRefFrame local_ref_frame(jni()); 207 while (!remote_streams_.empty()) 208 DisposeRemoteStream(remote_streams_.begin()); 209 } 210 211 void OnIceCandidate(const IceCandidateInterface* candidate) override { 212 ScopedLocalRefFrame local_ref_frame(jni()); 213 std::string sdp; 214 RTC_CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp; 215 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate"); 216 jmethodID ctor = GetMethodID(jni(), candidate_class, 217 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V"); 218 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid()); 219 jstring j_sdp = JavaStringFromStdString(jni(), sdp); 220 jobject j_candidate = jni()->NewObject( 221 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp); 222 CHECK_EXCEPTION(jni()) << "error during NewObject"; 223 jmethodID m = GetMethodID(jni(), *j_observer_class_, 224 "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V"); 225 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate); 226 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 227 } 228 229 void OnSignalingChange( 230 PeerConnectionInterface::SignalingState new_state) override { 231 ScopedLocalRefFrame local_ref_frame(jni()); 232 jmethodID m = GetMethodID( 233 jni(), *j_observer_class_, "onSignalingChange", 234 "(Lorg/webrtc/PeerConnection$SignalingState;)V"); 235 jobject new_state_enum = 236 JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state); 237 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); 238 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 239 } 240 241 void OnIceConnectionChange( 242 PeerConnectionInterface::IceConnectionState new_state) override { 243 ScopedLocalRefFrame local_ref_frame(jni()); 244 jmethodID m = GetMethodID( 245 jni(), *j_observer_class_, "onIceConnectionChange", 246 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V"); 247 jobject new_state_enum = JavaEnumFromIndex( 248 jni(), "PeerConnection$IceConnectionState", new_state); 249 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); 250 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 251 } 252 253 void OnIceConnectionReceivingChange(bool receiving) override { 254 ScopedLocalRefFrame local_ref_frame(jni()); 255 jmethodID m = GetMethodID( 256 jni(), *j_observer_class_, "onIceConnectionReceivingChange", "(Z)V"); 257 jni()->CallVoidMethod(*j_observer_global_, m, receiving); 258 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 259 } 260 261 void OnIceGatheringChange( 262 PeerConnectionInterface::IceGatheringState new_state) override { 263 ScopedLocalRefFrame local_ref_frame(jni()); 264 jmethodID m = GetMethodID( 265 jni(), *j_observer_class_, "onIceGatheringChange", 266 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V"); 267 jobject new_state_enum = JavaEnumFromIndex( 268 jni(), "PeerConnection$IceGatheringState", new_state); 269 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); 270 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 271 } 272 273 void OnAddStream(MediaStreamInterface* stream) override { 274 ScopedLocalRefFrame local_ref_frame(jni()); 275 // Java MediaStream holds one reference. Corresponding Release() is in 276 // MediaStream_free, triggered by MediaStream.dispose(). 277 stream->AddRef(); 278 jobject j_stream = 279 jni()->NewObject(*j_media_stream_class_, j_media_stream_ctor_, 280 reinterpret_cast<jlong>(stream)); 281 CHECK_EXCEPTION(jni()) << "error during NewObject"; 282 283 for (const auto& track : stream->GetAudioTracks()) { 284 jstring id = JavaStringFromStdString(jni(), track->id()); 285 // Java AudioTrack holds one reference. Corresponding Release() is in 286 // MediaStreamTrack_free, triggered by AudioTrack.dispose(). 287 track->AddRef(); 288 jobject j_track = 289 jni()->NewObject(*j_audio_track_class_, j_audio_track_ctor_, 290 reinterpret_cast<jlong>(track.get()), id); 291 CHECK_EXCEPTION(jni()) << "error during NewObject"; 292 jfieldID audio_tracks_id = GetFieldID(jni(), 293 *j_media_stream_class_, 294 "audioTracks", 295 "Ljava/util/LinkedList;"); 296 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id); 297 jmethodID add = GetMethodID(jni(), 298 GetObjectClass(jni(), audio_tracks), 299 "add", 300 "(Ljava/lang/Object;)Z"); 301 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track); 302 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; 303 RTC_CHECK(added); 304 } 305 306 for (const auto& track : stream->GetVideoTracks()) { 307 jstring id = JavaStringFromStdString(jni(), track->id()); 308 // Java VideoTrack holds one reference. Corresponding Release() is in 309 // MediaStreamTrack_free, triggered by VideoTrack.dispose(). 310 track->AddRef(); 311 jobject j_track = 312 jni()->NewObject(*j_video_track_class_, j_video_track_ctor_, 313 reinterpret_cast<jlong>(track.get()), id); 314 CHECK_EXCEPTION(jni()) << "error during NewObject"; 315 jfieldID video_tracks_id = GetFieldID(jni(), 316 *j_media_stream_class_, 317 "videoTracks", 318 "Ljava/util/LinkedList;"); 319 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id); 320 jmethodID add = GetMethodID(jni(), 321 GetObjectClass(jni(), video_tracks), 322 "add", 323 "(Ljava/lang/Object;)Z"); 324 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track); 325 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; 326 RTC_CHECK(added); 327 } 328 remote_streams_[stream] = NewGlobalRef(jni(), j_stream); 329 330 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream", 331 "(Lorg/webrtc/MediaStream;)V"); 332 jni()->CallVoidMethod(*j_observer_global_, m, j_stream); 333 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 334 } 335 336 void OnRemoveStream(MediaStreamInterface* stream) override { 337 ScopedLocalRefFrame local_ref_frame(jni()); 338 NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream); 339 RTC_CHECK(it != remote_streams_.end()) << "unexpected stream: " << std::hex 340 << stream; 341 jobject j_stream = it->second; 342 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream", 343 "(Lorg/webrtc/MediaStream;)V"); 344 jni()->CallVoidMethod(*j_observer_global_, m, j_stream); 345 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 346 DisposeRemoteStream(it); 347 } 348 349 void OnDataChannel(DataChannelInterface* channel) override { 350 ScopedLocalRefFrame local_ref_frame(jni()); 351 jobject j_channel = jni()->NewObject( 352 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel); 353 CHECK_EXCEPTION(jni()) << "error during NewObject"; 354 355 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel", 356 "(Lorg/webrtc/DataChannel;)V"); 357 jni()->CallVoidMethod(*j_observer_global_, m, j_channel); 358 359 // Channel is now owned by Java object, and will be freed from 360 // DataChannel.dispose(). Important that this be done _after_ the 361 // CallVoidMethod above as Java code might call back into native code and be 362 // surprised to see a refcount of 2. 363 int bumped_count = channel->AddRef(); 364 RTC_CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel"; 365 366 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 367 } 368 369 void OnRenegotiationNeeded() override { 370 ScopedLocalRefFrame local_ref_frame(jni()); 371 jmethodID m = 372 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V"); 373 jni()->CallVoidMethod(*j_observer_global_, m); 374 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 375 } 376 377 void SetConstraints(ConstraintsWrapper* constraints) { 378 RTC_CHECK(!constraints_.get()) << "constraints already set!"; 379 constraints_.reset(constraints); 380 } 381 382 const ConstraintsWrapper* constraints() { return constraints_.get(); } 383 384 private: 385 typedef std::map<MediaStreamInterface*, jobject> NativeToJavaStreamsMap; 386 387 void DisposeRemoteStream(const NativeToJavaStreamsMap::iterator& it) { 388 jobject j_stream = it->second; 389 remote_streams_.erase(it); 390 jni()->CallVoidMethod( 391 j_stream, GetMethodID(jni(), *j_media_stream_class_, "dispose", "()V")); 392 CHECK_EXCEPTION(jni()) << "error during MediaStream.dispose()"; 393 DeleteGlobalRef(jni(), j_stream); 394 } 395 396 JNIEnv* jni() { 397 return AttachCurrentThreadIfNeeded(); 398 } 399 400 const ScopedGlobalRef<jobject> j_observer_global_; 401 const ScopedGlobalRef<jclass> j_observer_class_; 402 const ScopedGlobalRef<jclass> j_media_stream_class_; 403 const jmethodID j_media_stream_ctor_; 404 const ScopedGlobalRef<jclass> j_audio_track_class_; 405 const jmethodID j_audio_track_ctor_; 406 const ScopedGlobalRef<jclass> j_video_track_class_; 407 const jmethodID j_video_track_ctor_; 408 const ScopedGlobalRef<jclass> j_data_channel_class_; 409 const jmethodID j_data_channel_ctor_; 410 // C++ -> Java remote streams. The stored jobects are global refs and must be 411 // manually deleted upon removal. Use DisposeRemoteStream(). 412 NativeToJavaStreamsMap remote_streams_; 413 scoped_ptr<ConstraintsWrapper> constraints_; 414}; 415 416// Wrapper for a Java MediaConstraints object. Copies all needed data so when 417// the constructor returns the Java object is no longer needed. 418class ConstraintsWrapper : public MediaConstraintsInterface { 419 public: 420 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) { 421 PopulateConstraintsFromJavaPairList( 422 jni, j_constraints, "mandatory", &mandatory_); 423 PopulateConstraintsFromJavaPairList( 424 jni, j_constraints, "optional", &optional_); 425 } 426 427 virtual ~ConstraintsWrapper() {} 428 429 // MediaConstraintsInterface. 430 const Constraints& GetMandatory() const override { return mandatory_; } 431 432 const Constraints& GetOptional() const override { return optional_; } 433 434 private: 435 // Helper for translating a List<Pair<String, String>> to a Constraints. 436 static void PopulateConstraintsFromJavaPairList( 437 JNIEnv* jni, jobject j_constraints, 438 const char* field_name, Constraints* field) { 439 jfieldID j_id = GetFieldID(jni, 440 GetObjectClass(jni, j_constraints), field_name, "Ljava/util/List;"); 441 jobject j_list = GetObjectField(jni, j_constraints, j_id); 442 jmethodID j_iterator_id = GetMethodID(jni, 443 GetObjectClass(jni, j_list), "iterator", "()Ljava/util/Iterator;"); 444 jobject j_iterator = jni->CallObjectMethod(j_list, j_iterator_id); 445 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 446 jmethodID j_has_next = GetMethodID(jni, 447 GetObjectClass(jni, j_iterator), "hasNext", "()Z"); 448 jmethodID j_next = GetMethodID(jni, 449 GetObjectClass(jni, j_iterator), "next", "()Ljava/lang/Object;"); 450 while (jni->CallBooleanMethod(j_iterator, j_has_next)) { 451 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; 452 jobject entry = jni->CallObjectMethod(j_iterator, j_next); 453 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 454 jmethodID get_key = GetMethodID(jni, 455 GetObjectClass(jni, entry), "getKey", "()Ljava/lang/String;"); 456 jstring j_key = reinterpret_cast<jstring>( 457 jni->CallObjectMethod(entry, get_key)); 458 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 459 jmethodID get_value = GetMethodID(jni, 460 GetObjectClass(jni, entry), "getValue", "()Ljava/lang/String;"); 461 jstring j_value = reinterpret_cast<jstring>( 462 jni->CallObjectMethod(entry, get_value)); 463 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 464 field->push_back(Constraint(JavaToStdString(jni, j_key), 465 JavaToStdString(jni, j_value))); 466 } 467 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; 468 } 469 470 Constraints mandatory_; 471 Constraints optional_; 472}; 473 474static jobject JavaSdpFromNativeSdp( 475 JNIEnv* jni, const SessionDescriptionInterface* desc) { 476 std::string sdp; 477 RTC_CHECK(desc->ToString(&sdp)) << "got so far: " << sdp; 478 jstring j_description = JavaStringFromStdString(jni, sdp); 479 480 jclass j_type_class = FindClass( 481 jni, "org/webrtc/SessionDescription$Type"); 482 jmethodID j_type_from_canonical = GetStaticMethodID( 483 jni, j_type_class, "fromCanonicalForm", 484 "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;"); 485 jstring j_type_string = JavaStringFromStdString(jni, desc->type()); 486 jobject j_type = jni->CallStaticObjectMethod( 487 j_type_class, j_type_from_canonical, j_type_string); 488 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 489 490 jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription"); 491 jmethodID j_sdp_ctor = GetMethodID( 492 jni, j_sdp_class, "<init>", 493 "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V"); 494 jobject j_sdp = jni->NewObject( 495 j_sdp_class, j_sdp_ctor, j_type, j_description); 496 CHECK_EXCEPTION(jni) << "error during NewObject"; 497 return j_sdp; 498} 499 500template <class T> // T is one of {Create,Set}SessionDescriptionObserver. 501class SdpObserverWrapper : public T { 502 public: 503 SdpObserverWrapper(JNIEnv* jni, jobject j_observer, 504 ConstraintsWrapper* constraints) 505 : constraints_(constraints), 506 j_observer_global_(jni, j_observer), 507 j_observer_class_(jni, GetObjectClass(jni, j_observer)) { 508 } 509 510 virtual ~SdpObserverWrapper() {} 511 512 // Can't mark override because of templating. 513 virtual void OnSuccess() { 514 ScopedLocalRefFrame local_ref_frame(jni()); 515 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V"); 516 jni()->CallVoidMethod(*j_observer_global_, m); 517 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 518 } 519 520 // Can't mark override because of templating. 521 virtual void OnSuccess(SessionDescriptionInterface* desc) { 522 ScopedLocalRefFrame local_ref_frame(jni()); 523 jmethodID m = GetMethodID( 524 jni(), *j_observer_class_, "onCreateSuccess", 525 "(Lorg/webrtc/SessionDescription;)V"); 526 jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc); 527 jni()->CallVoidMethod(*j_observer_global_, m, j_sdp); 528 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 529 } 530 531 protected: 532 // Common implementation for failure of Set & Create types, distinguished by 533 // |op| being "Set" or "Create". 534 void DoOnFailure(const std::string& op, const std::string& error) { 535 jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure", 536 "(Ljava/lang/String;)V"); 537 jstring j_error_string = JavaStringFromStdString(jni(), error); 538 jni()->CallVoidMethod(*j_observer_global_, m, j_error_string); 539 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 540 } 541 542 JNIEnv* jni() { 543 return AttachCurrentThreadIfNeeded(); 544 } 545 546 private: 547 scoped_ptr<ConstraintsWrapper> constraints_; 548 const ScopedGlobalRef<jobject> j_observer_global_; 549 const ScopedGlobalRef<jclass> j_observer_class_; 550}; 551 552class CreateSdpObserverWrapper 553 : public SdpObserverWrapper<CreateSessionDescriptionObserver> { 554 public: 555 CreateSdpObserverWrapper(JNIEnv* jni, jobject j_observer, 556 ConstraintsWrapper* constraints) 557 : SdpObserverWrapper(jni, j_observer, constraints) {} 558 559 void OnFailure(const std::string& error) override { 560 ScopedLocalRefFrame local_ref_frame(jni()); 561 SdpObserverWrapper::DoOnFailure(std::string("Create"), error); 562 } 563}; 564 565class SetSdpObserverWrapper 566 : public SdpObserverWrapper<SetSessionDescriptionObserver> { 567 public: 568 SetSdpObserverWrapper(JNIEnv* jni, jobject j_observer, 569 ConstraintsWrapper* constraints) 570 : SdpObserverWrapper(jni, j_observer, constraints) {} 571 572 void OnFailure(const std::string& error) override { 573 ScopedLocalRefFrame local_ref_frame(jni()); 574 SdpObserverWrapper::DoOnFailure(std::string("Set"), error); 575 } 576}; 577 578// Adapter for a Java DataChannel$Observer presenting a C++ DataChannelObserver 579// and dispatching the callback from C++ back to Java. 580class DataChannelObserverWrapper : public DataChannelObserver { 581 public: 582 DataChannelObserverWrapper(JNIEnv* jni, jobject j_observer) 583 : j_observer_global_(jni, j_observer), 584 j_observer_class_(jni, GetObjectClass(jni, j_observer)), 585 j_buffer_class_(jni, FindClass(jni, "org/webrtc/DataChannel$Buffer")), 586 j_on_buffered_amount_change_mid_(GetMethodID( 587 jni, *j_observer_class_, "onBufferedAmountChange", "(J)V")), 588 j_on_state_change_mid_( 589 GetMethodID(jni, *j_observer_class_, "onStateChange", "()V")), 590 j_on_message_mid_(GetMethodID(jni, *j_observer_class_, "onMessage", 591 "(Lorg/webrtc/DataChannel$Buffer;)V")), 592 j_buffer_ctor_(GetMethodID(jni, *j_buffer_class_, "<init>", 593 "(Ljava/nio/ByteBuffer;Z)V")) {} 594 595 virtual ~DataChannelObserverWrapper() {} 596 597 void OnBufferedAmountChange(uint64_t previous_amount) override { 598 ScopedLocalRefFrame local_ref_frame(jni()); 599 jni()->CallVoidMethod(*j_observer_global_, j_on_buffered_amount_change_mid_, 600 previous_amount); 601 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 602 } 603 604 void OnStateChange() override { 605 ScopedLocalRefFrame local_ref_frame(jni()); 606 jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_); 607 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 608 } 609 610 void OnMessage(const DataBuffer& buffer) override { 611 ScopedLocalRefFrame local_ref_frame(jni()); 612 jobject byte_buffer = jni()->NewDirectByteBuffer( 613 const_cast<char*>(buffer.data.data<char>()), buffer.data.size()); 614 jobject j_buffer = jni()->NewObject(*j_buffer_class_, j_buffer_ctor_, 615 byte_buffer, buffer.binary); 616 jni()->CallVoidMethod(*j_observer_global_, j_on_message_mid_, j_buffer); 617 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 618 } 619 620 private: 621 JNIEnv* jni() { 622 return AttachCurrentThreadIfNeeded(); 623 } 624 625 const ScopedGlobalRef<jobject> j_observer_global_; 626 const ScopedGlobalRef<jclass> j_observer_class_; 627 const ScopedGlobalRef<jclass> j_buffer_class_; 628 const jmethodID j_on_buffered_amount_change_mid_; 629 const jmethodID j_on_state_change_mid_; 630 const jmethodID j_on_message_mid_; 631 const jmethodID j_buffer_ctor_; 632}; 633 634// Adapter for a Java StatsObserver presenting a C++ StatsObserver and 635// dispatching the callback from C++ back to Java. 636class StatsObserverWrapper : public StatsObserver { 637 public: 638 StatsObserverWrapper(JNIEnv* jni, jobject j_observer) 639 : j_observer_global_(jni, j_observer), 640 j_observer_class_(jni, GetObjectClass(jni, j_observer)), 641 j_stats_report_class_(jni, FindClass(jni, "org/webrtc/StatsReport")), 642 j_stats_report_ctor_(GetMethodID( 643 jni, *j_stats_report_class_, "<init>", 644 "(Ljava/lang/String;Ljava/lang/String;D" 645 "[Lorg/webrtc/StatsReport$Value;)V")), 646 j_value_class_(jni, FindClass( 647 jni, "org/webrtc/StatsReport$Value")), 648 j_value_ctor_(GetMethodID( 649 jni, *j_value_class_, "<init>", 650 "(Ljava/lang/String;Ljava/lang/String;)V")) { 651 } 652 653 virtual ~StatsObserverWrapper() {} 654 655 void OnComplete(const StatsReports& reports) override { 656 ScopedLocalRefFrame local_ref_frame(jni()); 657 jobjectArray j_reports = ReportsToJava(jni(), reports); 658 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete", 659 "([Lorg/webrtc/StatsReport;)V"); 660 jni()->CallVoidMethod(*j_observer_global_, m, j_reports); 661 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 662 } 663 664 private: 665 jobjectArray ReportsToJava( 666 JNIEnv* jni, const StatsReports& reports) { 667 jobjectArray reports_array = jni->NewObjectArray( 668 reports.size(), *j_stats_report_class_, NULL); 669 int i = 0; 670 for (const auto* report : reports) { 671 ScopedLocalRefFrame local_ref_frame(jni); 672 jstring j_id = JavaStringFromStdString(jni, report->id()->ToString()); 673 jstring j_type = JavaStringFromStdString(jni, report->TypeToString()); 674 jobjectArray j_values = ValuesToJava(jni, report->values()); 675 jobject j_report = jni->NewObject(*j_stats_report_class_, 676 j_stats_report_ctor_, 677 j_id, 678 j_type, 679 report->timestamp(), 680 j_values); 681 jni->SetObjectArrayElement(reports_array, i++, j_report); 682 } 683 return reports_array; 684 } 685 686 jobjectArray ValuesToJava(JNIEnv* jni, const StatsReport::Values& values) { 687 jobjectArray j_values = jni->NewObjectArray( 688 values.size(), *j_value_class_, NULL); 689 int i = 0; 690 for (const auto& it : values) { 691 ScopedLocalRefFrame local_ref_frame(jni); 692 // Should we use the '.name' enum value here instead of converting the 693 // name to a string? 694 jstring j_name = JavaStringFromStdString(jni, it.second->display_name()); 695 jstring j_value = JavaStringFromStdString(jni, it.second->ToString()); 696 jobject j_element_value = 697 jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value); 698 jni->SetObjectArrayElement(j_values, i++, j_element_value); 699 } 700 return j_values; 701 } 702 703 JNIEnv* jni() { 704 return AttachCurrentThreadIfNeeded(); 705 } 706 707 const ScopedGlobalRef<jobject> j_observer_global_; 708 const ScopedGlobalRef<jclass> j_observer_class_; 709 const ScopedGlobalRef<jclass> j_stats_report_class_; 710 const jmethodID j_stats_report_ctor_; 711 const ScopedGlobalRef<jclass> j_value_class_; 712 const jmethodID j_value_ctor_; 713}; 714 715// Adapter presenting a cricket::VideoRenderer as a 716// webrtc::VideoRendererInterface. 717class VideoRendererWrapper : public VideoRendererInterface { 718 public: 719 static VideoRendererWrapper* Create(cricket::VideoRenderer* renderer) { 720 if (renderer) 721 return new VideoRendererWrapper(renderer); 722 return NULL; 723 } 724 725 virtual ~VideoRendererWrapper() {} 726 727 // This wraps VideoRenderer which still has SetSize. 728 void RenderFrame(const cricket::VideoFrame* video_frame) override { 729 ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded()); 730 const cricket::VideoFrame* frame = 731 video_frame->GetCopyWithRotationApplied(); 732 if (width_ != frame->GetWidth() || height_ != frame->GetHeight()) { 733 width_ = frame->GetWidth(); 734 height_ = frame->GetHeight(); 735 renderer_->SetSize(width_, height_, 0); 736 } 737 renderer_->RenderFrame(frame); 738 } 739 740 private: 741 explicit VideoRendererWrapper(cricket::VideoRenderer* renderer) 742 : width_(0), height_(0), renderer_(renderer) {} 743 int width_, height_; 744 scoped_ptr<cricket::VideoRenderer> renderer_; 745}; 746 747// Wrapper dispatching webrtc::VideoRendererInterface to a Java VideoRenderer 748// instance. 749class JavaVideoRendererWrapper : public VideoRendererInterface { 750 public: 751 JavaVideoRendererWrapper(JNIEnv* jni, jobject j_callbacks) 752 : j_callbacks_(jni, j_callbacks), 753 j_render_frame_id_(GetMethodID( 754 jni, GetObjectClass(jni, j_callbacks), "renderFrame", 755 "(Lorg/webrtc/VideoRenderer$I420Frame;)V")), 756 j_frame_class_(jni, 757 FindClass(jni, "org/webrtc/VideoRenderer$I420Frame")), 758 j_i420_frame_ctor_id_(GetMethodID( 759 jni, *j_frame_class_, "<init>", "(III[I[Ljava/nio/ByteBuffer;J)V")), 760 j_texture_frame_ctor_id_(GetMethodID( 761 jni, *j_frame_class_, "<init>", 762 "(IIII[FJ)V")), 763 j_byte_buffer_class_(jni, FindClass(jni, "java/nio/ByteBuffer")) { 764 CHECK_EXCEPTION(jni); 765 } 766 767 virtual ~JavaVideoRendererWrapper() {} 768 769 void RenderFrame(const cricket::VideoFrame* video_frame) override { 770 ScopedLocalRefFrame local_ref_frame(jni()); 771 jobject j_frame = (video_frame->GetNativeHandle() != nullptr) 772 ? CricketToJavaTextureFrame(video_frame) 773 : CricketToJavaI420Frame(video_frame); 774 // |j_callbacks_| is responsible for releasing |j_frame| with 775 // VideoRenderer.renderFrameDone(). 776 jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame); 777 CHECK_EXCEPTION(jni()); 778 } 779 780 private: 781 // Make a shallow copy of |frame| to be used with Java. The callee has 782 // ownership of the frame, and the frame should be released with 783 // VideoRenderer.releaseNativeFrame(). 784 static jlong javaShallowCopy(const cricket::VideoFrame* frame) { 785 return jlongFromPointer(frame->Copy()); 786 } 787 788 // Return a VideoRenderer.I420Frame referring to the data in |frame|. 789 jobject CricketToJavaI420Frame(const cricket::VideoFrame* frame) { 790 jintArray strides = jni()->NewIntArray(3); 791 jint* strides_array = jni()->GetIntArrayElements(strides, NULL); 792 strides_array[0] = frame->GetYPitch(); 793 strides_array[1] = frame->GetUPitch(); 794 strides_array[2] = frame->GetVPitch(); 795 jni()->ReleaseIntArrayElements(strides, strides_array, 0); 796 jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL); 797 jobject y_buffer = 798 jni()->NewDirectByteBuffer(const_cast<uint8_t*>(frame->GetYPlane()), 799 frame->GetYPitch() * frame->GetHeight()); 800 jobject u_buffer = jni()->NewDirectByteBuffer( 801 const_cast<uint8_t*>(frame->GetUPlane()), frame->GetChromaSize()); 802 jobject v_buffer = jni()->NewDirectByteBuffer( 803 const_cast<uint8_t*>(frame->GetVPlane()), frame->GetChromaSize()); 804 jni()->SetObjectArrayElement(planes, 0, y_buffer); 805 jni()->SetObjectArrayElement(planes, 1, u_buffer); 806 jni()->SetObjectArrayElement(planes, 2, v_buffer); 807 return jni()->NewObject( 808 *j_frame_class_, j_i420_frame_ctor_id_, 809 frame->GetWidth(), frame->GetHeight(), 810 static_cast<int>(frame->GetVideoRotation()), 811 strides, planes, javaShallowCopy(frame)); 812 } 813 814 // Return a VideoRenderer.I420Frame referring texture object in |frame|. 815 jobject CricketToJavaTextureFrame(const cricket::VideoFrame* frame) { 816 NativeHandleImpl* handle = 817 reinterpret_cast<NativeHandleImpl*>(frame->GetNativeHandle()); 818 jfloatArray sampling_matrix = jni()->NewFloatArray(16); 819 jni()->SetFloatArrayRegion(sampling_matrix, 0, 16, handle->sampling_matrix); 820 return jni()->NewObject( 821 *j_frame_class_, j_texture_frame_ctor_id_, 822 frame->GetWidth(), frame->GetHeight(), 823 static_cast<int>(frame->GetVideoRotation()), 824 handle->oes_texture_id, sampling_matrix, javaShallowCopy(frame)); 825 } 826 827 JNIEnv* jni() { 828 return AttachCurrentThreadIfNeeded(); 829 } 830 831 ScopedGlobalRef<jobject> j_callbacks_; 832 jmethodID j_render_frame_id_; 833 ScopedGlobalRef<jclass> j_frame_class_; 834 jmethodID j_i420_frame_ctor_id_; 835 jmethodID j_texture_frame_ctor_id_; 836 ScopedGlobalRef<jclass> j_byte_buffer_class_; 837}; 838 839 840static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) { 841 jfieldID native_dc_id = GetFieldID(jni, 842 GetObjectClass(jni, j_dc), "nativeDataChannel", "J"); 843 jlong j_d = GetLongField(jni, j_dc, native_dc_id); 844 return reinterpret_cast<DataChannelInterface*>(j_d); 845} 846 847JOW(jlong, DataChannel_registerObserverNative)( 848 JNIEnv* jni, jobject j_dc, jobject j_observer) { 849 scoped_ptr<DataChannelObserverWrapper> observer( 850 new DataChannelObserverWrapper(jni, j_observer)); 851 ExtractNativeDC(jni, j_dc)->RegisterObserver(observer.get()); 852 return jlongFromPointer(observer.release()); 853} 854 855JOW(void, DataChannel_unregisterObserverNative)( 856 JNIEnv* jni, jobject j_dc, jlong native_observer) { 857 ExtractNativeDC(jni, j_dc)->UnregisterObserver(); 858 delete reinterpret_cast<DataChannelObserverWrapper*>(native_observer); 859} 860 861JOW(jstring, DataChannel_label)(JNIEnv* jni, jobject j_dc) { 862 return JavaStringFromStdString(jni, ExtractNativeDC(jni, j_dc)->label()); 863} 864 865JOW(jobject, DataChannel_state)(JNIEnv* jni, jobject j_dc) { 866 return JavaEnumFromIndex( 867 jni, "DataChannel$State", ExtractNativeDC(jni, j_dc)->state()); 868} 869 870JOW(jlong, DataChannel_bufferedAmount)(JNIEnv* jni, jobject j_dc) { 871 uint64_t buffered_amount = ExtractNativeDC(jni, j_dc)->buffered_amount(); 872 RTC_CHECK_LE(buffered_amount, std::numeric_limits<int64_t>::max()) 873 << "buffered_amount overflowed jlong!"; 874 return static_cast<jlong>(buffered_amount); 875} 876 877JOW(void, DataChannel_close)(JNIEnv* jni, jobject j_dc) { 878 ExtractNativeDC(jni, j_dc)->Close(); 879} 880 881JOW(jboolean, DataChannel_sendNative)(JNIEnv* jni, jobject j_dc, 882 jbyteArray data, jboolean binary) { 883 jbyte* bytes = jni->GetByteArrayElements(data, NULL); 884 bool ret = ExtractNativeDC(jni, j_dc)->Send(DataBuffer( 885 rtc::Buffer(bytes, jni->GetArrayLength(data)), 886 binary)); 887 jni->ReleaseByteArrayElements(data, bytes, JNI_ABORT); 888 return ret; 889} 890 891JOW(void, DataChannel_dispose)(JNIEnv* jni, jobject j_dc) { 892 CHECK_RELEASE(ExtractNativeDC(jni, j_dc)); 893} 894 895JOW(void, Logging_nativeEnableTracing)( 896 JNIEnv* jni, jclass, jstring j_path, jint nativeLevels, 897 jint nativeSeverity) { 898 std::string path = JavaToStdString(jni, j_path); 899 if (nativeLevels != webrtc::kTraceNone) { 900 webrtc::Trace::set_level_filter(nativeLevels); 901#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 902 if (path != "logcat:") { 903#endif 904 RTC_CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false)) 905 << "SetTraceFile failed"; 906#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 907 } else { 908 // Intentionally leak this to avoid needing to reason about its lifecycle. 909 // It keeps no state and functions only as a dispatch point. 910 static LogcatTraceContext* g_trace_callback = new LogcatTraceContext(); 911 } 912#endif 913 } 914 if (nativeSeverity >= rtc::LS_SENSITIVE && nativeSeverity <= rtc::LS_ERROR) { 915 rtc::LogMessage::LogToDebug( 916 static_cast<rtc::LoggingSeverity>(nativeSeverity)); 917 } 918} 919 920JOW(void, Logging_nativeEnableLogThreads)(JNIEnv* jni, jclass) { 921 rtc::LogMessage::LogThreads(true); 922} 923 924JOW(void, Logging_nativeEnableLogTimeStamps)(JNIEnv* jni, jclass) { 925 rtc::LogMessage::LogTimestamps(true); 926} 927 928JOW(void, Logging_nativeLog)( 929 JNIEnv* jni, jclass, jint j_severity, jstring j_tag, jstring j_message) { 930 std::string message = JavaToStdString(jni, j_message); 931 std::string tag = JavaToStdString(jni, j_tag); 932 LOG_TAG(static_cast<rtc::LoggingSeverity>(j_severity), tag) << message; 933} 934 935JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) { 936 CHECK_RELEASE(reinterpret_cast<PeerConnectionInterface*>(j_p)); 937} 938 939JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) { 940 PCOJava* p = reinterpret_cast<PCOJava*>(j_p); 941 delete p; 942} 943 944JOW(void, MediaSource_free)(JNIEnv*, jclass, jlong j_p) { 945 CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p)); 946} 947 948JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) { 949 delete reinterpret_cast<cricket::VideoCapturer*>(j_p); 950} 951 952JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) { 953 delete reinterpret_cast<VideoRendererWrapper*>(j_p); 954} 955 956JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) { 957 delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p); 958} 959 960JOW(void, VideoRenderer_releaseNativeFrame)( 961 JNIEnv* jni, jclass, jlong j_frame_ptr) { 962 delete reinterpret_cast<const cricket::VideoFrame*>(j_frame_ptr); 963} 964 965JOW(void, MediaStreamTrack_free)(JNIEnv*, jclass, jlong j_p) { 966 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->Release(); 967} 968 969JOW(jboolean, MediaStream_nativeAddAudioTrack)( 970 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) { 971 return reinterpret_cast<MediaStreamInterface*>(pointer)->AddTrack( 972 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer)); 973} 974 975JOW(jboolean, MediaStream_nativeAddVideoTrack)( 976 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) { 977 return reinterpret_cast<MediaStreamInterface*>(pointer) 978 ->AddTrack(reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)); 979} 980 981JOW(jboolean, MediaStream_nativeRemoveAudioTrack)( 982 JNIEnv* jni, jclass, jlong pointer, jlong j_audio_track_pointer) { 983 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack( 984 reinterpret_cast<AudioTrackInterface*>(j_audio_track_pointer)); 985} 986 987JOW(jboolean, MediaStream_nativeRemoveVideoTrack)( 988 JNIEnv* jni, jclass, jlong pointer, jlong j_video_track_pointer) { 989 return reinterpret_cast<MediaStreamInterface*>(pointer)->RemoveTrack( 990 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)); 991} 992 993JOW(jstring, MediaStream_nativeLabel)(JNIEnv* jni, jclass, jlong j_p) { 994 return JavaStringFromStdString( 995 jni, reinterpret_cast<MediaStreamInterface*>(j_p)->label()); 996} 997 998JOW(void, MediaStream_free)(JNIEnv*, jclass, jlong j_p) { 999 CHECK_RELEASE(reinterpret_cast<MediaStreamInterface*>(j_p)); 1000} 1001 1002JOW(jlong, PeerConnectionFactory_nativeCreateObserver)( 1003 JNIEnv * jni, jclass, jobject j_observer) { 1004 return (jlong)new PCOJava(jni, j_observer); 1005} 1006 1007#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 1008JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)( 1009 JNIEnv* jni, jclass, jobject context, 1010 jboolean initialize_audio, jboolean initialize_video, 1011 jboolean video_hw_acceleration) { 1012 bool failure = false; 1013 video_hw_acceleration_enabled = video_hw_acceleration; 1014 AndroidNetworkMonitor::SetAndroidContext(jni, context); 1015 if (!factory_static_initialized) { 1016 if (initialize_video) { 1017 failure |= webrtc::SetRenderAndroidVM(GetJVM()); 1018 failure |= AndroidVideoCapturerJni::SetAndroidObjects(jni, context); 1019 } 1020 if (initialize_audio) 1021 failure |= webrtc::VoiceEngine::SetAndroidObjects(GetJVM(), context); 1022 factory_static_initialized = true; 1023 } 1024 return !failure; 1025} 1026#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 1027 1028JOW(void, PeerConnectionFactory_initializeFieldTrials)( 1029 JNIEnv* jni, jclass, jstring j_trials_init_string) { 1030 field_trials_init_string = NULL; 1031 if (j_trials_init_string != NULL) { 1032 const char* init_string = 1033 jni->GetStringUTFChars(j_trials_init_string, NULL); 1034 int init_string_length = jni->GetStringUTFLength(j_trials_init_string); 1035 field_trials_init_string = new char[init_string_length + 1]; 1036 rtc::strcpyn(field_trials_init_string, init_string_length + 1, init_string); 1037 jni->ReleaseStringUTFChars(j_trials_init_string, init_string); 1038 LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string; 1039 } 1040 webrtc::field_trial::InitFieldTrialsFromString(field_trials_init_string); 1041} 1042 1043JOW(void, PeerConnectionFactory_initializeInternalTracer)(JNIEnv* jni, jclass) { 1044 rtc::tracing::SetupInternalTracer(); 1045} 1046 1047JOW(jboolean, PeerConnectionFactory_startInternalTracingCapture)( 1048 JNIEnv* jni, jclass, jstring j_event_tracing_filename) { 1049 if (!j_event_tracing_filename) 1050 return false; 1051 1052 const char* init_string = 1053 jni->GetStringUTFChars(j_event_tracing_filename, NULL); 1054 LOG(LS_INFO) << "Starting internal tracing to: " << init_string; 1055 bool ret = rtc::tracing::StartInternalCapture(init_string); 1056 jni->ReleaseStringUTFChars(j_event_tracing_filename, init_string); 1057 return ret; 1058} 1059 1060JOW(void, PeerConnectionFactory_stopInternalTracingCapture)( 1061 JNIEnv* jni, jclass) { 1062 rtc::tracing::StopInternalCapture(); 1063} 1064 1065JOW(void, PeerConnectionFactory_shutdownInternalTracer)(JNIEnv* jni, jclass) { 1066 rtc::tracing::ShutdownInternalTracer(); 1067} 1068 1069// Helper struct for working around the fact that CreatePeerConnectionFactory() 1070// comes in two flavors: either entirely automagical (constructing its own 1071// threads and deleting them on teardown, but no external codec factory support) 1072// or entirely manual (requires caller to delete threads after factory 1073// teardown). This struct takes ownership of its ctor's arguments to present a 1074// single thing for Java to hold and eventually free. 1075class OwnedFactoryAndThreads { 1076 public: 1077 OwnedFactoryAndThreads(Thread* worker_thread, 1078 Thread* signaling_thread, 1079 WebRtcVideoEncoderFactory* encoder_factory, 1080 WebRtcVideoDecoderFactory* decoder_factory, 1081 rtc::NetworkMonitorFactory* network_monitor_factory, 1082 PeerConnectionFactoryInterface* factory) 1083 : worker_thread_(worker_thread), 1084 signaling_thread_(signaling_thread), 1085 encoder_factory_(encoder_factory), 1086 decoder_factory_(decoder_factory), 1087 network_monitor_factory_(network_monitor_factory), 1088 factory_(factory) {} 1089 1090 ~OwnedFactoryAndThreads() { 1091 CHECK_RELEASE(factory_); 1092 if (network_monitor_factory_ != nullptr) { 1093 rtc::NetworkMonitorFactory::ReleaseFactory(network_monitor_factory_); 1094 } 1095 } 1096 1097 PeerConnectionFactoryInterface* factory() { return factory_; } 1098 WebRtcVideoEncoderFactory* encoder_factory() { return encoder_factory_; } 1099 WebRtcVideoDecoderFactory* decoder_factory() { return decoder_factory_; } 1100 rtc::NetworkMonitorFactory* network_monitor_factory() { 1101 return network_monitor_factory_; 1102 } 1103 void clear_network_monitor_factory() { network_monitor_factory_ = nullptr; } 1104 void InvokeJavaCallbacksOnFactoryThreads(); 1105 1106 private: 1107 void JavaCallbackOnFactoryThreads(); 1108 1109 const scoped_ptr<Thread> worker_thread_; 1110 const scoped_ptr<Thread> signaling_thread_; 1111 WebRtcVideoEncoderFactory* encoder_factory_; 1112 WebRtcVideoDecoderFactory* decoder_factory_; 1113 rtc::NetworkMonitorFactory* network_monitor_factory_; 1114 PeerConnectionFactoryInterface* factory_; // Const after ctor except dtor. 1115}; 1116 1117void OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads() { 1118 JNIEnv* jni = AttachCurrentThreadIfNeeded(); 1119 ScopedLocalRefFrame local_ref_frame(jni); 1120 jclass j_factory_class = FindClass(jni, "org/webrtc/PeerConnectionFactory"); 1121 jmethodID m = nullptr; 1122 if (Thread::Current() == worker_thread_) { 1123 LOG(LS_INFO) << "Worker thread JavaCallback"; 1124 m = GetStaticMethodID(jni, j_factory_class, "onWorkerThreadReady", "()V"); 1125 } 1126 if (Thread::Current() == signaling_thread_) { 1127 LOG(LS_INFO) << "Signaling thread JavaCallback"; 1128 m = GetStaticMethodID( 1129 jni, j_factory_class, "onSignalingThreadReady", "()V"); 1130 } 1131 if (m != nullptr) { 1132 jni->CallStaticVoidMethod(j_factory_class, m); 1133 CHECK_EXCEPTION(jni) << "error during JavaCallback::CallStaticVoidMethod"; 1134 } 1135} 1136 1137void OwnedFactoryAndThreads::InvokeJavaCallbacksOnFactoryThreads() { 1138 LOG(LS_INFO) << "InvokeJavaCallbacksOnFactoryThreads."; 1139 worker_thread_->Invoke<void>( 1140 Bind(&OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads, this)); 1141 signaling_thread_->Invoke<void>( 1142 Bind(&OwnedFactoryAndThreads::JavaCallbackOnFactoryThreads, this)); 1143} 1144 1145JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnectionFactory)( 1146 JNIEnv* jni, jclass) { 1147 // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but 1148 // ThreadManager only WrapCurrentThread()s the thread where it is first 1149 // created. Since the semantics around when auto-wrapping happens in 1150 // webrtc/base/ are convoluted, we simply wrap here to avoid having to think 1151 // about ramifications of auto-wrapping there. 1152 rtc::ThreadManager::Instance()->WrapCurrentThread(); 1153 webrtc::Trace::CreateTrace(); 1154 Thread* worker_thread = new Thread(); 1155 worker_thread->SetName("worker_thread", NULL); 1156 Thread* signaling_thread = new Thread(); 1157 signaling_thread->SetName("signaling_thread", NULL); 1158 RTC_CHECK(worker_thread->Start() && signaling_thread->Start()) 1159 << "Failed to start threads"; 1160 WebRtcVideoEncoderFactory* encoder_factory = nullptr; 1161 WebRtcVideoDecoderFactory* decoder_factory = nullptr; 1162 rtc::NetworkMonitorFactory* network_monitor_factory = nullptr; 1163 1164#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 1165 if (video_hw_acceleration_enabled) { 1166 encoder_factory = new MediaCodecVideoEncoderFactory(); 1167 decoder_factory = new MediaCodecVideoDecoderFactory(); 1168 } 1169 network_monitor_factory = new AndroidNetworkMonitorFactory(); 1170 rtc::NetworkMonitorFactory::SetFactory(network_monitor_factory); 1171#endif 1172 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1173 webrtc::CreatePeerConnectionFactory(worker_thread, 1174 signaling_thread, 1175 NULL, 1176 encoder_factory, 1177 decoder_factory)); 1178 RTC_CHECK(factory) << "Failed to create the peer connection factory; " 1179 << "WebRTC/libjingle init likely failed on this device"; 1180 OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads( 1181 worker_thread, signaling_thread, 1182 encoder_factory, decoder_factory, 1183 network_monitor_factory, factory.release()); 1184 owned_factory->InvokeJavaCallbacksOnFactoryThreads(); 1185 return jlongFromPointer(owned_factory); 1186} 1187 1188JOW(void, PeerConnectionFactory_nativeFreeFactory)(JNIEnv*, jclass, jlong j_p) { 1189 delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p); 1190 if (field_trials_init_string) { 1191 webrtc::field_trial::InitFieldTrialsFromString(NULL); 1192 delete field_trials_init_string; 1193 field_trials_init_string = NULL; 1194 } 1195 webrtc::Trace::ReturnTrace(); 1196} 1197 1198static PeerConnectionFactoryInterface* factoryFromJava(jlong j_p) { 1199 return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory(); 1200} 1201 1202JOW(void, PeerConnectionFactory_nativeThreadsCallbacks)( 1203 JNIEnv*, jclass, jlong j_p) { 1204 OwnedFactoryAndThreads *factory = 1205 reinterpret_cast<OwnedFactoryAndThreads*>(j_p); 1206 factory->InvokeJavaCallbacksOnFactoryThreads(); 1207} 1208 1209JOW(jlong, PeerConnectionFactory_nativeCreateLocalMediaStream)( 1210 JNIEnv* jni, jclass, jlong native_factory, jstring label) { 1211 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1212 factoryFromJava(native_factory)); 1213 rtc::scoped_refptr<MediaStreamInterface> stream( 1214 factory->CreateLocalMediaStream(JavaToStdString(jni, label))); 1215 return (jlong)stream.release(); 1216} 1217 1218JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)( 1219 JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer, 1220 jobject j_constraints) { 1221 scoped_ptr<ConstraintsWrapper> constraints( 1222 new ConstraintsWrapper(jni, j_constraints)); 1223 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1224 factoryFromJava(native_factory)); 1225 rtc::scoped_refptr<VideoSourceInterface> source( 1226 factory->CreateVideoSource( 1227 reinterpret_cast<cricket::VideoCapturer*>(native_capturer), 1228 constraints.get())); 1229 return (jlong)source.release(); 1230} 1231 1232JOW(jlong, PeerConnectionFactory_nativeCreateVideoTrack)( 1233 JNIEnv* jni, jclass, jlong native_factory, jstring id, 1234 jlong native_source) { 1235 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1236 factoryFromJava(native_factory)); 1237 rtc::scoped_refptr<VideoTrackInterface> track( 1238 factory->CreateVideoTrack( 1239 JavaToStdString(jni, id), 1240 reinterpret_cast<VideoSourceInterface*>(native_source))); 1241 return (jlong)track.release(); 1242} 1243 1244JOW(jlong, PeerConnectionFactory_nativeCreateAudioSource)( 1245 JNIEnv* jni, jclass, jlong native_factory, jobject j_constraints) { 1246 scoped_ptr<ConstraintsWrapper> constraints( 1247 new ConstraintsWrapper(jni, j_constraints)); 1248 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1249 factoryFromJava(native_factory)); 1250 rtc::scoped_refptr<AudioSourceInterface> source( 1251 factory->CreateAudioSource(constraints.get())); 1252 return (jlong)source.release(); 1253} 1254 1255JOW(jlong, PeerConnectionFactory_nativeCreateAudioTrack)( 1256 JNIEnv* jni, jclass, jlong native_factory, jstring id, 1257 jlong native_source) { 1258 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1259 factoryFromJava(native_factory)); 1260 rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack( 1261 JavaToStdString(jni, id), 1262 reinterpret_cast<AudioSourceInterface*>(native_source))); 1263 return (jlong)track.release(); 1264} 1265 1266JOW(jboolean, PeerConnectionFactory_nativeStartAecDump)( 1267 JNIEnv* jni, jclass, jlong native_factory, jint file) { 1268#if defined(ANDROID) 1269 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1270 factoryFromJava(native_factory)); 1271 return factory->StartAecDump(file); 1272#else 1273 return false; 1274#endif 1275} 1276 1277JOW(void, PeerConnectionFactory_nativeStopAecDump)( 1278 JNIEnv* jni, jclass, jlong native_factory) { 1279#if defined(ANDROID) 1280 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1281 factoryFromJava(native_factory)); 1282 factory->StopAecDump(); 1283#endif 1284} 1285 1286JOW(jboolean, PeerConnectionFactory_nativeStartRtcEventLog)( 1287 JNIEnv* jni, jclass, jlong native_factory, jint file) { 1288#if defined(ANDROID) 1289 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1290 factoryFromJava(native_factory)); 1291 return factory->StartRtcEventLog(file); 1292#else 1293 return false; 1294#endif 1295} 1296 1297JOW(void, PeerConnectionFactory_nativeStopRtcEventLog)( 1298 JNIEnv* jni, jclass, jlong native_factory) { 1299#if defined(ANDROID) 1300 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1301 factoryFromJava(native_factory)); 1302 factory->StopRtcEventLog(); 1303#endif 1304} 1305 1306JOW(void, PeerConnectionFactory_nativeSetOptions)( 1307 JNIEnv* jni, jclass, jlong native_factory, jobject options) { 1308 rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( 1309 factoryFromJava(native_factory)); 1310 jclass options_class = jni->GetObjectClass(options); 1311 jfieldID network_ignore_mask_field = 1312 jni->GetFieldID(options_class, "networkIgnoreMask", "I"); 1313 int network_ignore_mask = 1314 jni->GetIntField(options, network_ignore_mask_field); 1315 1316 jfieldID disable_encryption_field = 1317 jni->GetFieldID(options_class, "disableEncryption", "Z"); 1318 bool disable_encryption = 1319 jni->GetBooleanField(options, disable_encryption_field); 1320 1321 jfieldID disable_network_monitor_field = 1322 jni->GetFieldID(options_class, "disableNetworkMonitor", "Z"); 1323 bool disable_network_monitor = 1324 jni->GetBooleanField(options, disable_network_monitor_field); 1325 1326 PeerConnectionFactoryInterface::Options options_to_set; 1327 1328 // This doesn't necessarily match the c++ version of this struct; feel free 1329 // to add more parameters as necessary. 1330 options_to_set.network_ignore_mask = network_ignore_mask; 1331 options_to_set.disable_encryption = disable_encryption; 1332 options_to_set.disable_network_monitor = disable_network_monitor; 1333 factory->SetOptions(options_to_set); 1334 1335 if (disable_network_monitor) { 1336 OwnedFactoryAndThreads* owner = 1337 reinterpret_cast<OwnedFactoryAndThreads*>(native_factory); 1338 if (owner->network_monitor_factory()) { 1339 rtc::NetworkMonitorFactory::ReleaseFactory( 1340 owner->network_monitor_factory()); 1341 owner->clear_network_monitor_factory(); 1342 } 1343 } 1344} 1345 1346JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions)( 1347 JNIEnv* jni, jclass, jlong native_factory, jobject local_egl_context, 1348 jobject remote_egl_context) { 1349#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) 1350 OwnedFactoryAndThreads* owned_factory = 1351 reinterpret_cast<OwnedFactoryAndThreads*>(native_factory); 1352 1353 jclass j_eglbase14_context_class = 1354 FindClass(jni, "org/webrtc/EglBase14$Context"); 1355 1356 MediaCodecVideoEncoderFactory* encoder_factory = 1357 static_cast<MediaCodecVideoEncoderFactory*> 1358 (owned_factory->encoder_factory()); 1359 if (encoder_factory && 1360 jni->IsInstanceOf(local_egl_context, j_eglbase14_context_class)) { 1361 LOG(LS_INFO) << "Set EGL context for HW encoding."; 1362 encoder_factory->SetEGLContext(jni, local_egl_context); 1363 } 1364 1365 MediaCodecVideoDecoderFactory* decoder_factory = 1366 static_cast<MediaCodecVideoDecoderFactory*> 1367 (owned_factory->decoder_factory()); 1368 if (decoder_factory && 1369 jni->IsInstanceOf(remote_egl_context, j_eglbase14_context_class)) { 1370 LOG(LS_INFO) << "Set EGL context for HW decoding."; 1371 decoder_factory->SetEGLContext(jni, remote_egl_context); 1372 } 1373#endif 1374} 1375 1376static std::string 1377GetJavaEnumName(JNIEnv* jni, const std::string& className, jobject j_enum) { 1378 jclass enumClass = FindClass(jni, className.c_str()); 1379 jmethodID nameMethod = 1380 GetMethodID(jni, enumClass, "name", "()Ljava/lang/String;"); 1381 jstring name = 1382 reinterpret_cast<jstring>(jni->CallObjectMethod(j_enum, nameMethod)); 1383 CHECK_EXCEPTION(jni) << "error during CallObjectMethod for " 1384 << className << ".name"; 1385 return JavaToStdString(jni, name); 1386} 1387 1388static PeerConnectionInterface::IceTransportsType 1389JavaIceTransportsTypeToNativeType(JNIEnv* jni, jobject j_ice_transports_type) { 1390 std::string enum_name = GetJavaEnumName( 1391 jni, "org/webrtc/PeerConnection$IceTransportsType", 1392 j_ice_transports_type); 1393 1394 if (enum_name == "ALL") 1395 return PeerConnectionInterface::kAll; 1396 1397 if (enum_name == "RELAY") 1398 return PeerConnectionInterface::kRelay; 1399 1400 if (enum_name == "NOHOST") 1401 return PeerConnectionInterface::kNoHost; 1402 1403 if (enum_name == "NONE") 1404 return PeerConnectionInterface::kNone; 1405 1406 RTC_CHECK(false) << "Unexpected IceTransportsType enum_name " << enum_name; 1407 return PeerConnectionInterface::kAll; 1408} 1409 1410static PeerConnectionInterface::BundlePolicy 1411JavaBundlePolicyToNativeType(JNIEnv* jni, jobject j_bundle_policy) { 1412 std::string enum_name = GetJavaEnumName( 1413 jni, "org/webrtc/PeerConnection$BundlePolicy", 1414 j_bundle_policy); 1415 1416 if (enum_name == "BALANCED") 1417 return PeerConnectionInterface::kBundlePolicyBalanced; 1418 1419 if (enum_name == "MAXBUNDLE") 1420 return PeerConnectionInterface::kBundlePolicyMaxBundle; 1421 1422 if (enum_name == "MAXCOMPAT") 1423 return PeerConnectionInterface::kBundlePolicyMaxCompat; 1424 1425 RTC_CHECK(false) << "Unexpected BundlePolicy enum_name " << enum_name; 1426 return PeerConnectionInterface::kBundlePolicyBalanced; 1427} 1428 1429static PeerConnectionInterface::RtcpMuxPolicy 1430JavaRtcpMuxPolicyToNativeType(JNIEnv* jni, jobject j_rtcp_mux_policy) { 1431 std::string enum_name = GetJavaEnumName( 1432 jni, "org/webrtc/PeerConnection$RtcpMuxPolicy", 1433 j_rtcp_mux_policy); 1434 1435 if (enum_name == "NEGOTIATE") 1436 return PeerConnectionInterface::kRtcpMuxPolicyNegotiate; 1437 1438 if (enum_name == "REQUIRE") 1439 return PeerConnectionInterface::kRtcpMuxPolicyRequire; 1440 1441 RTC_CHECK(false) << "Unexpected RtcpMuxPolicy enum_name " << enum_name; 1442 return PeerConnectionInterface::kRtcpMuxPolicyNegotiate; 1443} 1444 1445static PeerConnectionInterface::TcpCandidatePolicy 1446JavaTcpCandidatePolicyToNativeType( 1447 JNIEnv* jni, jobject j_tcp_candidate_policy) { 1448 std::string enum_name = GetJavaEnumName( 1449 jni, "org/webrtc/PeerConnection$TcpCandidatePolicy", 1450 j_tcp_candidate_policy); 1451 1452 if (enum_name == "ENABLED") 1453 return PeerConnectionInterface::kTcpCandidatePolicyEnabled; 1454 1455 if (enum_name == "DISABLED") 1456 return PeerConnectionInterface::kTcpCandidatePolicyDisabled; 1457 1458 RTC_CHECK(false) << "Unexpected TcpCandidatePolicy enum_name " << enum_name; 1459 return PeerConnectionInterface::kTcpCandidatePolicyEnabled; 1460} 1461 1462static rtc::KeyType JavaKeyTypeToNativeType(JNIEnv* jni, jobject j_key_type) { 1463 std::string enum_name = GetJavaEnumName( 1464 jni, "org/webrtc/PeerConnection$KeyType", j_key_type); 1465 1466 if (enum_name == "RSA") 1467 return rtc::KT_RSA; 1468 if (enum_name == "ECDSA") 1469 return rtc::KT_ECDSA; 1470 1471 RTC_CHECK(false) << "Unexpected KeyType enum_name " << enum_name; 1472 return rtc::KT_ECDSA; 1473} 1474 1475static PeerConnectionInterface::ContinualGatheringPolicy 1476 JavaContinualGatheringPolicyToNativeType( 1477 JNIEnv* jni, jobject j_gathering_policy) { 1478 std::string enum_name = GetJavaEnumName( 1479 jni, "org/webrtc/PeerConnection$ContinualGatheringPolicy", 1480 j_gathering_policy); 1481 if (enum_name == "GATHER_ONCE") 1482 return PeerConnectionInterface::GATHER_ONCE; 1483 1484 if (enum_name == "GATHER_CONTINUALLY") 1485 return PeerConnectionInterface::GATHER_CONTINUALLY; 1486 1487 RTC_CHECK(false) << "Unexpected ContinualGatheringPolicy enum name " 1488 << enum_name; 1489 return PeerConnectionInterface::GATHER_ONCE; 1490} 1491 1492static void JavaIceServersToJsepIceServers( 1493 JNIEnv* jni, jobject j_ice_servers, 1494 PeerConnectionInterface::IceServers* ice_servers) { 1495 jclass list_class = GetObjectClass(jni, j_ice_servers); 1496 jmethodID iterator_id = GetMethodID( 1497 jni, list_class, "iterator", "()Ljava/util/Iterator;"); 1498 jobject iterator = jni->CallObjectMethod(j_ice_servers, iterator_id); 1499 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 1500 jmethodID iterator_has_next = GetMethodID( 1501 jni, GetObjectClass(jni, iterator), "hasNext", "()Z"); 1502 jmethodID iterator_next = GetMethodID( 1503 jni, GetObjectClass(jni, iterator), "next", "()Ljava/lang/Object;"); 1504 while (jni->CallBooleanMethod(iterator, iterator_has_next)) { 1505 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; 1506 jobject j_ice_server = jni->CallObjectMethod(iterator, iterator_next); 1507 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 1508 jclass j_ice_server_class = GetObjectClass(jni, j_ice_server); 1509 jfieldID j_ice_server_uri_id = 1510 GetFieldID(jni, j_ice_server_class, "uri", "Ljava/lang/String;"); 1511 jfieldID j_ice_server_username_id = 1512 GetFieldID(jni, j_ice_server_class, "username", "Ljava/lang/String;"); 1513 jfieldID j_ice_server_password_id = 1514 GetFieldID(jni, j_ice_server_class, "password", "Ljava/lang/String;"); 1515 jstring uri = reinterpret_cast<jstring>( 1516 GetObjectField(jni, j_ice_server, j_ice_server_uri_id)); 1517 jstring username = reinterpret_cast<jstring>( 1518 GetObjectField(jni, j_ice_server, j_ice_server_username_id)); 1519 jstring password = reinterpret_cast<jstring>( 1520 GetObjectField(jni, j_ice_server, j_ice_server_password_id)); 1521 PeerConnectionInterface::IceServer server; 1522 server.uri = JavaToStdString(jni, uri); 1523 server.username = JavaToStdString(jni, username); 1524 server.password = JavaToStdString(jni, password); 1525 ice_servers->push_back(server); 1526 } 1527 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; 1528} 1529 1530static void JavaRTCConfigurationToJsepRTCConfiguration( 1531 JNIEnv* jni, 1532 jobject j_rtc_config, 1533 PeerConnectionInterface::RTCConfiguration* rtc_config) { 1534 jclass j_rtc_config_class = GetObjectClass(jni, j_rtc_config); 1535 1536 jfieldID j_ice_transports_type_id = GetFieldID( 1537 jni, j_rtc_config_class, "iceTransportsType", 1538 "Lorg/webrtc/PeerConnection$IceTransportsType;"); 1539 jobject j_ice_transports_type = GetObjectField( 1540 jni, j_rtc_config, j_ice_transports_type_id); 1541 1542 jfieldID j_bundle_policy_id = GetFieldID( 1543 jni, j_rtc_config_class, "bundlePolicy", 1544 "Lorg/webrtc/PeerConnection$BundlePolicy;"); 1545 jobject j_bundle_policy = GetObjectField( 1546 jni, j_rtc_config, j_bundle_policy_id); 1547 1548 jfieldID j_rtcp_mux_policy_id = GetFieldID( 1549 jni, j_rtc_config_class, "rtcpMuxPolicy", 1550 "Lorg/webrtc/PeerConnection$RtcpMuxPolicy;"); 1551 jobject j_rtcp_mux_policy = GetObjectField( 1552 jni, j_rtc_config, j_rtcp_mux_policy_id); 1553 1554 jfieldID j_tcp_candidate_policy_id = GetFieldID( 1555 jni, j_rtc_config_class, "tcpCandidatePolicy", 1556 "Lorg/webrtc/PeerConnection$TcpCandidatePolicy;"); 1557 jobject j_tcp_candidate_policy = GetObjectField( 1558 jni, j_rtc_config, j_tcp_candidate_policy_id); 1559 1560 jfieldID j_ice_servers_id = GetFieldID( 1561 jni, j_rtc_config_class, "iceServers", "Ljava/util/List;"); 1562 jobject j_ice_servers = GetObjectField(jni, j_rtc_config, j_ice_servers_id); 1563 1564 jfieldID j_audio_jitter_buffer_max_packets_id = 1565 GetFieldID(jni, j_rtc_config_class, "audioJitterBufferMaxPackets", "I"); 1566 jfieldID j_audio_jitter_buffer_fast_accelerate_id = GetFieldID( 1567 jni, j_rtc_config_class, "audioJitterBufferFastAccelerate", "Z"); 1568 1569 jfieldID j_ice_connection_receiving_timeout_id = 1570 GetFieldID(jni, j_rtc_config_class, "iceConnectionReceivingTimeout", "I"); 1571 1572 jfieldID j_ice_backup_candidate_pair_ping_interval_id = GetFieldID( 1573 jni, j_rtc_config_class, "iceBackupCandidatePairPingInterval", "I"); 1574 1575 jfieldID j_continual_gathering_policy_id = 1576 GetFieldID(jni, j_rtc_config_class, "continualGatheringPolicy", 1577 "Lorg/webrtc/PeerConnection$ContinualGatheringPolicy;"); 1578 jobject j_continual_gathering_policy = 1579 GetObjectField(jni, j_rtc_config, j_continual_gathering_policy_id); 1580 1581 rtc_config->type = 1582 JavaIceTransportsTypeToNativeType(jni, j_ice_transports_type); 1583 rtc_config->bundle_policy = 1584 JavaBundlePolicyToNativeType(jni, j_bundle_policy); 1585 rtc_config->rtcp_mux_policy = 1586 JavaRtcpMuxPolicyToNativeType(jni, j_rtcp_mux_policy); 1587 rtc_config->tcp_candidate_policy = 1588 JavaTcpCandidatePolicyToNativeType(jni, j_tcp_candidate_policy); 1589 JavaIceServersToJsepIceServers(jni, j_ice_servers, &rtc_config->servers); 1590 rtc_config->audio_jitter_buffer_max_packets = 1591 GetIntField(jni, j_rtc_config, j_audio_jitter_buffer_max_packets_id); 1592 rtc_config->audio_jitter_buffer_fast_accelerate = GetBooleanField( 1593 jni, j_rtc_config, j_audio_jitter_buffer_fast_accelerate_id); 1594 rtc_config->ice_connection_receiving_timeout = 1595 GetIntField(jni, j_rtc_config, j_ice_connection_receiving_timeout_id); 1596 rtc_config->ice_backup_candidate_pair_ping_interval = GetIntField( 1597 jni, j_rtc_config, j_ice_backup_candidate_pair_ping_interval_id); 1598 rtc_config->continual_gathering_policy = 1599 JavaContinualGatheringPolicyToNativeType( 1600 jni, j_continual_gathering_policy); 1601} 1602 1603JOW(jlong, PeerConnectionFactory_nativeCreatePeerConnection)( 1604 JNIEnv *jni, jclass, jlong factory, jobject j_rtc_config, 1605 jobject j_constraints, jlong observer_p) { 1606 rtc::scoped_refptr<PeerConnectionFactoryInterface> f( 1607 reinterpret_cast<PeerConnectionFactoryInterface*>( 1608 factoryFromJava(factory))); 1609 1610 PeerConnectionInterface::RTCConfiguration rtc_config; 1611 JavaRTCConfigurationToJsepRTCConfiguration(jni, j_rtc_config, &rtc_config); 1612 1613 jclass j_rtc_config_class = GetObjectClass(jni, j_rtc_config); 1614 jfieldID j_key_type_id = GetFieldID(jni, j_rtc_config_class, "keyType", 1615 "Lorg/webrtc/PeerConnection$KeyType;"); 1616 jobject j_key_type = GetObjectField(jni, j_rtc_config, j_key_type_id); 1617 1618 // Create ECDSA certificate. 1619 if (JavaKeyTypeToNativeType(jni, j_key_type) == rtc::KT_ECDSA) { 1620 scoped_ptr<rtc::SSLIdentity> ssl_identity( 1621 rtc::SSLIdentity::Generate(webrtc::kIdentityName, rtc::KT_ECDSA)); 1622 if (ssl_identity.get()) { 1623 rtc_config.certificates.push_back( 1624 rtc::RTCCertificate::Create(std::move(ssl_identity))); 1625 LOG(LS_INFO) << "ECDSA certificate created."; 1626 } else { 1627 // Failing to create certificate should not abort peer connection 1628 // creation. Instead default encryption (currently RSA) will be used. 1629 LOG(LS_WARNING) << 1630 "Failed to generate SSLIdentity. Default encryption will be used."; 1631 } 1632 } 1633 1634 PCOJava* observer = reinterpret_cast<PCOJava*>(observer_p); 1635 observer->SetConstraints(new ConstraintsWrapper(jni, j_constraints)); 1636 rtc::scoped_refptr<PeerConnectionInterface> pc(f->CreatePeerConnection( 1637 rtc_config, observer->constraints(), NULL, NULL, observer)); 1638 return (jlong)pc.release(); 1639} 1640 1641static rtc::scoped_refptr<PeerConnectionInterface> ExtractNativePC( 1642 JNIEnv* jni, jobject j_pc) { 1643 jfieldID native_pc_id = GetFieldID(jni, 1644 GetObjectClass(jni, j_pc), "nativePeerConnection", "J"); 1645 jlong j_p = GetLongField(jni, j_pc, native_pc_id); 1646 return rtc::scoped_refptr<PeerConnectionInterface>( 1647 reinterpret_cast<PeerConnectionInterface*>(j_p)); 1648} 1649 1650JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) { 1651 const SessionDescriptionInterface* sdp = 1652 ExtractNativePC(jni, j_pc)->local_description(); 1653 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL; 1654} 1655 1656JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) { 1657 const SessionDescriptionInterface* sdp = 1658 ExtractNativePC(jni, j_pc)->remote_description(); 1659 return sdp ? JavaSdpFromNativeSdp(jni, sdp) : NULL; 1660} 1661 1662JOW(jobject, PeerConnection_createDataChannel)( 1663 JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) { 1664 DataChannelInit init = JavaDataChannelInitToNative(jni, j_init); 1665 rtc::scoped_refptr<DataChannelInterface> channel( 1666 ExtractNativePC(jni, j_pc)->CreateDataChannel( 1667 JavaToStdString(jni, j_label), &init)); 1668 // Mustn't pass channel.get() directly through NewObject to avoid reading its 1669 // vararg parameter as 64-bit and reading memory that doesn't belong to the 1670 // 32-bit parameter. 1671 jlong nativeChannelPtr = jlongFromPointer(channel.get()); 1672 RTC_CHECK(nativeChannelPtr) << "Failed to create DataChannel"; 1673 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel"); 1674 jmethodID j_data_channel_ctor = GetMethodID( 1675 jni, j_data_channel_class, "<init>", "(J)V"); 1676 jobject j_channel = jni->NewObject( 1677 j_data_channel_class, j_data_channel_ctor, nativeChannelPtr); 1678 CHECK_EXCEPTION(jni) << "error during NewObject"; 1679 // Channel is now owned by Java object, and will be freed from there. 1680 int bumped_count = channel->AddRef(); 1681 RTC_CHECK(bumped_count == 2) << "Unexpected refcount"; 1682 return j_channel; 1683} 1684 1685JOW(void, PeerConnection_createOffer)( 1686 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) { 1687 ConstraintsWrapper* constraints = 1688 new ConstraintsWrapper(jni, j_constraints); 1689 rtc::scoped_refptr<CreateSdpObserverWrapper> observer( 1690 new rtc::RefCountedObject<CreateSdpObserverWrapper>( 1691 jni, j_observer, constraints)); 1692 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints); 1693} 1694 1695JOW(void, PeerConnection_createAnswer)( 1696 JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) { 1697 ConstraintsWrapper* constraints = 1698 new ConstraintsWrapper(jni, j_constraints); 1699 rtc::scoped_refptr<CreateSdpObserverWrapper> observer( 1700 new rtc::RefCountedObject<CreateSdpObserverWrapper>( 1701 jni, j_observer, constraints)); 1702 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints); 1703} 1704 1705// Helper to create a SessionDescriptionInterface from a SessionDescription. 1706static SessionDescriptionInterface* JavaSdpToNativeSdp( 1707 JNIEnv* jni, jobject j_sdp) { 1708 jfieldID j_type_id = GetFieldID( 1709 jni, GetObjectClass(jni, j_sdp), "type", 1710 "Lorg/webrtc/SessionDescription$Type;"); 1711 jobject j_type = GetObjectField(jni, j_sdp, j_type_id); 1712 jmethodID j_canonical_form_id = GetMethodID( 1713 jni, GetObjectClass(jni, j_type), "canonicalForm", 1714 "()Ljava/lang/String;"); 1715 jstring j_type_string = (jstring)jni->CallObjectMethod( 1716 j_type, j_canonical_form_id); 1717 CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; 1718 std::string std_type = JavaToStdString(jni, j_type_string); 1719 1720 jfieldID j_description_id = GetFieldID( 1721 jni, GetObjectClass(jni, j_sdp), "description", "Ljava/lang/String;"); 1722 jstring j_description = (jstring)GetObjectField(jni, j_sdp, j_description_id); 1723 std::string std_description = JavaToStdString(jni, j_description); 1724 1725 return webrtc::CreateSessionDescription( 1726 std_type, std_description, NULL); 1727} 1728 1729JOW(void, PeerConnection_setLocalDescription)( 1730 JNIEnv* jni, jobject j_pc, 1731 jobject j_observer, jobject j_sdp) { 1732 rtc::scoped_refptr<SetSdpObserverWrapper> observer( 1733 new rtc::RefCountedObject<SetSdpObserverWrapper>( 1734 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL))); 1735 ExtractNativePC(jni, j_pc)->SetLocalDescription( 1736 observer, JavaSdpToNativeSdp(jni, j_sdp)); 1737} 1738 1739JOW(void, PeerConnection_setRemoteDescription)( 1740 JNIEnv* jni, jobject j_pc, 1741 jobject j_observer, jobject j_sdp) { 1742 rtc::scoped_refptr<SetSdpObserverWrapper> observer( 1743 new rtc::RefCountedObject<SetSdpObserverWrapper>( 1744 jni, j_observer, reinterpret_cast<ConstraintsWrapper*>(NULL))); 1745 ExtractNativePC(jni, j_pc)->SetRemoteDescription( 1746 observer, JavaSdpToNativeSdp(jni, j_sdp)); 1747} 1748 1749JOW(jboolean, PeerConnection_setConfiguration)( 1750 JNIEnv* jni, jobject j_pc, jobject j_rtc_config) { 1751 PeerConnectionInterface::RTCConfiguration rtc_config; 1752 JavaRTCConfigurationToJsepRTCConfiguration(jni, j_rtc_config, &rtc_config); 1753 return ExtractNativePC(jni, j_pc)->SetConfiguration(rtc_config); 1754} 1755 1756JOW(jboolean, PeerConnection_nativeAddIceCandidate)( 1757 JNIEnv* jni, jobject j_pc, jstring j_sdp_mid, 1758 jint j_sdp_mline_index, jstring j_candidate_sdp) { 1759 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid); 1760 std::string sdp = JavaToStdString(jni, j_candidate_sdp); 1761 scoped_ptr<IceCandidateInterface> candidate( 1762 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, NULL)); 1763 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get()); 1764} 1765 1766JOW(jboolean, PeerConnection_nativeAddLocalStream)( 1767 JNIEnv* jni, jobject j_pc, jlong native_stream) { 1768 return ExtractNativePC(jni, j_pc)->AddStream( 1769 reinterpret_cast<MediaStreamInterface*>(native_stream)); 1770} 1771 1772JOW(void, PeerConnection_nativeRemoveLocalStream)( 1773 JNIEnv* jni, jobject j_pc, jlong native_stream) { 1774 ExtractNativePC(jni, j_pc)->RemoveStream( 1775 reinterpret_cast<MediaStreamInterface*>(native_stream)); 1776} 1777 1778JOW(jobject, PeerConnection_nativeCreateSender)( 1779 JNIEnv* jni, jobject j_pc, jstring j_kind, jstring j_stream_id) { 1780 jclass j_rtp_sender_class = FindClass(jni, "org/webrtc/RtpSender"); 1781 jmethodID j_rtp_sender_ctor = 1782 GetMethodID(jni, j_rtp_sender_class, "<init>", "(J)V"); 1783 1784 std::string kind = JavaToStdString(jni, j_kind); 1785 std::string stream_id = JavaToStdString(jni, j_stream_id); 1786 rtc::scoped_refptr<RtpSenderInterface> sender = 1787 ExtractNativePC(jni, j_pc)->CreateSender(kind, stream_id); 1788 if (!sender.get()) { 1789 return nullptr; 1790 } 1791 jlong nativeSenderPtr = jlongFromPointer(sender.get()); 1792 jobject j_sender = 1793 jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr); 1794 CHECK_EXCEPTION(jni) << "error during NewObject"; 1795 // Sender is now owned by the Java object, and will be freed from 1796 // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders(). 1797 sender->AddRef(); 1798 return j_sender; 1799} 1800 1801JOW(jobject, PeerConnection_nativeGetSenders)(JNIEnv* jni, jobject j_pc) { 1802 jclass j_array_list_class = FindClass(jni, "java/util/ArrayList"); 1803 jmethodID j_array_list_ctor = 1804 GetMethodID(jni, j_array_list_class, "<init>", "()V"); 1805 jmethodID j_array_list_add = 1806 GetMethodID(jni, j_array_list_class, "add", "(Ljava/lang/Object;)Z"); 1807 jobject j_senders = jni->NewObject(j_array_list_class, j_array_list_ctor); 1808 CHECK_EXCEPTION(jni) << "error during NewObject"; 1809 1810 jclass j_rtp_sender_class = FindClass(jni, "org/webrtc/RtpSender"); 1811 jmethodID j_rtp_sender_ctor = 1812 GetMethodID(jni, j_rtp_sender_class, "<init>", "(J)V"); 1813 1814 auto senders = ExtractNativePC(jni, j_pc)->GetSenders(); 1815 for (const auto& sender : senders) { 1816 jlong nativeSenderPtr = jlongFromPointer(sender.get()); 1817 jobject j_sender = 1818 jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr); 1819 CHECK_EXCEPTION(jni) << "error during NewObject"; 1820 // Sender is now owned by the Java object, and will be freed from 1821 // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders(). 1822 sender->AddRef(); 1823 jni->CallBooleanMethod(j_senders, j_array_list_add, j_sender); 1824 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; 1825 } 1826 return j_senders; 1827} 1828 1829JOW(jobject, PeerConnection_nativeGetReceivers)(JNIEnv* jni, jobject j_pc) { 1830 jclass j_array_list_class = FindClass(jni, "java/util/ArrayList"); 1831 jmethodID j_array_list_ctor = 1832 GetMethodID(jni, j_array_list_class, "<init>", "()V"); 1833 jmethodID j_array_list_add = 1834 GetMethodID(jni, j_array_list_class, "add", "(Ljava/lang/Object;)Z"); 1835 jobject j_receivers = jni->NewObject(j_array_list_class, j_array_list_ctor); 1836 CHECK_EXCEPTION(jni) << "error during NewObject"; 1837 1838 jclass j_rtp_receiver_class = FindClass(jni, "org/webrtc/RtpReceiver"); 1839 jmethodID j_rtp_receiver_ctor = 1840 GetMethodID(jni, j_rtp_receiver_class, "<init>", "(J)V"); 1841 1842 auto receivers = ExtractNativePC(jni, j_pc)->GetReceivers(); 1843 for (const auto& receiver : receivers) { 1844 jlong nativeReceiverPtr = jlongFromPointer(receiver.get()); 1845 jobject j_receiver = jni->NewObject(j_rtp_receiver_class, 1846 j_rtp_receiver_ctor, nativeReceiverPtr); 1847 CHECK_EXCEPTION(jni) << "error during NewObject"; 1848 // Receiver is now owned by Java object, and will be freed from there. 1849 receiver->AddRef(); 1850 jni->CallBooleanMethod(j_receivers, j_array_list_add, j_receiver); 1851 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; 1852 } 1853 return j_receivers; 1854} 1855 1856JOW(bool, PeerConnection_nativeGetStats)( 1857 JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) { 1858 rtc::scoped_refptr<StatsObserverWrapper> observer( 1859 new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer)); 1860 return ExtractNativePC(jni, j_pc)->GetStats( 1861 observer, 1862 reinterpret_cast<MediaStreamTrackInterface*>(native_track), 1863 PeerConnectionInterface::kStatsOutputLevelStandard); 1864} 1865 1866JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) { 1867 PeerConnectionInterface::SignalingState state = 1868 ExtractNativePC(jni, j_pc)->signaling_state(); 1869 return JavaEnumFromIndex(jni, "PeerConnection$SignalingState", state); 1870} 1871 1872JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) { 1873 PeerConnectionInterface::IceConnectionState state = 1874 ExtractNativePC(jni, j_pc)->ice_connection_state(); 1875 return JavaEnumFromIndex(jni, "PeerConnection$IceConnectionState", state); 1876} 1877 1878JOW(jobject, PeerConnection_iceGatheringState)(JNIEnv* jni, jobject j_pc) { 1879 PeerConnectionInterface::IceGatheringState state = 1880 ExtractNativePC(jni, j_pc)->ice_gathering_state(); 1881 return JavaEnumFromIndex(jni, "PeerConnection$IceGatheringState", state); 1882} 1883 1884JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) { 1885 ExtractNativePC(jni, j_pc)->Close(); 1886 return; 1887} 1888 1889JOW(jobject, MediaSource_nativeState)(JNIEnv* jni, jclass, jlong j_p) { 1890 rtc::scoped_refptr<MediaSourceInterface> p( 1891 reinterpret_cast<MediaSourceInterface*>(j_p)); 1892 return JavaEnumFromIndex(jni, "MediaSource$State", p->state()); 1893} 1894 1895JOW(jobject, VideoCapturer_nativeCreateVideoCapturer)( 1896 JNIEnv* jni, jclass, jstring j_device_name) { 1897// Since we can't create platform specific java implementations in Java, we 1898// defer the creation to C land. 1899#if defined(ANDROID) 1900 // TODO(nisse): This case is intended to be deleted. 1901 jclass j_video_capturer_class( 1902 FindClass(jni, "org/webrtc/VideoCapturerAndroid")); 1903 const int camera_id = jni->CallStaticIntMethod( 1904 j_video_capturer_class, 1905 GetStaticMethodID(jni, j_video_capturer_class, "lookupDeviceName", 1906 "(Ljava/lang/String;)I"), 1907 j_device_name); 1908 CHECK_EXCEPTION(jni) << "error during VideoCapturerAndroid.lookupDeviceName"; 1909 if (camera_id == -1) 1910 return nullptr; 1911 jobject j_video_capturer = jni->NewObject( 1912 j_video_capturer_class, 1913 GetMethodID(jni, j_video_capturer_class, "<init>", "(I)V"), camera_id); 1914 CHECK_EXCEPTION(jni) << "error during creation of VideoCapturerAndroid"; 1915 jfieldID helper_fid = GetFieldID(jni, j_video_capturer_class, "surfaceHelper", 1916 "Lorg/webrtc/SurfaceTextureHelper;"); 1917 1918 rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate = 1919 new rtc::RefCountedObject<AndroidVideoCapturerJni>( 1920 jni, j_video_capturer, 1921 GetObjectField(jni, j_video_capturer, helper_fid)); 1922 rtc::scoped_ptr<cricket::VideoCapturer> capturer( 1923 new webrtc::AndroidVideoCapturer(delegate)); 1924 1925#else 1926 std::string device_name = JavaToStdString(jni, j_device_name); 1927 scoped_ptr<cricket::DeviceManagerInterface> device_manager( 1928 cricket::DeviceManagerFactory::Create()); 1929 RTC_CHECK(device_manager->Init()) << "DeviceManager::Init() failed"; 1930 cricket::Device device; 1931 if (!device_manager->GetVideoCaptureDevice(device_name, &device)) { 1932 LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name; 1933 return 0; 1934 } 1935 scoped_ptr<cricket::VideoCapturer> capturer( 1936 device_manager->CreateVideoCapturer(device)); 1937 1938 jclass j_video_capturer_class( 1939 FindClass(jni, "org/webrtc/VideoCapturer")); 1940 const jmethodID j_videocapturer_ctor(GetMethodID( 1941 jni, j_video_capturer_class, "<init>", "()V")); 1942 jobject j_video_capturer = 1943 jni->NewObject(j_video_capturer_class, 1944 j_videocapturer_ctor); 1945 CHECK_EXCEPTION(jni) << "error during creation of VideoCapturer"; 1946 1947#endif 1948 const jmethodID j_videocapturer_set_native_capturer(GetMethodID( 1949 jni, j_video_capturer_class, "setNativeCapturer", "(J)V")); 1950 jni->CallVoidMethod(j_video_capturer, 1951 j_videocapturer_set_native_capturer, 1952 jlongFromPointer(capturer.release())); 1953 CHECK_EXCEPTION(jni) << "error during setNativeCapturer"; 1954 return j_video_capturer; 1955} 1956 1957JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)( 1958 JNIEnv* jni, jclass, int x, int y) { 1959 scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create( 1960 cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y))); 1961 return (jlong)renderer.release(); 1962} 1963 1964JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)( 1965 JNIEnv* jni, jclass, jobject j_callbacks) { 1966 scoped_ptr<JavaVideoRendererWrapper> renderer( 1967 new JavaVideoRendererWrapper(jni, j_callbacks)); 1968 return (jlong)renderer.release(); 1969} 1970 1971JOW(void, VideoRenderer_nativeCopyPlane)( 1972 JNIEnv *jni, jclass, jobject j_src_buffer, jint width, jint height, 1973 jint src_stride, jobject j_dst_buffer, jint dst_stride) { 1974 size_t src_size = jni->GetDirectBufferCapacity(j_src_buffer); 1975 size_t dst_size = jni->GetDirectBufferCapacity(j_dst_buffer); 1976 RTC_CHECK(src_stride >= width) << "Wrong source stride " << src_stride; 1977 RTC_CHECK(dst_stride >= width) << "Wrong destination stride " << dst_stride; 1978 RTC_CHECK(src_size >= src_stride * height) 1979 << "Insufficient source buffer capacity " << src_size; 1980 RTC_CHECK(dst_size >= dst_stride * height) 1981 << "Isufficient destination buffer capacity " << dst_size; 1982 uint8_t *src = 1983 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_src_buffer)); 1984 uint8_t *dst = 1985 reinterpret_cast<uint8_t*>(jni->GetDirectBufferAddress(j_dst_buffer)); 1986 if (src_stride == dst_stride) { 1987 memcpy(dst, src, src_stride * height); 1988 } else { 1989 for (int i = 0; i < height; i++) { 1990 memcpy(dst, src, width); 1991 src += src_stride; 1992 dst += dst_stride; 1993 } 1994 } 1995} 1996 1997JOW(void, VideoSource_stop)(JNIEnv* jni, jclass, jlong j_p) { 1998 reinterpret_cast<VideoSourceInterface*>(j_p)->Stop(); 1999} 2000 2001JOW(void, VideoSource_restart)( 2002 JNIEnv* jni, jclass, jlong j_p_source, jlong j_p_format) { 2003 reinterpret_cast<VideoSourceInterface*>(j_p_source)->Restart(); 2004} 2005 2006JOW(jstring, MediaStreamTrack_nativeId)(JNIEnv* jni, jclass, jlong j_p) { 2007 return JavaStringFromStdString( 2008 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->id()); 2009} 2010 2011JOW(jstring, MediaStreamTrack_nativeKind)(JNIEnv* jni, jclass, jlong j_p) { 2012 return JavaStringFromStdString( 2013 jni, reinterpret_cast<MediaStreamTrackInterface*>(j_p)->kind()); 2014} 2015 2016JOW(jboolean, MediaStreamTrack_nativeEnabled)(JNIEnv* jni, jclass, jlong j_p) { 2017 return reinterpret_cast<MediaStreamTrackInterface*>(j_p)->enabled(); 2018} 2019 2020JOW(jobject, MediaStreamTrack_nativeState)(JNIEnv* jni, jclass, jlong j_p) { 2021 return JavaEnumFromIndex( 2022 jni, 2023 "MediaStreamTrack$State", 2024 reinterpret_cast<MediaStreamTrackInterface*>(j_p)->state()); 2025} 2026 2027JOW(jboolean, MediaStreamTrack_nativeSetState)( 2028 JNIEnv* jni, jclass, jlong j_p, jint j_new_state) { 2029 MediaStreamTrackInterface::TrackState new_state = 2030 (MediaStreamTrackInterface::TrackState)j_new_state; 2031 return reinterpret_cast<MediaStreamTrackInterface*>(j_p) 2032 ->set_state(new_state); 2033} 2034 2035JOW(jboolean, MediaStreamTrack_nativeSetEnabled)( 2036 JNIEnv* jni, jclass, jlong j_p, jboolean enabled) { 2037 return reinterpret_cast<MediaStreamTrackInterface*>(j_p) 2038 ->set_enabled(enabled); 2039} 2040 2041JOW(void, VideoTrack_nativeAddRenderer)( 2042 JNIEnv* jni, jclass, 2043 jlong j_video_track_pointer, jlong j_renderer_pointer) { 2044 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->AddRenderer( 2045 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer)); 2046} 2047 2048JOW(void, VideoTrack_nativeRemoveRenderer)( 2049 JNIEnv* jni, jclass, 2050 jlong j_video_track_pointer, jlong j_renderer_pointer) { 2051 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer( 2052 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer)); 2053} 2054 2055JOW(jlong, CallSessionFileRotatingLogSink_nativeAddSink)( 2056 JNIEnv* jni, jclass, 2057 jstring j_dirPath, jint j_maxFileSize, jint j_severity) { 2058 std::string dir_path = JavaToStdString(jni, j_dirPath); 2059 rtc::CallSessionFileRotatingLogSink* sink = 2060 new rtc::CallSessionFileRotatingLogSink(dir_path, j_maxFileSize); 2061 if (!sink->Init()) { 2062 LOG_V(rtc::LoggingSeverity::LS_WARNING) << 2063 "Failed to init CallSessionFileRotatingLogSink for path " << dir_path; 2064 delete sink; 2065 return 0; 2066 } 2067 rtc::LogMessage::AddLogToStream( 2068 sink, static_cast<rtc::LoggingSeverity>(j_severity)); 2069 return (jlong) sink; 2070} 2071 2072JOW(void, CallSessionFileRotatingLogSink_nativeDeleteSink)( 2073 JNIEnv* jni, jclass, jlong j_sink) { 2074 rtc::CallSessionFileRotatingLogSink* sink = 2075 reinterpret_cast<rtc::CallSessionFileRotatingLogSink*>(j_sink); 2076 rtc::LogMessage::RemoveLogToStream(sink); 2077 delete sink; 2078} 2079 2080JOW(jbyteArray, CallSessionFileRotatingLogSink_nativeGetLogData)( 2081 JNIEnv* jni, jclass, jstring j_dirPath) { 2082 std::string dir_path = JavaToStdString(jni, j_dirPath); 2083 rtc::scoped_ptr<rtc::CallSessionFileRotatingStream> stream( 2084 new rtc::CallSessionFileRotatingStream(dir_path)); 2085 if (!stream->Open()) { 2086 LOG_V(rtc::LoggingSeverity::LS_WARNING) << 2087 "Failed to open CallSessionFileRotatingStream for path " << dir_path; 2088 return jni->NewByteArray(0); 2089 } 2090 size_t log_size = 0; 2091 if (!stream->GetSize(&log_size) || log_size == 0) { 2092 LOG_V(rtc::LoggingSeverity::LS_WARNING) << 2093 "CallSessionFileRotatingStream returns 0 size for path " << dir_path; 2094 return jni->NewByteArray(0); 2095 } 2096 2097 size_t read = 0; 2098 rtc::scoped_ptr<jbyte> buffer(static_cast<jbyte*>(malloc(log_size))); 2099 stream->ReadAll(buffer.get(), log_size, &read, nullptr); 2100 2101 jbyteArray result = jni->NewByteArray(read); 2102 jni->SetByteArrayRegion(result, 0, read, buffer.get()); 2103 2104 return result; 2105} 2106 2107JOW(jboolean, RtpSender_nativeSetTrack)(JNIEnv* jni, 2108 jclass, 2109 jlong j_rtp_sender_pointer, 2110 jlong j_track_pointer) { 2111 return reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer) 2112 ->SetTrack(reinterpret_cast<MediaStreamTrackInterface*>(j_track_pointer)); 2113} 2114 2115JOW(jlong, RtpSender_nativeGetTrack)(JNIEnv* jni, 2116 jclass, 2117 jlong j_rtp_sender_pointer, 2118 jlong j_track_pointer) { 2119 return jlongFromPointer( 2120 reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer) 2121 ->track() 2122 .release()); 2123} 2124 2125JOW(jstring, RtpSender_nativeId)( 2126 JNIEnv* jni, jclass, jlong j_rtp_sender_pointer) { 2127 return JavaStringFromStdString( 2128 jni, reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)->id()); 2129} 2130 2131JOW(void, RtpSender_free)(JNIEnv* jni, jclass, jlong j_rtp_sender_pointer) { 2132 reinterpret_cast<RtpSenderInterface*>(j_rtp_sender_pointer)->Release(); 2133} 2134 2135JOW(jlong, RtpReceiver_nativeGetTrack)(JNIEnv* jni, 2136 jclass, 2137 jlong j_rtp_receiver_pointer, 2138 jlong j_track_pointer) { 2139 return jlongFromPointer( 2140 reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer) 2141 ->track() 2142 .release()); 2143} 2144 2145JOW(jstring, RtpReceiver_nativeId)( 2146 JNIEnv* jni, jclass, jlong j_rtp_receiver_pointer) { 2147 return JavaStringFromStdString( 2148 jni, 2149 reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)->id()); 2150} 2151 2152JOW(void, RtpReceiver_free)(JNIEnv* jni, jclass, jlong j_rtp_receiver_pointer) { 2153 reinterpret_cast<RtpReceiverInterface*>(j_rtp_receiver_pointer)->Release(); 2154} 2155 2156} // namespace webrtc_jni 2157