| /* |
| * 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 "sdk/android/src/jni/pc/peer_connection_factory.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "absl/memory/memory.h" |
| #include "api/video_codecs/video_decoder_factory.h" |
| #include "api/video_codecs/video_encoder_factory.h" |
| #include "media/base/media_engine.h" |
| #include "modules/audio_device/include/audio_device.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 "api/call/call_factory_interface.h" |
| #include "api/rtc_event_log/rtc_event_log_factory.h" |
| #include "api/task_queue/default_task_queue_factory.h" |
| #include "api/video_codecs/video_decoder_factory.h" |
| #include "api/video_codecs/video_encoder_factory.h" |
| #include "media/engine/webrtc_media_engine.h" |
| #include "modules/audio_device/include/audio_device.h" |
| #include "modules/audio_processing/include/audio_processing.h" |
| #include "rtc_base/event_tracer.h" |
| #include "rtc_base/physical_socket_server.h" |
| #include "rtc_base/thread.h" |
| #include "sdk/android/generated_peerconnection_jni/PeerConnectionFactory_jni.h" |
| #include "sdk/android/native_api/jni/java_types.h" |
| #include "sdk/android/native_api/stacktrace/stacktrace.h" |
| #include "sdk/android/src/jni/jni_helpers.h" |
| #include "sdk/android/src/jni/logging/log_sink.h" |
| #include "sdk/android/src/jni/pc/android_network_monitor.h" |
| #include "sdk/android/src/jni/pc/audio.h" |
| #include "sdk/android/src/jni/pc/ice_candidate.h" |
| #include "sdk/android/src/jni/pc/media_stream_track.h" |
| #include "sdk/android/src/jni/pc/owned_factory_and_threads.h" |
| #include "sdk/android/src/jni/pc/peer_connection.h" |
| #include "sdk/android/src/jni/pc/rtp_capabilities.h" |
| #include "sdk/android/src/jni/pc/ssl_certificate_verifier_wrapper.h" |
| #include "sdk/android/src/jni/pc/video.h" |
| #include "system_wrappers/include/field_trial.h" |
| |
| namespace webrtc { |
| namespace jni { |
| |
| namespace { |
| |
| // Take ownership of the jlong reference and cast it into an rtc::scoped_refptr. |
| template <typename T> |
| rtc::scoped_refptr<T> TakeOwnershipOfRefPtr(jlong j_pointer) { |
| T* ptr = reinterpret_cast<T*>(j_pointer); |
| rtc::scoped_refptr<T> refptr; |
| refptr.swap(&ptr); |
| return refptr; |
| } |
| |
| // Take ownership of the jlong reference and cast it into a std::unique_ptr. |
| template <typename T> |
| std::unique_ptr<T> TakeOwnershipOfUniquePtr(jlong native_pointer) { |
| return std::unique_ptr<T>(reinterpret_cast<T*>(native_pointer)); |
| } |
| |
| typedef void (*JavaMethodPointer)(JNIEnv*, const JavaRef<jobject>&); |
| |
| // Post a message on the given thread that will call the Java method on the |
| // given Java object. |
| void PostJavaCallback(JNIEnv* env, |
| rtc::Thread* queue, |
| const JavaRef<jobject>& j_object, |
| JavaMethodPointer java_method_pointer) { |
| ScopedJavaGlobalRef<jobject> object(env, j_object); |
| queue->PostTask([object = std::move(object), java_method_pointer] { |
| java_method_pointer(AttachCurrentThreadIfNeeded(), object); |
| }); |
| } |
| |
| absl::optional<PeerConnectionFactoryInterface::Options> |
| JavaToNativePeerConnectionFactoryOptions(JNIEnv* jni, |
| const JavaRef<jobject>& j_options) { |
| if (j_options.is_null()) |
| return absl::nullopt; |
| |
| PeerConnectionFactoryInterface::Options native_options; |
| |
| // This doesn't necessarily match the c++ version of this struct; feel free |
| // to add more parameters as necessary. |
| native_options.network_ignore_mask = |
| Java_Options_getNetworkIgnoreMask(jni, j_options); |
| native_options.disable_encryption = |
| Java_Options_getDisableEncryption(jni, j_options); |
| native_options.disable_network_monitor = |
| Java_Options_getDisableNetworkMonitor(jni, j_options); |
| |
| return native_options; |
| } |
| |
| // Place static objects into a container that gets leaked so we avoid |
| // non-trivial destructor. |
| struct StaticObjectContainer { |
| // Field trials initialization string |
| std::unique_ptr<std::string> field_trials_init_string; |
| // Set in PeerConnectionFactory_InjectLoggable(). |
| std::unique_ptr<JNILogSink> jni_log_sink; |
| }; |
| |
| StaticObjectContainer& GetStaticObjects() { |
| static StaticObjectContainer* static_objects = new StaticObjectContainer(); |
| return *static_objects; |
| } |
| |
| ScopedJavaLocalRef<jobject> NativeToScopedJavaPeerConnectionFactory( |
| JNIEnv* env, |
| rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pcf, |
| std::unique_ptr<rtc::SocketFactory> socket_factory, |
| std::unique_ptr<rtc::Thread> network_thread, |
| std::unique_ptr<rtc::Thread> worker_thread, |
| std::unique_ptr<rtc::Thread> signaling_thread) { |
| OwnedFactoryAndThreads* owned_factory = new OwnedFactoryAndThreads( |
| std::move(socket_factory), std::move(network_thread), |
| std::move(worker_thread), std::move(signaling_thread), pcf); |
| |
| ScopedJavaLocalRef<jobject> j_pcf = Java_PeerConnectionFactory_Constructor( |
| env, NativeToJavaPointer(owned_factory)); |
| |
| PostJavaCallback(env, owned_factory->network_thread(), j_pcf, |
| &Java_PeerConnectionFactory_onNetworkThreadReady); |
| PostJavaCallback(env, owned_factory->worker_thread(), j_pcf, |
| &Java_PeerConnectionFactory_onWorkerThreadReady); |
| PostJavaCallback(env, owned_factory->signaling_thread(), j_pcf, |
| &Java_PeerConnectionFactory_onSignalingThreadReady); |
| |
| return j_pcf; |
| } |
| |
| PeerConnectionFactoryInterface* PeerConnectionFactoryFromJava(jlong j_p) { |
| return reinterpret_cast<OwnedFactoryAndThreads*>(j_p)->factory(); |
| } |
| |
| } // namespace |
| |
| // Note: Some of the video-specific PeerConnectionFactory methods are |
| // implemented in "video.cc". This is done so that if an application |
| // doesn't need video support, it can just link with "null_video.cc" |
| // instead of "video.cc", which doesn't bring in the video-specific |
| // dependencies. |
| |
| // Set in PeerConnectionFactory_initializeAndroidGlobals(). |
| static bool factory_static_initialized = false; |
| |
| jobject NativeToJavaPeerConnectionFactory( |
| JNIEnv* jni, |
| rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pcf, |
| std::unique_ptr<rtc::SocketFactory> socket_factory, |
| std::unique_ptr<rtc::Thread> network_thread, |
| std::unique_ptr<rtc::Thread> worker_thread, |
| std::unique_ptr<rtc::Thread> signaling_thread) { |
| return NativeToScopedJavaPeerConnectionFactory( |
| jni, pcf, std::move(socket_factory), std::move(network_thread), |
| std::move(worker_thread), std::move(signaling_thread)) |
| .Release(); |
| } |
| |
| static void JNI_PeerConnectionFactory_InitializeAndroidGlobals(JNIEnv* jni) { |
| if (!factory_static_initialized) { |
| JVM::Initialize(GetJVM()); |
| factory_static_initialized = true; |
| } |
| } |
| |
| static void JNI_PeerConnectionFactory_InitializeFieldTrials( |
| JNIEnv* jni, |
| const JavaParamRef<jstring>& j_trials_init_string) { |
| std::unique_ptr<std::string>& field_trials_init_string = |
| GetStaticObjects().field_trials_init_string; |
| |
| if (j_trials_init_string.is_null()) { |
| field_trials_init_string = nullptr; |
| field_trial::InitFieldTrialsFromString(nullptr); |
| return; |
| } |
| field_trials_init_string = std::make_unique<std::string>( |
| JavaToNativeString(jni, j_trials_init_string)); |
| RTC_LOG(LS_INFO) << "initializeFieldTrials: " << *field_trials_init_string; |
| field_trial::InitFieldTrialsFromString(field_trials_init_string->c_str()); |
| } |
| |
| static void JNI_PeerConnectionFactory_InitializeInternalTracer(JNIEnv* jni) { |
| rtc::tracing::SetupInternalTracer(); |
| } |
| |
| static ScopedJavaLocalRef<jstring> |
| JNI_PeerConnectionFactory_FindFieldTrialsFullName( |
| JNIEnv* jni, |
| const JavaParamRef<jstring>& j_name) { |
| return NativeToJavaString( |
| jni, field_trial::FindFullName(JavaToStdString(jni, j_name))); |
| } |
| |
| static jboolean JNI_PeerConnectionFactory_StartInternalTracingCapture( |
| JNIEnv* jni, |
| const JavaParamRef<jstring>& j_event_tracing_filename) { |
| if (j_event_tracing_filename.is_null()) |
| return false; |
| |
| const char* init_string = |
| jni->GetStringUTFChars(j_event_tracing_filename.obj(), NULL); |
| RTC_LOG(LS_INFO) << "Starting internal tracing to: " << init_string; |
| bool ret = rtc::tracing::StartInternalCapture(init_string); |
| jni->ReleaseStringUTFChars(j_event_tracing_filename.obj(), init_string); |
| return ret; |
| } |
| |
| static void JNI_PeerConnectionFactory_StopInternalTracingCapture(JNIEnv* jni) { |
| rtc::tracing::StopInternalCapture(); |
| } |
| |
| static void JNI_PeerConnectionFactory_ShutdownInternalTracer(JNIEnv* jni) { |
| rtc::tracing::ShutdownInternalTracer(); |
| } |
| |
| // Following parameters are optional: |
| // `audio_device_module`, `jencoder_factory`, `jdecoder_factory`, |
| // `audio_processor`, `fec_controller_factory`, |
| // `network_state_predictor_factory`, `neteq_factory`. |
| ScopedJavaLocalRef<jobject> CreatePeerConnectionFactoryForJava( |
| JNIEnv* jni, |
| const JavaParamRef<jobject>& jcontext, |
| const JavaParamRef<jobject>& joptions, |
| rtc::scoped_refptr<AudioDeviceModule> audio_device_module, |
| rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, |
| rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, |
| const JavaParamRef<jobject>& jencoder_factory, |
| const JavaParamRef<jobject>& jdecoder_factory, |
| rtc::scoped_refptr<AudioProcessing> audio_processor, |
| std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory, |
| std::unique_ptr<NetworkControllerFactoryInterface> |
| network_controller_factory, |
| std::unique_ptr<NetworkStatePredictorFactoryInterface> |
| network_state_predictor_factory, |
| std::unique_ptr<NetEqFactory> neteq_factory) { |
| // 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(); |
| |
| auto socket_server = std::make_unique<rtc::PhysicalSocketServer>(); |
| auto network_thread = std::make_unique<rtc::Thread>(socket_server.get()); |
| 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"; |
| |
| const absl::optional<PeerConnectionFactoryInterface::Options> options = |
| JavaToNativePeerConnectionFactoryOptions(jni, joptions); |
| |
| PeerConnectionFactoryDependencies dependencies; |
| // TODO(bugs.webrtc.org/13145): Also add socket_server.get() to the |
| // dependencies. |
| dependencies.network_thread = network_thread.get(); |
| dependencies.worker_thread = worker_thread.get(); |
| dependencies.signaling_thread = signaling_thread.get(); |
| dependencies.task_queue_factory = CreateDefaultTaskQueueFactory(); |
| dependencies.call_factory = CreateCallFactory(); |
| dependencies.event_log_factory = std::make_unique<RtcEventLogFactory>( |
| dependencies.task_queue_factory.get()); |
| dependencies.fec_controller_factory = std::move(fec_controller_factory); |
| dependencies.network_controller_factory = |
| std::move(network_controller_factory); |
| dependencies.network_state_predictor_factory = |
| std::move(network_state_predictor_factory); |
| dependencies.neteq_factory = std::move(neteq_factory); |
| if (!(options && options->disable_network_monitor)) { |
| dependencies.network_monitor_factory = |
| std::make_unique<AndroidNetworkMonitorFactory>(); |
| } |
| |
| cricket::MediaEngineDependencies media_dependencies; |
| media_dependencies.task_queue_factory = dependencies.task_queue_factory.get(); |
| media_dependencies.adm = std::move(audio_device_module); |
| media_dependencies.audio_encoder_factory = std::move(audio_encoder_factory); |
| media_dependencies.audio_decoder_factory = std::move(audio_decoder_factory); |
| media_dependencies.audio_processing = std::move(audio_processor); |
| media_dependencies.video_encoder_factory = |
| absl::WrapUnique(CreateVideoEncoderFactory(jni, jencoder_factory)); |
| media_dependencies.video_decoder_factory = |
| absl::WrapUnique(CreateVideoDecoderFactory(jni, jdecoder_factory)); |
| dependencies.media_engine = |
| cricket::CreateMediaEngine(std::move(media_dependencies)); |
| |
| rtc::scoped_refptr<PeerConnectionFactoryInterface> factory = |
| CreateModularPeerConnectionFactory(std::move(dependencies)); |
| |
| 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 (options) |
| factory->SetOptions(*options); |
| |
| return NativeToScopedJavaPeerConnectionFactory( |
| jni, factory, std::move(socket_server), std::move(network_thread), |
| std::move(worker_thread), std::move(signaling_thread)); |
| } |
| |
| static ScopedJavaLocalRef<jobject> |
| JNI_PeerConnectionFactory_CreatePeerConnectionFactory( |
| JNIEnv* jni, |
| const JavaParamRef<jobject>& jcontext, |
| const JavaParamRef<jobject>& joptions, |
| jlong native_audio_device_module, |
| jlong native_audio_encoder_factory, |
| jlong native_audio_decoder_factory, |
| const JavaParamRef<jobject>& jencoder_factory, |
| const JavaParamRef<jobject>& jdecoder_factory, |
| jlong native_audio_processor, |
| jlong native_fec_controller_factory, |
| jlong native_network_controller_factory, |
| jlong native_network_state_predictor_factory, |
| jlong native_neteq_factory) { |
| rtc::scoped_refptr<AudioProcessing> audio_processor( |
| reinterpret_cast<AudioProcessing*>(native_audio_processor)); |
| return CreatePeerConnectionFactoryForJava( |
| jni, jcontext, joptions, |
| rtc::scoped_refptr<AudioDeviceModule>( |
| reinterpret_cast<AudioDeviceModule*>(native_audio_device_module)), |
| TakeOwnershipOfRefPtr<AudioEncoderFactory>(native_audio_encoder_factory), |
| TakeOwnershipOfRefPtr<AudioDecoderFactory>(native_audio_decoder_factory), |
| jencoder_factory, jdecoder_factory, |
| audio_processor ? audio_processor : CreateAudioProcessing(), |
| TakeOwnershipOfUniquePtr<FecControllerFactoryInterface>( |
| native_fec_controller_factory), |
| TakeOwnershipOfUniquePtr<NetworkControllerFactoryInterface>( |
| native_network_controller_factory), |
| TakeOwnershipOfUniquePtr<NetworkStatePredictorFactoryInterface>( |
| native_network_state_predictor_factory), |
| TakeOwnershipOfUniquePtr<NetEqFactory>(native_neteq_factory)); |
| } |
| |
| static void JNI_PeerConnectionFactory_FreeFactory(JNIEnv*, jlong j_p) { |
| delete reinterpret_cast<OwnedFactoryAndThreads*>(j_p); |
| field_trial::InitFieldTrialsFromString(nullptr); |
| GetStaticObjects().field_trials_init_string = nullptr; |
| } |
| |
| static jlong JNI_PeerConnectionFactory_CreateLocalMediaStream( |
| JNIEnv* jni, |
| jlong native_factory, |
| const JavaParamRef<jstring>& label) { |
| rtc::scoped_refptr<MediaStreamInterface> stream( |
| PeerConnectionFactoryFromJava(native_factory) |
| ->CreateLocalMediaStream(JavaToStdString(jni, label))); |
| return jlongFromPointer(stream.release()); |
| } |
| |
| static jlong JNI_PeerConnectionFactory_CreateAudioSource( |
| JNIEnv* jni, |
| jlong native_factory, |
| const JavaParamRef<jobject>& j_constraints) { |
| std::unique_ptr<MediaConstraints> constraints = |
| JavaToNativeMediaConstraints(jni, j_constraints); |
| cricket::AudioOptions options; |
| CopyConstraintsIntoAudioOptions(constraints.get(), &options); |
| rtc::scoped_refptr<AudioSourceInterface> source( |
| PeerConnectionFactoryFromJava(native_factory) |
| ->CreateAudioSource(options)); |
| return jlongFromPointer(source.release()); |
| } |
| |
| jlong JNI_PeerConnectionFactory_CreateAudioTrack( |
| JNIEnv* jni, |
| jlong native_factory, |
| const JavaParamRef<jstring>& id, |
| jlong native_source) { |
| rtc::scoped_refptr<AudioTrackInterface> track( |
| PeerConnectionFactoryFromJava(native_factory) |
| ->CreateAudioTrack( |
| JavaToStdString(jni, id), |
| reinterpret_cast<AudioSourceInterface*>(native_source))); |
| return jlongFromPointer(track.release()); |
| } |
| |
| ScopedJavaLocalRef<jobject> JNI_PeerConnectionFactory_GetRtpSenderCapabilities( |
| JNIEnv* jni, |
| jlong native_factory, |
| const JavaParamRef<jobject>& media_type) { |
| auto factory = PeerConnectionFactoryFromJava(native_factory); |
| return NativeToJavaRtpCapabilities( |
| jni, factory->GetRtpSenderCapabilities( |
| JavaToNativeMediaType(jni, media_type))); |
| } |
| |
| ScopedJavaLocalRef<jobject> |
| JNI_PeerConnectionFactory_GetRtpReceiverCapabilities( |
| JNIEnv* jni, |
| jlong native_factory, |
| const JavaParamRef<jobject>& media_type) { |
| auto factory = PeerConnectionFactoryFromJava(native_factory); |
| return NativeToJavaRtpCapabilities( |
| jni, factory->GetRtpReceiverCapabilities( |
| JavaToNativeMediaType(jni, media_type))); |
| } |
| |
| static jboolean JNI_PeerConnectionFactory_StartAecDump( |
| JNIEnv* jni, |
| jlong native_factory, |
| jint file_descriptor, |
| jint filesize_limit_bytes) { |
| FILE* f = fdopen(file_descriptor, "wb"); |
| if (!f) { |
| close(file_descriptor); |
| return false; |
| } |
| |
| return PeerConnectionFactoryFromJava(native_factory) |
| ->StartAecDump(f, filesize_limit_bytes); |
| } |
| |
| static void JNI_PeerConnectionFactory_StopAecDump(JNIEnv* jni, |
| jlong native_factory) { |
| PeerConnectionFactoryFromJava(native_factory)->StopAecDump(); |
| } |
| |
| static jlong JNI_PeerConnectionFactory_CreatePeerConnection( |
| JNIEnv* jni, |
| jlong factory, |
| const JavaParamRef<jobject>& j_rtc_config, |
| const JavaParamRef<jobject>& j_constraints, |
| jlong observer_p, |
| const JavaParamRef<jobject>& j_sslCertificateVerifier) { |
| std::unique_ptr<PeerConnectionObserver> observer( |
| reinterpret_cast<PeerConnectionObserver*>(observer_p)); |
| |
| PeerConnectionInterface::RTCConfiguration rtc_config( |
| PeerConnectionInterface::RTCConfigurationType::kAggressive); |
| JavaToNativeRTCConfiguration(jni, j_rtc_config, &rtc_config); |
| |
| if (rtc_config.certificates.empty()) { |
| // Generate non-default certificate. |
| rtc::KeyType key_type = GetRtcConfigKeyType(jni, j_rtc_config); |
| if (key_type != rtc::KT_DEFAULT) { |
| rtc::scoped_refptr<rtc::RTCCertificate> certificate = |
| rtc::RTCCertificateGenerator::GenerateCertificate( |
| rtc::KeyParams(key_type), absl::nullopt); |
| if (!certificate) { |
| RTC_LOG(LS_ERROR) << "Failed to generate certificate. KeyType: " |
| << key_type; |
| return 0; |
| } |
| rtc_config.certificates.push_back(certificate); |
| } |
| } |
| |
| std::unique_ptr<MediaConstraints> constraints; |
| if (!j_constraints.is_null()) { |
| constraints = JavaToNativeMediaConstraints(jni, j_constraints); |
| CopyConstraintsIntoRtcConfiguration(constraints.get(), &rtc_config); |
| } |
| |
| PeerConnectionDependencies peer_connection_dependencies(observer.get()); |
| if (!j_sslCertificateVerifier.is_null()) { |
| peer_connection_dependencies.tls_cert_verifier = |
| std::make_unique<SSLCertificateVerifierWrapper>( |
| jni, j_sslCertificateVerifier); |
| } |
| |
| auto result = |
| PeerConnectionFactoryFromJava(factory)->CreatePeerConnectionOrError( |
| rtc_config, std::move(peer_connection_dependencies)); |
| if (!result.ok()) |
| return 0; |
| |
| return jlongFromPointer(new OwnedPeerConnection( |
| result.MoveValue(), std::move(observer), std::move(constraints))); |
| } |
| |
| static jlong JNI_PeerConnectionFactory_CreateVideoSource( |
| JNIEnv* jni, |
| jlong native_factory, |
| jboolean is_screencast, |
| jboolean align_timestamps) { |
| OwnedFactoryAndThreads* factory = |
| reinterpret_cast<OwnedFactoryAndThreads*>(native_factory); |
| return jlongFromPointer(CreateVideoSource(jni, factory->signaling_thread(), |
| factory->worker_thread(), |
| is_screencast, align_timestamps)); |
| } |
| |
| static jlong JNI_PeerConnectionFactory_CreateVideoTrack( |
| JNIEnv* jni, |
| jlong native_factory, |
| const JavaParamRef<jstring>& id, |
| jlong native_source) { |
| rtc::scoped_refptr<VideoTrackInterface> track = |
| PeerConnectionFactoryFromJava(native_factory) |
| ->CreateVideoTrack( |
| rtc::scoped_refptr<VideoTrackSourceInterface>( |
| reinterpret_cast<VideoTrackSourceInterface*>(native_source)), |
| JavaToStdString(jni, id)); |
| return jlongFromPointer(track.release()); |
| } |
| |
| static jlong JNI_PeerConnectionFactory_GetNativePeerConnectionFactory( |
| JNIEnv* jni, |
| jlong native_factory) { |
| return jlongFromPointer(PeerConnectionFactoryFromJava(native_factory)); |
| } |
| |
| static void JNI_PeerConnectionFactory_InjectLoggable( |
| JNIEnv* jni, |
| const JavaParamRef<jobject>& j_logging, |
| jint nativeSeverity) { |
| std::unique_ptr<JNILogSink>& jni_log_sink = GetStaticObjects().jni_log_sink; |
| |
| // If there is already a LogSink, remove it from LogMessage. |
| if (jni_log_sink) { |
| rtc::LogMessage::RemoveLogToStream(jni_log_sink.get()); |
| } |
| jni_log_sink = std::make_unique<JNILogSink>(jni, j_logging); |
| rtc::LogMessage::AddLogToStream( |
| jni_log_sink.get(), static_cast<rtc::LoggingSeverity>(nativeSeverity)); |
| rtc::LogMessage::LogToDebug(rtc::LS_NONE); |
| } |
| |
| static void JNI_PeerConnectionFactory_DeleteLoggable(JNIEnv* jni) { |
| std::unique_ptr<JNILogSink>& jni_log_sink = GetStaticObjects().jni_log_sink; |
| |
| if (jni_log_sink) { |
| rtc::LogMessage::RemoveLogToStream(jni_log_sink.get()); |
| jni_log_sink.reset(); |
| } |
| } |
| |
| static void JNI_PeerConnectionFactory_PrintStackTrace(JNIEnv* env, jint tid) { |
| RTC_LOG(LS_WARNING) << StackTraceToString(GetStackTrace(tid)); |
| } |
| |
| } // namespace jni |
| } // namespace webrtc |