| /* |
| * Copyright 2017 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "api/peerconnectioninterface.h" |
| #include "media/base/mediaengine.h" |
| #include "modules/utility/include/jvm_android.h" |
| // We don't depend on the audio processing module implementation. |
| // The user may pass in a nullptr. |
| #include "modules/audio_processing/include/audio_processing.h" // nogncheck |
| #include "rtc_base/event_tracer.h" |
| #include "rtc_base/stringutils.h" |
| #include "rtc_base/thread.h" |
| #include "sdk/android/src/jni/jni_helpers.h" |
| #include "sdk/android/src/jni/pc/androidnetworkmonitor_jni.h" |
| #include "sdk/android/src/jni/pc/audio_jni.h" |
| #include "sdk/android/src/jni/pc/java_native_conversion.h" |
| #include "sdk/android/src/jni/pc/media_jni.h" |
| #include "sdk/android/src/jni/pc/ownedfactoryandthreads.h" |
| #include "sdk/android/src/jni/pc/peerconnectionobserver_jni.h" |
| #include "sdk/android/src/jni/pc/video_jni.h" |
| #include "system_wrappers/include/field_trial.h" |
| // Adding 'nogncheck' to disable the gn include headers check. |
| // We don't want to depend on 'system_wrappers:field_trial_default' because |
| // clients should be able to provide their own implementation. |
| #include "system_wrappers/include/field_trial_default.h" // nogncheck |
| |
| namespace webrtc { |
| namespace jni { |
| |
| // Note: Some of the video-specific PeerConnectionFactory methods are |
| // implemented in "video_jni.cc". This is done so that if an application |
| // doesn't need video support, it can just link with "null_video_jni.cc" |
| // instead of "video_jni.cc", which doesn't bring in the video-specific |
| // dependencies. |
| |
| // Field trials initialization string |
| static char* field_trials_init_string = nullptr; |
| |
| // Set in PeerConnectionFactory_initializeAndroidGlobals(). |
| static bool factory_static_initialized = false; |
| static bool video_hw_acceleration_enabled = true; |
| |
| JNI_FUNCTION_DECLARATION(jlong, |
| PeerConnectionFactory_nativeCreateObserver, |
| JNIEnv* jni, |
| jclass, |
| jobject j_observer) { |
| return (jlong) new PeerConnectionObserverJni(jni, j_observer); |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_nativeInitializeAndroidGlobals, |
| JNIEnv* jni, |
| jclass, |
| jobject context, |
| jboolean video_hw_acceleration) { |
| video_hw_acceleration_enabled = video_hw_acceleration; |
| if (!factory_static_initialized) { |
| JVM::Initialize(GetJVM()); |
| factory_static_initialized = true; |
| } |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_initializeFieldTrials, |
| JNIEnv* jni, |
| jclass, |
| jstring j_trials_init_string) { |
| field_trials_init_string = NULL; |
| if (j_trials_init_string != NULL) { |
| const char* init_string = |
| jni->GetStringUTFChars(j_trials_init_string, NULL); |
| int init_string_length = jni->GetStringUTFLength(j_trials_init_string); |
| field_trials_init_string = new char[init_string_length + 1]; |
| rtc::strcpyn(field_trials_init_string, init_string_length + 1, init_string); |
| jni->ReleaseStringUTFChars(j_trials_init_string, init_string); |
| LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string; |
| } |
| field_trial::InitFieldTrialsFromString(field_trials_init_string); |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_initializeInternalTracer, |
| JNIEnv* jni, |
| jclass) { |
| rtc::tracing::SetupInternalTracer(); |
| } |
| |
| JNI_FUNCTION_DECLARATION(jstring, |
| PeerConnectionFactory_nativeFieldTrialsFindFullName, |
| JNIEnv* jni, |
| jclass, |
| jstring j_name) { |
| return JavaStringFromStdString( |
| jni, field_trial::FindFullName(JavaToStdString(jni, j_name))); |
| } |
| |
| JNI_FUNCTION_DECLARATION(jboolean, |
| PeerConnectionFactory_startInternalTracingCapture, |
| JNIEnv* jni, |
| jclass, |
| jstring j_event_tracing_filename) { |
| if (!j_event_tracing_filename) |
| return false; |
| |
| const char* init_string = |
| jni->GetStringUTFChars(j_event_tracing_filename, NULL); |
| LOG(LS_INFO) << "Starting internal tracing to: " << init_string; |
| bool ret = rtc::tracing::StartInternalCapture(init_string); |
| jni->ReleaseStringUTFChars(j_event_tracing_filename, init_string); |
| return ret; |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_stopInternalTracingCapture, |
| JNIEnv* jni, |
| jclass) { |
| rtc::tracing::StopInternalCapture(); |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_shutdownInternalTracer, |
| JNIEnv* jni, |
| jclass) { |
| rtc::tracing::ShutdownInternalTracer(); |
| } |
| |
| jlong CreatePeerConnectionFactoryForJava( |
| JNIEnv* jni, |
| jobject joptions, |
| jobject jencoder_factory, |
| jobject jdecoder_factory, |
| rtc::scoped_refptr<AudioProcessing> audio_processor) { |
| // talk/ assumes pretty widely that the current Thread is ThreadManager'd, but |
| // ThreadManager only WrapCurrentThread()s the thread where it is first |
| // created. Since the semantics around when auto-wrapping happens in |
| // webrtc/rtc_base/ are convoluted, we simply wrap here to avoid having to |
| // think about ramifications of auto-wrapping there. |
| rtc::ThreadManager::Instance()->WrapCurrentThread(); |
| |
| std::unique_ptr<rtc::Thread> network_thread = |
| rtc::Thread::CreateWithSocketServer(); |
| network_thread->SetName("network_thread", nullptr); |
| RTC_CHECK(network_thread->Start()) << "Failed to start thread"; |
| |
| std::unique_ptr<rtc::Thread> worker_thread = rtc::Thread::Create(); |
| worker_thread->SetName("worker_thread", nullptr); |
| RTC_CHECK(worker_thread->Start()) << "Failed to start thread"; |
| |
| std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create(); |
| signaling_thread->SetName("signaling_thread", NULL); |
| RTC_CHECK(signaling_thread->Start()) << "Failed to start thread"; |
| |
| cricket::WebRtcVideoEncoderFactory* video_encoder_factory = nullptr; |
| cricket::WebRtcVideoDecoderFactory* video_decoder_factory = nullptr; |
| rtc::NetworkMonitorFactory* network_monitor_factory = nullptr; |
| auto audio_encoder_factory = CreateAudioEncoderFactory(); |
| auto audio_decoder_factory = CreateAudioDecoderFactory(); |
| |
| PeerConnectionFactoryInterface::Options options; |
| bool has_options = joptions != NULL; |
| if (has_options) { |
| options = JavaToNativePeerConnectionFactoryOptions(jni, joptions); |
| } |
| |
| if (video_hw_acceleration_enabled) { |
| video_encoder_factory = CreateVideoEncoderFactory(jni, jencoder_factory); |
| video_decoder_factory = CreateVideoDecoderFactory(jni, jdecoder_factory); |
| } |
| // Do not create network_monitor_factory only if the options are |
| // provided and disable_network_monitor therein is set to true. |
| if (!(has_options && options.disable_network_monitor)) { |
| network_monitor_factory = new AndroidNetworkMonitorFactory(); |
| rtc::NetworkMonitorFactory::SetFactory(network_monitor_factory); |
| } |
| |
| AudioDeviceModule* adm = nullptr; |
| rtc::scoped_refptr<AudioMixer> audio_mixer = nullptr; |
| std::unique_ptr<CallFactoryInterface> call_factory(CreateCallFactory()); |
| std::unique_ptr<RtcEventLogFactoryInterface> rtc_event_log_factory( |
| CreateRtcEventLogFactory()); |
| std::unique_ptr<cricket::MediaEngineInterface> media_engine(CreateMediaEngine( |
| adm, audio_encoder_factory, audio_decoder_factory, video_encoder_factory, |
| video_decoder_factory, audio_mixer, audio_processor)); |
| |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( |
| CreateModularPeerConnectionFactory( |
| network_thread.get(), worker_thread.get(), signaling_thread.get(), |
| std::move(media_engine), std::move(call_factory), |
| std::move(rtc_event_log_factory))); |
| RTC_CHECK(factory) << "Failed to create the peer connection factory; " |
| << "WebRTC/libjingle init likely failed on this device"; |
| // TODO(honghaiz): Maybe put the options as the argument of |
| // CreatePeerConnectionFactory. |
| if (has_options) { |
| factory->SetOptions(options); |
| } |
| OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads( |
| std::move(network_thread), std::move(worker_thread), |
| std::move(signaling_thread), video_encoder_factory, video_decoder_factory, |
| network_monitor_factory, factory.release()); |
| owned_factory->InvokeJavaCallbacksOnFactoryThreads(); |
| return jlongFromPointer(owned_factory); |
| } |
| |
| JNI_FUNCTION_DECLARATION( |
| jlong, |
| PeerConnectionFactory_nativeCreatePeerConnectionFactory, |
| JNIEnv* jni, |
| jclass, |
| jobject joptions, |
| jobject jencoder_factory, |
| jobject jdecoder_factory) { |
| return CreatePeerConnectionFactoryForJava(jni, joptions, jencoder_factory, |
| jdecoder_factory, |
| CreateAudioProcessing()); |
| } |
| |
| JNI_FUNCTION_DECLARATION( |
| jlong, |
| PeerConnectionFactory_nativeCreatePeerConnectionFactoryWithAudioProcessing, |
| JNIEnv* jni, |
| jclass, |
| jobject joptions, |
| jobject jencoder_factory, |
| jobject jdecoder_factory, |
| jlong native_audio_processor) { |
| rtc::scoped_refptr<AudioProcessing> audio_processor = |
| reinterpret_cast<AudioProcessing*>(native_audio_processor); |
| RTC_DCHECK(audio_processor); |
| return CreatePeerConnectionFactoryForJava(jni, joptions, jencoder_factory, |
| jdecoder_factory, audio_processor); |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_nativeFreeFactory, |
| JNIEnv*, |
| jclass, |
| jlong j_p) { |
| delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p); |
| if (field_trials_init_string) { |
| field_trial::InitFieldTrialsFromString(NULL); |
| delete field_trials_init_string; |
| field_trials_init_string = NULL; |
| } |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_nativeThreadsCallbacks, |
| JNIEnv*, |
| jclass, |
| jlong j_p) { |
| OwnedFactoryAndThreads* factory = |
| reinterpret_cast<OwnedFactoryAndThreads*>(j_p); |
| factory->InvokeJavaCallbacksOnFactoryThreads(); |
| } |
| |
| JNI_FUNCTION_DECLARATION(jlong, |
| PeerConnectionFactory_nativeCreateLocalMediaStream, |
| JNIEnv* jni, |
| jclass, |
| jlong native_factory, |
| jstring label) { |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( |
| factoryFromJava(native_factory)); |
| rtc::scoped_refptr<MediaStreamInterface> stream( |
| factory->CreateLocalMediaStream(JavaToStdString(jni, label))); |
| return (jlong)stream.release(); |
| } |
| |
| JNI_FUNCTION_DECLARATION(jlong, |
| PeerConnectionFactory_nativeCreateAudioSource, |
| JNIEnv* jni, |
| jclass, |
| jlong native_factory, |
| jobject j_constraints) { |
| std::unique_ptr<MediaConstraintsJni> constraints( |
| new MediaConstraintsJni(jni, j_constraints)); |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( |
| factoryFromJava(native_factory)); |
| cricket::AudioOptions options; |
| CopyConstraintsIntoAudioOptions(constraints.get(), &options); |
| rtc::scoped_refptr<AudioSourceInterface> source( |
| factory->CreateAudioSource(options)); |
| return (jlong)source.release(); |
| } |
| |
| JNI_FUNCTION_DECLARATION(jlong, |
| PeerConnectionFactory_nativeCreateAudioTrack, |
| JNIEnv* jni, |
| jclass, |
| jlong native_factory, |
| jstring id, |
| jlong native_source) { |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( |
| factoryFromJava(native_factory)); |
| rtc::scoped_refptr<AudioTrackInterface> track(factory->CreateAudioTrack( |
| JavaToStdString(jni, id), |
| reinterpret_cast<AudioSourceInterface*>(native_source))); |
| return (jlong)track.release(); |
| } |
| |
| JNI_FUNCTION_DECLARATION(jboolean, |
| PeerConnectionFactory_nativeStartAecDump, |
| JNIEnv* jni, |
| jclass, |
| jlong native_factory, |
| jint file, |
| jint filesize_limit_bytes) { |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( |
| factoryFromJava(native_factory)); |
| return factory->StartAecDump(file, filesize_limit_bytes); |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_nativeStopAecDump, |
| JNIEnv* jni, |
| jclass, |
| jlong native_factory) { |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( |
| factoryFromJava(native_factory)); |
| factory->StopAecDump(); |
| } |
| |
| JNI_FUNCTION_DECLARATION(void, |
| PeerConnectionFactory_nativeSetOptions, |
| JNIEnv* jni, |
| jclass, |
| jlong native_factory, |
| jobject options) { |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory( |
| factoryFromJava(native_factory)); |
| PeerConnectionFactoryInterface::Options options_to_set = |
| JavaToNativePeerConnectionFactoryOptions(jni, options); |
| factory->SetOptions(options_to_set); |
| |
| if (options_to_set.disable_network_monitor) { |
| OwnedFactoryAndThreads* owner = |
| reinterpret_cast<OwnedFactoryAndThreads*>(native_factory); |
| if (owner->network_monitor_factory()) { |
| rtc::NetworkMonitorFactory::ReleaseFactory( |
| owner->network_monitor_factory()); |
| owner->clear_network_monitor_factory(); |
| } |
| } |
| } |
| |
| JNI_FUNCTION_DECLARATION(jlong, |
| PeerConnectionFactory_nativeCreatePeerConnection, |
| JNIEnv* jni, |
| jclass, |
| jlong factory, |
| jobject j_rtc_config, |
| jobject j_constraints, |
| jlong observer_p) { |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> f( |
| reinterpret_cast<PeerConnectionFactoryInterface*>( |
| factoryFromJava(factory))); |
| |
| PeerConnectionInterface::RTCConfiguration rtc_config( |
| PeerConnectionInterface::RTCConfigurationType::kAggressive); |
| JavaToNativeRTCConfiguration(jni, j_rtc_config, &rtc_config); |
| |
| jclass j_rtc_config_class = GetObjectClass(jni, j_rtc_config); |
| jfieldID j_key_type_id = GetFieldID(jni, j_rtc_config_class, "keyType", |
| "Lorg/webrtc/PeerConnection$KeyType;"); |
| jobject j_key_type = GetObjectField(jni, j_rtc_config, j_key_type_id); |
| |
| // Generate non-default certificate. |
| rtc::KeyType key_type = JavaToNativeKeyType(jni, j_key_type); |
| if (key_type != rtc::KT_DEFAULT) { |
| rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
| rtc::RTCCertificateGenerator::GenerateCertificate( |
| rtc::KeyParams(key_type), rtc::Optional<uint64_t>()); |
| if (!certificate) { |
| LOG(LS_ERROR) << "Failed to generate certificate. KeyType: " << key_type; |
| return 0; |
| } |
| rtc_config.certificates.push_back(certificate); |
| } |
| |
| PeerConnectionObserverJni* observer = |
| reinterpret_cast<PeerConnectionObserverJni*>(observer_p); |
| observer->SetConstraints(new MediaConstraintsJni(jni, j_constraints)); |
| CopyConstraintsIntoRtcConfiguration(observer->constraints(), &rtc_config); |
| rtc::scoped_refptr<PeerConnectionInterface> pc( |
| f->CreatePeerConnection(rtc_config, nullptr, nullptr, observer)); |
| return (jlong)pc.release(); |
| } |
| |
| } // namespace jni |
| } // namespace webrtc |