diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/libwebrtc/sdk/android/native_api | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/sdk/android/native_api')
25 files changed, 2201 insertions, 0 deletions
diff --git a/third_party/libwebrtc/sdk/android/native_api/DEPS b/third_party/libwebrtc/sdk/android/native_api/DEPS new file mode 100644 index 0000000000..020e1cbf09 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/DEPS @@ -0,0 +1,4 @@ +include_rules = [ + "+modules/audio_device/include/audio_device.h", + "+system_wrappers/include", +] diff --git a/third_party/libwebrtc/sdk/android/native_api/audio_device_module/audio_device_android.cc b/third_party/libwebrtc/sdk/android/native_api/audio_device_module/audio_device_android.cc new file mode 100644 index 0000000000..2be7f7d7fb --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/audio_device_module/audio_device_android.cc @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018 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/native_api/audio_device_module/audio_device_android.h" + +#include <stdlib.h> + +#include <memory> +#include <utility> + +#include "api/scoped_refptr.h" +#include "rtc_base/logging.h" +#include "rtc_base/ref_count.h" + +#if defined(WEBRTC_AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO) +#include "sdk/android/src/jni/audio_device/aaudio_player.h" +#include "sdk/android/src/jni/audio_device/aaudio_recorder.h" +#endif + +#include "sdk/android/src/jni/audio_device/audio_record_jni.h" +#include "sdk/android/src/jni/audio_device/audio_track_jni.h" +#include "sdk/android/src/jni/audio_device/opensles_player.h" +#include "sdk/android/src/jni/audio_device/opensles_recorder.h" +#include "system_wrappers/include/metrics.h" + +namespace webrtc { + +namespace { + +void GetDefaultAudioParameters(JNIEnv* env, + jobject application_context, + AudioParameters* input_parameters, + AudioParameters* output_parameters) { + const JavaParamRef<jobject> j_context(application_context); + const ScopedJavaLocalRef<jobject> j_audio_manager = + jni::GetAudioManager(env, j_context); + const int input_sample_rate = jni::GetDefaultSampleRate(env, j_audio_manager); + const int output_sample_rate = + jni::GetDefaultSampleRate(env, j_audio_manager); + jni::GetAudioParameters(env, j_context, j_audio_manager, input_sample_rate, + output_sample_rate, false /* use_stereo_input */, + false /* use_stereo_output */, input_parameters, + output_parameters); +} + +} // namespace + +#if defined(WEBRTC_AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO) +rtc::scoped_refptr<AudioDeviceModule> CreateAAudioAudioDeviceModule( + JNIEnv* env, + jobject application_context) { + RTC_DLOG(LS_INFO) << __FUNCTION__; + // Get default audio input/output parameters. + AudioParameters input_parameters; + AudioParameters output_parameters; + GetDefaultAudioParameters(env, application_context, &input_parameters, + &output_parameters); + // Create ADM from AAudioRecorder and AAudioPlayer. + return CreateAudioDeviceModuleFromInputAndOutput( + AudioDeviceModule::kAndroidAAudioAudio, false /* use_stereo_input */, + false /* use_stereo_output */, + jni::kLowLatencyModeDelayEstimateInMilliseconds, + std::make_unique<jni::AAudioRecorder>(input_parameters), + std::make_unique<jni::AAudioPlayer>(output_parameters)); +} +#endif + +rtc::scoped_refptr<AudioDeviceModule> CreateJavaAudioDeviceModule( + JNIEnv* env, + jobject application_context) { + RTC_DLOG(LS_INFO) << __FUNCTION__; + // Get default audio input/output parameters. + const JavaParamRef<jobject> j_context(application_context); + const ScopedJavaLocalRef<jobject> j_audio_manager = + jni::GetAudioManager(env, j_context); + AudioParameters input_parameters; + AudioParameters output_parameters; + GetDefaultAudioParameters(env, application_context, &input_parameters, + &output_parameters); + // Create ADM from AudioRecord and AudioTrack. + auto audio_input = std::make_unique<jni::AudioRecordJni>( + env, input_parameters, jni::kHighLatencyModeDelayEstimateInMilliseconds, + jni::AudioRecordJni::CreateJavaWebRtcAudioRecord(env, j_context, + j_audio_manager)); + auto audio_output = std::make_unique<jni::AudioTrackJni>( + env, output_parameters, + jni::AudioTrackJni::CreateJavaWebRtcAudioTrack(env, j_context, + j_audio_manager)); + return CreateAudioDeviceModuleFromInputAndOutput( + AudioDeviceModule::kAndroidJavaAudio, false /* use_stereo_input */, + false /* use_stereo_output */, + jni::kHighLatencyModeDelayEstimateInMilliseconds, std::move(audio_input), + std::move(audio_output)); +} + +rtc::scoped_refptr<AudioDeviceModule> CreateOpenSLESAudioDeviceModule( + JNIEnv* env, + jobject application_context) { + RTC_DLOG(LS_INFO) << __FUNCTION__; + // Get default audio input/output parameters. + AudioParameters input_parameters; + AudioParameters output_parameters; + GetDefaultAudioParameters(env, application_context, &input_parameters, + &output_parameters); + // Create ADM from OpenSLESRecorder and OpenSLESPlayer. + rtc::scoped_refptr<jni::OpenSLEngineManager> engine_manager( + new jni::OpenSLEngineManager()); + auto audio_input = + std::make_unique<jni::OpenSLESRecorder>(input_parameters, engine_manager); + auto audio_output = std::make_unique<jni::OpenSLESPlayer>( + output_parameters, std::move(engine_manager)); + return CreateAudioDeviceModuleFromInputAndOutput( + AudioDeviceModule::kAndroidOpenSLESAudio, false /* use_stereo_input */, + false /* use_stereo_output */, + jni::kLowLatencyModeDelayEstimateInMilliseconds, std::move(audio_input), + std::move(audio_output)); +} + +rtc::scoped_refptr<AudioDeviceModule> +CreateJavaInputAndOpenSLESOutputAudioDeviceModule(JNIEnv* env, + jobject application_context) { + RTC_DLOG(LS_INFO) << __FUNCTION__; + // Get default audio input/output parameters. + const JavaParamRef<jobject> j_context(application_context); + const ScopedJavaLocalRef<jobject> j_audio_manager = + jni::GetAudioManager(env, j_context); + AudioParameters input_parameters; + AudioParameters output_parameters; + GetDefaultAudioParameters(env, application_context, &input_parameters, + &output_parameters); + // Create ADM from AudioRecord and OpenSLESPlayer. + auto audio_input = std::make_unique<jni::AudioRecordJni>( + env, input_parameters, jni::kLowLatencyModeDelayEstimateInMilliseconds, + jni::AudioRecordJni::CreateJavaWebRtcAudioRecord(env, j_context, + j_audio_manager)); + + rtc::scoped_refptr<jni::OpenSLEngineManager> engine_manager( + new jni::OpenSLEngineManager()); + auto audio_output = std::make_unique<jni::OpenSLESPlayer>( + output_parameters, std::move(engine_manager)); + return CreateAudioDeviceModuleFromInputAndOutput( + AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio, + false /* use_stereo_input */, false /* use_stereo_output */, + jni::kLowLatencyModeDelayEstimateInMilliseconds, std::move(audio_input), + std::move(audio_output)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/audio_device_module/audio_device_android.h b/third_party/libwebrtc/sdk/android/native_api/audio_device_module/audio_device_android.h new file mode 100644 index 0000000000..a093f8c895 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/audio_device_module/audio_device_android.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_AUDIO_DEVICE_MODULE_AUDIO_DEVICE_ANDROID_H_ +#define SDK_ANDROID_NATIVE_API_AUDIO_DEVICE_MODULE_AUDIO_DEVICE_ANDROID_H_ + +#include <jni.h> + +#include "modules/audio_device/include/audio_device.h" + +namespace webrtc { + +#if defined(WEBRTC_AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO) +rtc::scoped_refptr<AudioDeviceModule> CreateAAudioAudioDeviceModule( + JNIEnv* env, + jobject application_context); +#endif + +rtc::scoped_refptr<AudioDeviceModule> CreateJavaAudioDeviceModule( + JNIEnv* env, + jobject application_context); + +rtc::scoped_refptr<AudioDeviceModule> CreateOpenSLESAudioDeviceModule( + JNIEnv* env, + jobject application_context); + +rtc::scoped_refptr<AudioDeviceModule> +CreateJavaInputAndOpenSLESOutputAudioDeviceModule(JNIEnv* env, + jobject application_context); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_AUDIO_DEVICE_MODULE_AUDIO_DEVICE_ANDROID_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/base/init.cc b/third_party/libwebrtc/sdk/android/native_api/base/init.cc new file mode 100644 index 0000000000..176aa89ece --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/base/init.cc @@ -0,0 +1,24 @@ +/* + * Copyright 2018 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/native_api/base/init.h" + +#include "rtc_base/checks.h" +#include "sdk/android/native_api/jni/class_loader.h" +#include "sdk/android/src/jni/jni_helpers.h" + +namespace webrtc { + +void InitAndroid(JavaVM* jvm) { + RTC_CHECK_GE(jni::InitGlobalJniVariables(jvm), 0); + InitClassLoader(jni::GetEnv()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/base/init.h b/third_party/libwebrtc/sdk/android/native_api/base/init.h new file mode 100644 index 0000000000..d6a0ec1509 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/base/init.h @@ -0,0 +1,23 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_BASE_INIT_H_ +#define SDK_ANDROID_NATIVE_API_BASE_INIT_H_ + +#include <jni.h> + +namespace webrtc { + +// Initializes global state needed by WebRTC Android NDK. +void InitAndroid(JavaVM* jvm); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_BASE_INIT_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/codecs/wrapper.cc b/third_party/libwebrtc/sdk/android/native_api/codecs/wrapper.cc new file mode 100644 index 0000000000..c3f2095335 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/codecs/wrapper.cc @@ -0,0 +1,49 @@ +/* + * Copyright 2018 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/native_api/codecs/wrapper.h" + +#include <memory> + +#include "sdk/android/native_api/jni/scoped_java_ref.h" +#include "sdk/android/src/jni/video_codec_info.h" +#include "sdk/android/src/jni/video_decoder_factory_wrapper.h" +#include "sdk/android/src/jni/video_encoder_factory_wrapper.h" +#include "sdk/android/src/jni/video_encoder_wrapper.h" + +namespace webrtc { + +SdpVideoFormat JavaToNativeVideoCodecInfo(JNIEnv* jni, jobject codec_info) { + return jni::VideoCodecInfoToSdpVideoFormat(jni, + JavaParamRef<jobject>(codec_info)); +} + +std::unique_ptr<VideoDecoderFactory> JavaToNativeVideoDecoderFactory( + JNIEnv* jni, + jobject decoder_factory) { + return std::make_unique<jni::VideoDecoderFactoryWrapper>( + jni, JavaParamRef<jobject>(decoder_factory)); +} + +std::unique_ptr<VideoEncoderFactory> JavaToNativeVideoEncoderFactory( + JNIEnv* jni, + jobject encoder_factory) { + return std::make_unique<jni::VideoEncoderFactoryWrapper>( + jni, JavaParamRef<jobject>(encoder_factory)); +} + +std::vector<VideoEncoder::ResolutionBitrateLimits> +JavaToNativeResolutionBitrateLimits(JNIEnv* jni, + const jobjectArray j_bitrate_limits_array) { + return jni::JavaToNativeResolutionBitrateLimits( + jni, JavaParamRef<jobjectArray>(j_bitrate_limits_array)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/codecs/wrapper.h b/third_party/libwebrtc/sdk/android/native_api/codecs/wrapper.h new file mode 100644 index 0000000000..04201699bc --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/codecs/wrapper.h @@ -0,0 +1,48 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_CODECS_WRAPPER_H_ +#define SDK_ANDROID_NATIVE_API_CODECS_WRAPPER_H_ + +#include <jni.h> +#include <memory> +#include <vector> + +#include "api/video_codecs/sdp_video_format.h" +#include "api/video_codecs/video_decoder_factory.h" +#include "api/video_codecs/video_encoder.h" +#include "api/video_codecs/video_encoder_factory.h" + +namespace webrtc { + +// Creates an instance of webrtc::SdpVideoFormat from Java VideoCodecInfo. +SdpVideoFormat JavaToNativeVideoCodecInfo(JNIEnv* jni, jobject codec_info); + +// Creates an instance of webrtc::VideoDecoderFactory from Java +// VideoDecoderFactory. +std::unique_ptr<VideoDecoderFactory> JavaToNativeVideoDecoderFactory( + JNIEnv* jni, + jobject decoder_factory); + +// Creates an instance of webrtc::VideoEncoderFactory from Java +// VideoEncoderFactory. +std::unique_ptr<VideoEncoderFactory> JavaToNativeVideoEncoderFactory( + JNIEnv* jni, + jobject encoder_factory); + +// Creates an array of VideoEncoder::ResolutionBitrateLimits from Java array +// of ResolutionBitrateLimits. +std::vector<VideoEncoder::ResolutionBitrateLimits> +JavaToNativeResolutionBitrateLimits(JNIEnv* jni, + jobjectArray j_bitrate_limits_array); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_CODECS_WRAPPER_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/class_loader.cc b/third_party/libwebrtc/sdk/android/native_api/jni/class_loader.cc new file mode 100644 index 0000000000..1789d78c85 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/class_loader.cc @@ -0,0 +1,80 @@ +/* + * 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/native_api/jni/class_loader.h" + +#include <algorithm> +#include <string> + +#include "rtc_base/checks.h" +#include "sdk/android/generated_native_api_jni/WebRtcClassLoader_jni.h" +#include "sdk/android/native_api/jni/java_types.h" +#include "sdk/android/native_api/jni/scoped_java_ref.h" + +// Abort the process if `jni` has a Java exception pending. This macros uses the +// comma operator to execute ExceptionDescribe and ExceptionClear ignoring their +// return values and sending "" to the error stream. +#define CHECK_EXCEPTION(jni) \ + RTC_CHECK(!jni->ExceptionCheck()) \ + << (jni->ExceptionDescribe(), jni->ExceptionClear(), "") + +namespace webrtc { + +namespace { + +class ClassLoader { + public: + explicit ClassLoader(JNIEnv* env) + : class_loader_(jni::Java_WebRtcClassLoader_getClassLoader(env)) { + class_loader_class_ = reinterpret_cast<jclass>( + env->NewGlobalRef(env->FindClass("java/lang/ClassLoader"))); + CHECK_EXCEPTION(env); + load_class_method_ = + env->GetMethodID(class_loader_class_, "loadClass", + "(Ljava/lang/String;)Ljava/lang/Class;"); + CHECK_EXCEPTION(env); + } + + ScopedJavaLocalRef<jclass> FindClass(JNIEnv* env, const char* c_name) { + // ClassLoader.loadClass expects a classname with components separated by + // dots instead of the slashes that JNIEnv::FindClass expects. + std::string name(c_name); + std::replace(name.begin(), name.end(), '/', '.'); + ScopedJavaLocalRef<jstring> j_name = NativeToJavaString(env, name); + const jclass clazz = static_cast<jclass>(env->CallObjectMethod( + class_loader_.obj(), load_class_method_, j_name.obj())); + CHECK_EXCEPTION(env); + return ScopedJavaLocalRef<jclass>(env, clazz); + } + + private: + ScopedJavaGlobalRef<jobject> class_loader_; + jclass class_loader_class_; + jmethodID load_class_method_; +}; + +static ClassLoader* g_class_loader = nullptr; + +} // namespace + +void InitClassLoader(JNIEnv* env) { + RTC_CHECK(g_class_loader == nullptr); + g_class_loader = new ClassLoader(env); +} + +ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* name) { + // The class loader will be null in the JNI code called from the ClassLoader + // ctor when we are bootstrapping ourself. + return (g_class_loader == nullptr) + ? ScopedJavaLocalRef<jclass>(env, env->FindClass(name)) + : g_class_loader->FindClass(env, name); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/class_loader.h b/third_party/libwebrtc/sdk/android/native_api/jni/class_loader.h new file mode 100644 index 0000000000..2d102fe4a2 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/class_loader.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +// Android's FindClass() is tricky because the app-specific ClassLoader is not +// consulted when there is no app-specific frame on the stack (i.e. when called +// from a thread created from native C++ code). These helper functions provide a +// workaround for this. +// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass + +#ifndef SDK_ANDROID_NATIVE_API_JNI_CLASS_LOADER_H_ +#define SDK_ANDROID_NATIVE_API_JNI_CLASS_LOADER_H_ + +#include <jni.h> + +#include "sdk/android/native_api/jni/scoped_java_ref.h" + +namespace webrtc { + +// This method should be called from JNI_OnLoad and before any calls to +// FindClass. This is normally called by InitAndroid. +void InitClassLoader(JNIEnv* env); + +// This function is identical to JNIEnv::FindClass except that it works from any +// thread. This function loads and returns a local reference to the class with +// the given name. The name argument is a fully-qualified class name. For +// example, the fully-qualified class name for the java.lang.String class is: +// "java/lang/String". This function will be used from the JNI generated code +// and should rarely be used manually. +ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* name); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_JNI_CLASS_LOADER_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/java_types.cc b/third_party/libwebrtc/sdk/android/native_api/jni/java_types.cc new file mode 100644 index 0000000000..af02c10f4c --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/java_types.cc @@ -0,0 +1,355 @@ +/* + * Copyright 2015 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/native_api/jni/java_types.h" + +#include <memory> +#include <string> +#include <utility> + +#include "sdk/android/generated_external_classes_jni/ArrayList_jni.h" +#include "sdk/android/generated_external_classes_jni/Boolean_jni.h" +#include "sdk/android/generated_external_classes_jni/Double_jni.h" +#include "sdk/android/generated_external_classes_jni/Enum_jni.h" +#include "sdk/android/generated_external_classes_jni/Integer_jni.h" +#include "sdk/android/generated_external_classes_jni/Iterable_jni.h" +#include "sdk/android/generated_external_classes_jni/Iterator_jni.h" +#include "sdk/android/generated_external_classes_jni/LinkedHashMap_jni.h" +#include "sdk/android/generated_external_classes_jni/Long_jni.h" +#include "sdk/android/generated_external_classes_jni/Map_jni.h" +#include "sdk/android/generated_native_api_jni/JniHelper_jni.h" + +namespace webrtc { + +Iterable::Iterable(JNIEnv* jni, const JavaRef<jobject>& iterable) + : jni_(jni), iterable_(jni, iterable) {} + +Iterable::Iterable(Iterable&& other) = default; + +Iterable::~Iterable() = default; + +// Creates an iterator representing the end of any collection. +Iterable::Iterator::Iterator() = default; + +// Creates an iterator pointing to the beginning of the specified collection. +Iterable::Iterator::Iterator(JNIEnv* jni, const JavaRef<jobject>& iterable) + : jni_(jni) { + iterator_ = JNI_Iterable::Java_Iterable_iterator(jni, iterable); + RTC_CHECK(!iterator_.is_null()); + // Start at the first element in the collection. + ++(*this); +} + +// Move constructor - necessary to be able to return iterator types from +// functions. +Iterable::Iterator::Iterator(Iterator&& other) + : jni_(std::move(other.jni_)), + iterator_(std::move(other.iterator_)), + value_(std::move(other.value_)) { + RTC_DCHECK_RUN_ON(&thread_checker_); +} + +Iterable::Iterator::~Iterator() = default; + +// Advances the iterator one step. +Iterable::Iterator& Iterable::Iterator::operator++() { + RTC_DCHECK_RUN_ON(&thread_checker_); + if (AtEnd()) { + // Can't move past the end. + return *this; + } + bool has_next = JNI_Iterator::Java_Iterator_hasNext(jni_, iterator_); + if (!has_next) { + iterator_ = nullptr; + value_ = nullptr; + return *this; + } + + value_ = JNI_Iterator::Java_Iterator_next(jni_, iterator_); + return *this; +} + +void Iterable::Iterator::Remove() { + JNI_Iterator::Java_Iterator_remove(jni_, iterator_); +} + +// Provides a way to compare the iterator with itself and with the end iterator. +// Note: all other comparison results are undefined, just like for C++ input +// iterators. +bool Iterable::Iterator::operator==(const Iterable::Iterator& other) { + // Two different active iterators should never be compared. + RTC_DCHECK(this == &other || AtEnd() || other.AtEnd()); + return AtEnd() == other.AtEnd(); +} + +ScopedJavaLocalRef<jobject>& Iterable::Iterator::operator*() { + RTC_CHECK(!AtEnd()); + return value_; +} + +bool Iterable::Iterator::AtEnd() const { + RTC_DCHECK_RUN_ON(&thread_checker_); + return jni_ == nullptr || IsNull(jni_, iterator_); +} + +bool IsNull(JNIEnv* jni, const JavaRef<jobject>& obj) { + return jni->IsSameObject(obj.obj(), nullptr); +} + +std::string GetJavaEnumName(JNIEnv* jni, const JavaRef<jobject>& j_enum) { + return JavaToStdString(jni, JNI_Enum::Java_Enum_name(jni, j_enum)); +} + +Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef<jobject>& j_map) { + return Iterable(jni, JNI_Map::Java_Map_entrySet(jni, j_map)); +} + +ScopedJavaLocalRef<jobject> GetJavaMapEntryKey( + JNIEnv* jni, + const JavaRef<jobject>& j_entry) { + return jni::Java_JniHelper_getKey(jni, j_entry); +} + +ScopedJavaLocalRef<jobject> GetJavaMapEntryValue( + JNIEnv* jni, + const JavaRef<jobject>& j_entry) { + return jni::Java_JniHelper_getValue(jni, j_entry); +} + +int64_t JavaToNativeLong(JNIEnv* env, const JavaRef<jobject>& j_long) { + return JNI_Long::Java_Long_longValue(env, j_long); +} + +absl::optional<bool> JavaToNativeOptionalBool(JNIEnv* jni, + const JavaRef<jobject>& boolean) { + if (IsNull(jni, boolean)) + return absl::nullopt; + return JNI_Boolean::Java_Boolean_booleanValue(jni, boolean); +} + +absl::optional<double> JavaToNativeOptionalDouble( + JNIEnv* jni, + const JavaRef<jobject>& j_double) { + if (IsNull(jni, j_double)) + return absl::nullopt; + return JNI_Double::Java_Double_doubleValue(jni, j_double); +} + +absl::optional<int32_t> JavaToNativeOptionalInt( + JNIEnv* jni, + const JavaRef<jobject>& integer) { + if (IsNull(jni, integer)) + return absl::nullopt; + return JNI_Integer::Java_Integer_intValue(jni, integer); +} + +// Given a jstring, reinterprets it to a new native string. +std::string JavaToNativeString(JNIEnv* jni, const JavaRef<jstring>& j_string) { + const ScopedJavaLocalRef<jbyteArray> j_byte_array = + jni::Java_JniHelper_getStringBytes(jni, j_string); + + const size_t len = jni->GetArrayLength(j_byte_array.obj()); + CHECK_EXCEPTION(jni) << "error during GetArrayLength"; + std::string str(len, '\0'); + jni->GetByteArrayRegion(j_byte_array.obj(), 0, len, + reinterpret_cast<jbyte*>(&str[0])); + CHECK_EXCEPTION(jni) << "error during GetByteArrayRegion"; + return str; +} + +std::map<std::string, std::string> JavaToNativeStringMap( + JNIEnv* jni, + const JavaRef<jobject>& j_map) { + return JavaToNativeMap<std::string, std::string>( + jni, j_map, + [](JNIEnv* env, JavaRef<jobject> const& key, + JavaRef<jobject> const& value) { + return std::make_pair( + JavaToNativeString(env, static_java_ref_cast<jstring>(env, key)), + JavaToNativeString(env, static_java_ref_cast<jstring>(env, value))); + }); +} + +ScopedJavaLocalRef<jobject> NativeToJavaBoolean(JNIEnv* env, bool b) { + return JNI_Boolean::Java_Boolean_ConstructorJLB_Z(env, b); +} + +ScopedJavaLocalRef<jobject> NativeToJavaDouble(JNIEnv* env, double d) { + return JNI_Double::Java_Double_ConstructorJLD_D(env, d); +} + +ScopedJavaLocalRef<jobject> NativeToJavaInteger(JNIEnv* jni, int32_t i) { + return JNI_Integer::Java_Integer_ConstructorJLI_I(jni, i); +} + +ScopedJavaLocalRef<jobject> NativeToJavaLong(JNIEnv* env, int64_t u) { + return JNI_Long::Java_Long_ConstructorJLLO_J(env, u); +} + +ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* env, const char* str) { + jstring j_str = env->NewStringUTF(str); + CHECK_EXCEPTION(env) << "error during NewStringUTF"; + return ScopedJavaLocalRef<jstring>(env, j_str); +} + +ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni, + const std::string& str) { + return NativeToJavaString(jni, str.c_str()); +} + +ScopedJavaLocalRef<jobject> NativeToJavaDouble( + JNIEnv* jni, + const absl::optional<double>& optional_double) { + return optional_double ? NativeToJavaDouble(jni, *optional_double) : nullptr; +} + +ScopedJavaLocalRef<jobject> NativeToJavaInteger( + JNIEnv* jni, + const absl::optional<int32_t>& optional_int) { + return optional_int ? NativeToJavaInteger(jni, *optional_int) : nullptr; +} + +ScopedJavaLocalRef<jstring> NativeToJavaString( + JNIEnv* jni, + const absl::optional<std::string>& str) { + return str ? NativeToJavaString(jni, *str) : nullptr; +} + +ScopedJavaLocalRef<jbyteArray> NativeToJavaByteArray( + JNIEnv* env, + rtc::ArrayView<int8_t> container) { + ScopedJavaLocalRef<jbyteArray> jarray(env, + env->NewByteArray(container.size())); + int8_t* array_ptr = + env->GetByteArrayElements(jarray.obj(), /*isCopy=*/nullptr); + memcpy(array_ptr, container.data(), container.size() * sizeof(int8_t)); + env->ReleaseByteArrayElements(jarray.obj(), array_ptr, /*mode=*/0); + return jarray; +} + +ScopedJavaLocalRef<jintArray> NativeToJavaIntArray( + JNIEnv* env, + rtc::ArrayView<int32_t> container) { + ScopedJavaLocalRef<jintArray> jarray(env, env->NewIntArray(container.size())); + int32_t* array_ptr = + env->GetIntArrayElements(jarray.obj(), /*isCopy=*/nullptr); + memcpy(array_ptr, container.data(), container.size() * sizeof(int32_t)); + env->ReleaseIntArrayElements(jarray.obj(), array_ptr, /*mode=*/0); + return jarray; +} + +std::vector<int8_t> JavaToNativeByteArray(JNIEnv* env, + const JavaRef<jbyteArray>& jarray) { + int8_t* array_ptr = + env->GetByteArrayElements(jarray.obj(), /*isCopy=*/nullptr); + size_t array_length = env->GetArrayLength(jarray.obj()); + std::vector<int8_t> container(array_ptr, array_ptr + array_length); + env->ReleaseByteArrayElements(jarray.obj(), array_ptr, /*mode=*/JNI_ABORT); + return container; +} + +std::vector<int32_t> JavaToNativeIntArray(JNIEnv* env, + const JavaRef<jintArray>& jarray) { + int32_t* array_ptr = + env->GetIntArrayElements(jarray.obj(), /*isCopy=*/nullptr); + size_t array_length = env->GetArrayLength(jarray.obj()); + std::vector<int32_t> container(array_ptr, array_ptr + array_length); + env->ReleaseIntArrayElements(jarray.obj(), array_ptr, /*mode=*/JNI_ABORT); + return container; +} + +ScopedJavaLocalRef<jobjectArray> NativeToJavaBooleanArray( + JNIEnv* env, + const std::vector<bool>& container) { + return NativeToJavaObjectArray(env, container, java_lang_Boolean_clazz(env), + &NativeToJavaBoolean); +} + +ScopedJavaLocalRef<jobjectArray> NativeToJavaDoubleArray( + JNIEnv* env, + const std::vector<double>& container) { + ScopedJavaLocalRef<jobject> (*convert_function)(JNIEnv*, double) = + &NativeToJavaDouble; + return NativeToJavaObjectArray(env, container, java_lang_Double_clazz(env), + convert_function); +} + +ScopedJavaLocalRef<jobjectArray> NativeToJavaIntegerArray( + JNIEnv* env, + const std::vector<int32_t>& container) { + ScopedJavaLocalRef<jobject> (*convert_function)(JNIEnv*, int32_t) = + &NativeToJavaInteger; + return NativeToJavaObjectArray(env, container, java_lang_Integer_clazz(env), + convert_function); +} + +ScopedJavaLocalRef<jobjectArray> NativeToJavaLongArray( + JNIEnv* env, + const std::vector<int64_t>& container) { + return NativeToJavaObjectArray(env, container, java_lang_Long_clazz(env), + &NativeToJavaLong); +} + +ScopedJavaLocalRef<jobjectArray> NativeToJavaStringArray( + JNIEnv* env, + const std::vector<std::string>& container) { + ScopedJavaLocalRef<jstring> (*convert_function)(JNIEnv*, const std::string&) = + &NativeToJavaString; + return NativeToJavaObjectArray( + env, container, + static_cast<jclass>(jni::Java_JniHelper_getStringClass(env).obj()), + convert_function); +} + +JavaListBuilder::JavaListBuilder(JNIEnv* env) + : env_(env), j_list_(JNI_ArrayList::Java_ArrayList_ConstructorJUALI(env)) {} + +JavaListBuilder::~JavaListBuilder() = default; + +void JavaListBuilder::add(const JavaRef<jobject>& element) { + JNI_ArrayList::Java_ArrayList_addZ_JUE(env_, j_list_, element); +} + +JavaMapBuilder::JavaMapBuilder(JNIEnv* env) + : env_(env), + j_map_(JNI_LinkedHashMap::Java_LinkedHashMap_ConstructorJULIHM(env)) {} + +JavaMapBuilder::~JavaMapBuilder() = default; + +void JavaMapBuilder::put(const JavaRef<jobject>& key, + const JavaRef<jobject>& value) { + JNI_Map::Java_Map_put(env_, j_map_, key, value); +} + +jlong NativeToJavaPointer(void* ptr) { + static_assert(sizeof(intptr_t) <= sizeof(jlong), + "Time to rethink the use of jlongs"); + // Going through intptr_t to be obvious about the definedness of the + // conversion from pointer to integral type. intptr_t to jlong is a standard + // widening by the static_assert above. + jlong ret = reinterpret_cast<intptr_t>(ptr); + RTC_DCHECK(reinterpret_cast<void*>(ret) == ptr); + return ret; +} + +// Given a list of jstrings, reinterprets it to a new vector of native strings. +std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni, + const JavaRef<jobject>& list) { + std::vector<std::string> converted_list; + if (!list.is_null()) { + for (const JavaRef<jobject>& str : Iterable(jni, list)) { + converted_list.push_back(JavaToStdString( + jni, JavaParamRef<jstring>(static_cast<jstring>(str.obj())))); + } + } + return converted_list; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/java_types.h b/third_party/libwebrtc/sdk/android/native_api/jni/java_types.h new file mode 100644 index 0000000000..1008737d90 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/java_types.h @@ -0,0 +1,366 @@ +/* + * Copyright 2015 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. + */ + +// Android's FindClass() is tricky because the app-specific ClassLoader is not +// consulted when there is no app-specific frame on the stack (i.e. when called +// from a thread created from native C++ code). These helper functions provide a +// workaround for this. +// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass + +#ifndef SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_ +#define SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_ + +#include <jni.h> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "api/sequence_checker.h" +#include "rtc_base/checks.h" +#include "sdk/android/native_api/jni/scoped_java_ref.h" + +// Abort the process if `jni` has a Java exception pending. +// This macros uses the comma operator to execute ExceptionDescribe +// and ExceptionClear ignoring their return values and sending "" +// to the error stream. +#define CHECK_EXCEPTION(jni) \ + RTC_CHECK(!jni->ExceptionCheck()) \ + << (jni->ExceptionDescribe(), jni->ExceptionClear(), "") + +namespace webrtc { + +// --------------- +// -- Utilities -- +// --------------- + +// Provides a convenient way to iterate over a Java Iterable using the +// C++ range-for loop. +// E.g. for (jobject value : Iterable(jni, j_iterable)) { ... } +// Note: Since Java iterators cannot be duplicated, the iterator class is not +// copyable to prevent creating multiple C++ iterators that refer to the same +// Java iterator. +class Iterable { + public: + Iterable(JNIEnv* jni, const JavaRef<jobject>& iterable); + Iterable(Iterable&& other); + + ~Iterable(); + + Iterable(const Iterable&) = delete; + Iterable& operator=(const Iterable&) = delete; + + class Iterator { + public: + // Creates an iterator representing the end of any collection. + Iterator(); + // Creates an iterator pointing to the beginning of the specified + // collection. + Iterator(JNIEnv* jni, const JavaRef<jobject>& iterable); + + // Move constructor - necessary to be able to return iterator types from + // functions. + Iterator(Iterator&& other); + + ~Iterator(); + + Iterator(const Iterator&) = delete; + Iterator& operator=(const Iterator&) = delete; + + // Move assignment should not be used. + Iterator& operator=(Iterator&&) = delete; + + // Advances the iterator one step. + Iterator& operator++(); + + // Removes the element the iterator is pointing to. Must still advance the + // iterator afterwards. + void Remove(); + + // Provides a way to compare the iterator with itself and with the end + // iterator. + // Note: all other comparison results are undefined, just like for C++ input + // iterators. + bool operator==(const Iterator& other); + bool operator!=(const Iterator& other) { return !(*this == other); } + ScopedJavaLocalRef<jobject>& operator*(); + + private: + bool AtEnd() const; + + JNIEnv* jni_ = nullptr; + ScopedJavaLocalRef<jobject> iterator_; + ScopedJavaLocalRef<jobject> value_; + SequenceChecker thread_checker_; + }; + + Iterable::Iterator begin() { return Iterable::Iterator(jni_, iterable_); } + Iterable::Iterator end() { return Iterable::Iterator(); } + + private: + JNIEnv* jni_; + ScopedJavaLocalRef<jobject> iterable_; +}; + +// Returns true if `obj` == null in Java. +bool IsNull(JNIEnv* jni, const JavaRef<jobject>& obj); + +// Returns the name of a Java enum. +std::string GetJavaEnumName(JNIEnv* jni, const JavaRef<jobject>& j_enum); + +Iterable GetJavaMapEntrySet(JNIEnv* jni, const JavaRef<jobject>& j_map); +ScopedJavaLocalRef<jobject> GetJavaMapEntryKey(JNIEnv* jni, + const JavaRef<jobject>& j_entry); +ScopedJavaLocalRef<jobject> GetJavaMapEntryValue( + JNIEnv* jni, + const JavaRef<jobject>& j_entry); + +// -------------------------------------------------------- +// -- Methods for converting Java types to native types. -- +// -------------------------------------------------------- + +int64_t JavaToNativeLong(JNIEnv* env, const JavaRef<jobject>& j_long); + +absl::optional<bool> JavaToNativeOptionalBool(JNIEnv* jni, + const JavaRef<jobject>& boolean); +absl::optional<double> JavaToNativeOptionalDouble( + JNIEnv* jni, + const JavaRef<jobject>& j_double); +absl::optional<int32_t> JavaToNativeOptionalInt( + JNIEnv* jni, + const JavaRef<jobject>& integer); + +// Given a (UTF-16) jstring return a new UTF-8 native string. +std::string JavaToNativeString(JNIEnv* jni, const JavaRef<jstring>& j_string); + +template <typename T, typename Convert> +std::vector<T> JavaToNativeVector(JNIEnv* env, + const JavaRef<jobjectArray>& j_container, + Convert convert) { + std::vector<T> container; + const size_t size = env->GetArrayLength(j_container.obj()); + container.reserve(size); + for (size_t i = 0; i < size; ++i) { + container.emplace_back(convert( + env, ScopedJavaLocalRef<jobject>( + env, env->GetObjectArrayElement(j_container.obj(), i)))); + } + CHECK_EXCEPTION(env) << "Error during JavaToNativeVector"; + return container; +} + +template <typename T, typename Java_T = jobject, typename Convert> +std::vector<T> JavaListToNativeVector(JNIEnv* env, + const JavaRef<jobject>& j_list, + Convert convert) { + std::vector<T> native_list; + if (!j_list.is_null()) { + for (ScopedJavaLocalRef<jobject>& j_item : Iterable(env, j_list)) { + native_list.emplace_back( + convert(env, static_java_ref_cast<Java_T>(env, j_item))); + } + CHECK_EXCEPTION(env) << "Error during JavaListToNativeVector"; + } + return native_list; +} + +template <typename Key, typename T, typename Convert> +std::map<Key, T> JavaToNativeMap(JNIEnv* env, + const JavaRef<jobject>& j_map, + Convert convert) { + std::map<Key, T> container; + for (auto const& j_entry : GetJavaMapEntrySet(env, j_map)) { + container.emplace(convert(env, GetJavaMapEntryKey(env, j_entry), + GetJavaMapEntryValue(env, j_entry))); + } + return container; +} + +// Converts Map<String, String> to std::map<std::string, std::string>. +std::map<std::string, std::string> JavaToNativeStringMap( + JNIEnv* env, + const JavaRef<jobject>& j_map); + +// -------------------------------------------------------- +// -- Methods for converting native types to Java types. -- +// -------------------------------------------------------- + +ScopedJavaLocalRef<jobject> NativeToJavaBoolean(JNIEnv* env, bool b); +ScopedJavaLocalRef<jobject> NativeToJavaDouble(JNIEnv* env, double d); +ScopedJavaLocalRef<jobject> NativeToJavaInteger(JNIEnv* jni, int32_t i); +ScopedJavaLocalRef<jobject> NativeToJavaLong(JNIEnv* env, int64_t u); +ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni, const char* str); +ScopedJavaLocalRef<jstring> NativeToJavaString(JNIEnv* jni, + const std::string& str); + +ScopedJavaLocalRef<jobject> NativeToJavaDouble( + JNIEnv* jni, + const absl::optional<double>& optional_double); +ScopedJavaLocalRef<jobject> NativeToJavaInteger( + JNIEnv* jni, + const absl::optional<int32_t>& optional_int); +ScopedJavaLocalRef<jstring> NativeToJavaString( + JNIEnv* jni, + const absl::optional<std::string>& str); + +// Helper function for converting std::vector<T> into a Java array. +template <typename T, typename Convert> +ScopedJavaLocalRef<jobjectArray> NativeToJavaObjectArray( + JNIEnv* env, + const std::vector<T>& container, + jclass clazz, + Convert convert) { + ScopedJavaLocalRef<jobjectArray> j_container( + env, env->NewObjectArray(container.size(), clazz, nullptr)); + int i = 0; + for (const T& element : container) { + env->SetObjectArrayElement(j_container.obj(), i, + convert(env, element).obj()); + ++i; + } + return j_container; +} + +ScopedJavaLocalRef<jbyteArray> NativeToJavaByteArray( + JNIEnv* env, + rtc::ArrayView<int8_t> container); +ScopedJavaLocalRef<jintArray> NativeToJavaIntArray( + JNIEnv* env, + rtc::ArrayView<int32_t> container); + +std::vector<int8_t> JavaToNativeByteArray(JNIEnv* env, + const JavaRef<jbyteArray>& jarray); +std::vector<int32_t> JavaToNativeIntArray(JNIEnv* env, + const JavaRef<jintArray>& jarray); + +ScopedJavaLocalRef<jobjectArray> NativeToJavaBooleanArray( + JNIEnv* env, + const std::vector<bool>& container); +ScopedJavaLocalRef<jobjectArray> NativeToJavaDoubleArray( + JNIEnv* env, + const std::vector<double>& container); +ScopedJavaLocalRef<jobjectArray> NativeToJavaIntegerArray( + JNIEnv* env, + const std::vector<int32_t>& container); +ScopedJavaLocalRef<jobjectArray> NativeToJavaLongArray( + JNIEnv* env, + const std::vector<int64_t>& container); +ScopedJavaLocalRef<jobjectArray> NativeToJavaStringArray( + JNIEnv* env, + const std::vector<std::string>& container); + +// This is a helper class for NativeToJavaList(). Use that function instead of +// using this class directly. +class JavaListBuilder { + public: + explicit JavaListBuilder(JNIEnv* env); + ~JavaListBuilder(); + void add(const JavaRef<jobject>& element); + ScopedJavaLocalRef<jobject> java_list() { return j_list_; } + + private: + JNIEnv* env_; + ScopedJavaLocalRef<jobject> j_list_; +}; + +template <typename C, typename Convert> +ScopedJavaLocalRef<jobject> NativeToJavaList(JNIEnv* env, + const C& container, + Convert convert) { + JavaListBuilder builder(env); + for (const auto& e : container) + builder.add(convert(env, e)); + return builder.java_list(); +} + +// This is a helper class for NativeToJavaMap(). Use that function instead of +// using this class directly. +class JavaMapBuilder { + public: + explicit JavaMapBuilder(JNIEnv* env); + ~JavaMapBuilder(); + void put(const JavaRef<jobject>& key, const JavaRef<jobject>& value); + ScopedJavaLocalRef<jobject> GetJavaMap() { return j_map_; } + + private: + JNIEnv* env_; + ScopedJavaLocalRef<jobject> j_map_; +}; + +template <typename C, typename Convert> +ScopedJavaLocalRef<jobject> NativeToJavaMap(JNIEnv* env, + const C& container, + Convert convert) { + JavaMapBuilder builder(env); + for (const auto& e : container) { + const auto key_value_pair = convert(env, e); + builder.put(key_value_pair.first, key_value_pair.second); + } + return builder.GetJavaMap(); +} + +template <typename C> +ScopedJavaLocalRef<jobject> NativeToJavaStringMap(JNIEnv* env, + const C& container) { + JavaMapBuilder builder(env); + for (const auto& e : container) { + const auto key_value_pair = std::make_pair( + NativeToJavaString(env, e.first), NativeToJavaString(env, e.second)); + builder.put(key_value_pair.first, key_value_pair.second); + } + return builder.GetJavaMap(); +} + +// Return a `jlong` that will correctly convert back to `ptr`. This is needed +// because the alternative (of silently passing a 32-bit pointer to a vararg +// function expecting a 64-bit param) picks up garbage in the high 32 bits. +jlong NativeToJavaPointer(void* ptr); + +// ------------------------ +// -- Deprecated methods -- +// ------------------------ + +// Deprecated. Use JavaToNativeString. +inline std::string JavaToStdString(JNIEnv* jni, + const JavaRef<jstring>& j_string) { + return JavaToNativeString(jni, j_string); +} + +// Deprecated. Use scoped jobjects instead. +inline std::string JavaToStdString(JNIEnv* jni, jstring j_string) { + return JavaToStdString(jni, JavaParamRef<jstring>(j_string)); +} + +// Deprecated. Use JavaListToNativeVector<std::string, jstring> instead. +// Given a List of (UTF-16) jstrings +// return a new vector of UTF-8 native strings. +std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni, + const JavaRef<jobject>& list); + +// Deprecated. Use JavaToNativeStringMap instead. +// Parses Map<String, String> to std::map<std::string, std::string>. +inline std::map<std::string, std::string> JavaToStdMapStrings( + JNIEnv* jni, + const JavaRef<jobject>& j_map) { + return JavaToNativeStringMap(jni, j_map); +} + +// Deprecated. Use scoped jobjects instead. +inline std::map<std::string, std::string> JavaToStdMapStrings(JNIEnv* jni, + jobject j_map) { + return JavaToStdMapStrings(jni, JavaParamRef<jobject>(j_map)); +} + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_JNI_JAVA_TYPES_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/jni_int_wrapper.h b/third_party/libwebrtc/sdk/android/native_api/jni/jni_int_wrapper.h new file mode 100644 index 0000000000..23da7f2ce4 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/jni_int_wrapper.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018 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. + */ + +// Originally this class is from Chromium. +// https://cs.chromium.org/chromium/src/base/android/jni_int_wrapper.h. + +#ifndef SDK_ANDROID_NATIVE_API_JNI_JNI_INT_WRAPPER_H_ +#define SDK_ANDROID_NATIVE_API_JNI_JNI_INT_WRAPPER_H_ + +// Wrapper used to receive int when calling Java from native. The wrapper +// disallows automatic conversion of anything besides int32_t to a jint. +// Checking is only done in debugging builds. + +#ifdef NDEBUG + +typedef jint JniIntWrapper; + +// This inline is sufficiently trivial that it does not change the +// final code generated by g++. +inline jint as_jint(JniIntWrapper wrapper) { + return wrapper; +} + +#else + +class JniIntWrapper { + public: + JniIntWrapper() : i_(0) {} + JniIntWrapper(int32_t i) : i_(i) {} // NOLINT(runtime/explicit) + explicit JniIntWrapper(const JniIntWrapper& ji) : i_(ji.i_) {} + + jint as_jint() const { return i_; } + + // If you get an "invokes a deleted function" error at the lines below it is + // because you used an implicit conversion to convert e.g. a long to an + // int32_t when calling Java. We disallow this. If you want a lossy + // conversion, please use an explicit conversion in your C++ code. + JniIntWrapper(uint32_t) = delete; // NOLINT(runtime/explicit) + JniIntWrapper(uint64_t) = delete; // NOLINT(runtime/explicit) + JniIntWrapper(int64_t) = delete; // NOLINT(runtime/explicit) + + private: + const jint i_; +}; + +inline jint as_jint(const JniIntWrapper& wrapper) { + return wrapper.as_jint(); +} + +#endif // NDEBUG + +#endif // SDK_ANDROID_NATIVE_API_JNI_JNI_INT_WRAPPER_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/jvm.cc b/third_party/libwebrtc/sdk/android/native_api/jni/jvm.cc new file mode 100644 index 0000000000..3356cbeb6f --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/jvm.cc @@ -0,0 +1,21 @@ +/* + * Copyright 2018 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/native_api/jni/jvm.h" + +#include "sdk/android/src/jni/jvm.h" + +namespace webrtc { + +JNIEnv* AttachCurrentThreadIfNeeded() { + return jni::AttachCurrentThreadIfNeeded(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/jvm.h b/third_party/libwebrtc/sdk/android/native_api/jni/jvm.h new file mode 100644 index 0000000000..00bce6734d --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/jvm.h @@ -0,0 +1,21 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_JNI_JVM_H_ +#define SDK_ANDROID_NATIVE_API_JNI_JVM_H_ + +#include <jni.h> + +namespace webrtc { +// Returns a JNI environment usable on this thread. +JNIEnv* AttachCurrentThreadIfNeeded(); +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_JNI_JVM_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/jni/scoped_java_ref.h b/third_party/libwebrtc/sdk/android/native_api/jni/scoped_java_ref.h new file mode 100644 index 0000000000..a2be447de2 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/jni/scoped_java_ref.h @@ -0,0 +1,226 @@ +/* + * 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. + */ + +// Originally these classes are from Chromium. +// https://cs.chromium.org/chromium/src/base/android/scoped_java_ref.h. + +#ifndef SDK_ANDROID_NATIVE_API_JNI_SCOPED_JAVA_REF_H_ +#define SDK_ANDROID_NATIVE_API_JNI_SCOPED_JAVA_REF_H_ + +#include <jni.h> + +#include <utility> + +#include "sdk/android/native_api/jni/jvm.h" + +namespace webrtc { + +// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful +// for allowing functions to accept a reference without having to mandate +// whether it is a local or global type. +template <typename T> +class JavaRef; + +// Template specialization of JavaRef, which acts as the base class for all +// other JavaRef<> template types. This allows you to e.g. pass JavaRef<jstring> +// into a function taking const JavaRef<jobject>&. +template <> +class JavaRef<jobject> { + public: + JavaRef(const JavaRef&) = delete; + JavaRef& operator=(const JavaRef&) = delete; + + jobject obj() const { return obj_; } + bool is_null() const { + // This is not valid for weak references. For weak references you need to + // use env->IsSameObject(objc_, nullptr), but that should be avoided anyway + // since it does not prevent the object from being freed immediately + // thereafter. Consequently, programmers should not use this check on weak + // references anyway and should first make a ScopedJavaLocalRef or + // ScopedJavaGlobalRef before checking if it is null. + return obj_ == nullptr; + } + + protected: + constexpr JavaRef() : obj_(nullptr) {} + explicit JavaRef(jobject obj) : obj_(obj) {} + jobject obj_; +}; + +template <typename T> +class JavaRef : public JavaRef<jobject> { + public: + JavaRef(const JavaRef&) = delete; + JavaRef& operator=(const JavaRef&) = delete; + + T obj() const { return static_cast<T>(obj_); } + + protected: + JavaRef() : JavaRef<jobject>(nullptr) {} + explicit JavaRef(T obj) : JavaRef<jobject>(obj) {} +}; + +// Holds a local reference to a JNI method parameter. +// Method parameters should not be deleted, and so this class exists purely to +// wrap them as a JavaRef<T> in the JNI binding generator. Do not create +// instances manually. +template <typename T> +class JavaParamRef : public JavaRef<T> { + public: + // Assumes that `obj` is a parameter passed to a JNI method from Java. + // Does not assume ownership as parameters should not be deleted. + explicit JavaParamRef(T obj) : JavaRef<T>(obj) {} + JavaParamRef(JNIEnv*, T obj) : JavaRef<T>(obj) {} + + JavaParamRef(const JavaParamRef&) = delete; + JavaParamRef& operator=(const JavaParamRef&) = delete; +}; + +// Holds a local reference to a Java object. The local reference is scoped +// to the lifetime of this object. +// Instances of this class may hold onto any JNIEnv passed into it until +// destroyed. Therefore, since a JNIEnv is only suitable for use on a single +// thread, objects of this class must be created, used, and destroyed, on a +// single thread. +// Therefore, this class should only be used as a stack-based object and from a +// single thread. If you wish to have the reference outlive the current +// callstack (e.g. as a class member) or you wish to pass it across threads, +// use a ScopedJavaGlobalRef instead. +template <typename T> +class ScopedJavaLocalRef : public JavaRef<T> { + public: + ScopedJavaLocalRef() = default; + ScopedJavaLocalRef(std::nullptr_t) {} // NOLINT(runtime/explicit) + + ScopedJavaLocalRef(JNIEnv* env, const JavaRef<T>& other) : env_(env) { + Reset(other.obj(), OwnershipPolicy::RETAIN); + } + // Allow constructing e.g. ScopedJavaLocalRef<jobject> from + // ScopedJavaLocalRef<jstring>. + template <typename G> + ScopedJavaLocalRef(ScopedJavaLocalRef<G>&& other) : env_(other.env()) { + Reset(other.Release(), OwnershipPolicy::ADOPT); + } + ScopedJavaLocalRef(const ScopedJavaLocalRef& other) : env_(other.env_) { + Reset(other.obj(), OwnershipPolicy::RETAIN); + } + + // Assumes that `obj` is a reference to a Java object and takes + // ownership of this reference. This should preferably not be used + // outside of JNI helper functions. + ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(obj), env_(env) {} + + ~ScopedJavaLocalRef() { + if (obj_ != nullptr) + env_->DeleteLocalRef(obj_); + } + + void operator=(const ScopedJavaLocalRef& other) { + Reset(other.obj(), OwnershipPolicy::RETAIN); + } + void operator=(ScopedJavaLocalRef&& other) { + Reset(other.Release(), OwnershipPolicy::ADOPT); + } + + // Releases the reference to the caller. The caller *must* delete the + // reference when it is done with it. Note that calling a Java method + // is *not* a transfer of ownership and Release() should not be used. + T Release() { + T obj = static_cast<T>(obj_); + obj_ = nullptr; + return obj; + } + + JNIEnv* env() const { return env_; } + + private: + using JavaRef<T>::obj_; + + enum OwnershipPolicy { + // The scoped object takes ownership of an object by taking over an existing + // ownership claim. + ADOPT, + // The scoped object will retain the the object and any initial ownership is + // not changed. + RETAIN + }; + + void Reset(T obj, OwnershipPolicy policy) { + if (obj_ != nullptr) + env_->DeleteLocalRef(obj_); + obj_ = (obj != nullptr && policy == OwnershipPolicy::RETAIN) + ? env_->NewLocalRef(obj) + : obj; + } + + JNIEnv* const env_ = AttachCurrentThreadIfNeeded(); +}; + +// Holds a global reference to a Java object. The global reference is scoped +// to the lifetime of this object. This class does not hold onto any JNIEnv* +// passed to it, hence it is safe to use across threads (within the constraints +// imposed by the underlying Java object that it references). +template <typename T> +class ScopedJavaGlobalRef : public JavaRef<T> { + public: + using JavaRef<T>::obj_; + + ScopedJavaGlobalRef() = default; + explicit constexpr ScopedJavaGlobalRef(std::nullptr_t) {} + ScopedJavaGlobalRef(JNIEnv* env, const JavaRef<T>& other) + : JavaRef<T>(static_cast<T>(env->NewGlobalRef(other.obj()))) {} + explicit ScopedJavaGlobalRef(const ScopedJavaLocalRef<T>& other) + : ScopedJavaGlobalRef(other.env(), other) {} + ScopedJavaGlobalRef(ScopedJavaGlobalRef&& other) + : JavaRef<T>(other.Release()) {} + + ~ScopedJavaGlobalRef() { + if (obj_ != nullptr) + AttachCurrentThreadIfNeeded()->DeleteGlobalRef(obj_); + } + + ScopedJavaGlobalRef(const ScopedJavaGlobalRef&) = delete; + ScopedJavaGlobalRef& operator=(const ScopedJavaGlobalRef&) = delete; + + void operator=(const JavaRef<T>& other) { + JNIEnv* env = AttachCurrentThreadIfNeeded(); + if (obj_ != nullptr) { + env->DeleteGlobalRef(obj_); + } + obj_ = other.is_null() ? nullptr : env->NewGlobalRef(other.obj()); + } + + void operator=(std::nullptr_t) { + if (obj_ != nullptr) { + AttachCurrentThreadIfNeeded()->DeleteGlobalRef(obj_); + } + obj_ = nullptr; + } + + // Releases the reference to the caller. The caller *must* delete the + // reference when it is done with it. Note that calling a Java method + // is *not* a transfer of ownership and Release() should not be used. + T Release() { + T obj = static_cast<T>(obj_); + obj_ = nullptr; + return obj; + } +}; + +template <typename T> +inline ScopedJavaLocalRef<T> static_java_ref_cast(JNIEnv* env, + JavaRef<jobject> const& ref) { + ScopedJavaLocalRef<jobject> owned_ref(env, ref); + return ScopedJavaLocalRef<T>(env, static_cast<T>(owned_ref.Release())); +} + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_JNI_SCOPED_JAVA_REF_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/network_monitor/network_monitor.cc b/third_party/libwebrtc/sdk/android/native_api/network_monitor/network_monitor.cc new file mode 100644 index 0000000000..38be7fdef7 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/network_monitor/network_monitor.cc @@ -0,0 +1,31 @@ +/* + * Copyright 2018 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/native_api/network_monitor/network_monitor.h" + +#include <memory> + +#include "sdk/android/src/jni/android_network_monitor.h" + +namespace webrtc { + +std::unique_ptr<rtc::NetworkMonitorFactory> CreateAndroidNetworkMonitorFactory( + JNIEnv* env, + jobject application_context) { + return std::make_unique<jni::AndroidNetworkMonitorFactory>( + env, JavaParamRef<jobject>(application_context)); +} + +std::unique_ptr<rtc::NetworkMonitorFactory> +CreateAndroidNetworkMonitorFactory() { + return std::make_unique<jni::AndroidNetworkMonitorFactory>(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/network_monitor/network_monitor.h b/third_party/libwebrtc/sdk/android/native_api/network_monitor/network_monitor.h new file mode 100644 index 0000000000..45ecd75543 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/network_monitor/network_monitor.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_NETWORK_MONITOR_NETWORK_MONITOR_H_ +#define SDK_ANDROID_NATIVE_API_NETWORK_MONITOR_NETWORK_MONITOR_H_ + +#include <jni.h> + +#include <memory> + +#include "rtc_base/network_monitor_factory.h" + +namespace webrtc { + +// Creates an Android-specific network monitor, which is capable of detecting +// network changes as soon as they occur, requesting a cellular interface +// (dependent on permissions), and binding sockets to network interfaces (more +// reliable than binding to IP addresses on Android). +std::unique_ptr<rtc::NetworkMonitorFactory> CreateAndroidNetworkMonitorFactory( + JNIEnv* env, + jobject application_context); + +// Deprecated. Pass in application context instead. +std::unique_ptr<rtc::NetworkMonitorFactory> +CreateAndroidNetworkMonitorFactory(); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_NETWORK_MONITOR_NETWORK_MONITOR_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/peerconnection/peer_connection_factory.cc b/third_party/libwebrtc/sdk/android/native_api/peerconnection/peer_connection_factory.cc new file mode 100644 index 0000000000..87ab991cf4 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/peerconnection/peer_connection_factory.cc @@ -0,0 +1,33 @@ +/* + * Copyright 2018 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/native_api/peerconnection/peer_connection_factory.h" + +#include <jni.h> + +#include <memory> +#include <utility> + +#include "sdk/android/src/jni/pc/peer_connection_factory.h" + +namespace webrtc { + +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 webrtc::jni::NativeToJavaPeerConnectionFactory( + jni, pcf, std::move(socket_factory), std::move(network_thread), + std::move(worker_thread), std::move(signaling_thread)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/peerconnection/peer_connection_factory.h b/third_party/libwebrtc/sdk/android/native_api/peerconnection/peer_connection_factory.h new file mode 100644 index 0000000000..959eb797ce --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/peerconnection/peer_connection_factory.h @@ -0,0 +1,34 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_PEERCONNECTION_PEER_CONNECTION_FACTORY_H_ +#define SDK_ANDROID_NATIVE_API_PEERCONNECTION_PEER_CONNECTION_FACTORY_H_ + +#include <jni.h> + +#include <memory> + +#include "api/peer_connection_interface.h" +#include "rtc_base/thread.h" + +namespace webrtc { + +// Creates java PeerConnectionFactory with specified `pcf`. +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); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_PEERCONNECTION_PEER_CONNECTION_FACTORY_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/stacktrace/stacktrace.cc b/third_party/libwebrtc/sdk/android/native_api/stacktrace/stacktrace.cc new file mode 100644 index 0000000000..96e03e0af1 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/stacktrace/stacktrace.cc @@ -0,0 +1,286 @@ +/* + * Copyright 2019 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/native_api/stacktrace/stacktrace.h" + +#include <dlfcn.h> +#include <errno.h> +#include <linux/futex.h> +#include <sys/ptrace.h> +#include <sys/ucontext.h> +#include <syscall.h> +#include <ucontext.h> +#include <unistd.h> +#include <unwind.h> +#include <atomic> + +// ptrace.h is polluting the namespace. Clean up to avoid conflicts with rtc. +#if defined(DS) +#undef DS +#endif + +#include "absl/base/attributes.h" +#include "rtc_base/logging.h" +#include "rtc_base/strings/string_builder.h" +#include "rtc_base/synchronization/mutex.h" + +namespace webrtc { + +namespace { + +// Maximum stack trace depth we allow before aborting. +constexpr size_t kMaxStackSize = 100; +// Signal that will be used to interrupt threads. SIGURG ("Urgent condition on +// socket") is chosen because Android does not set up a specific handler for +// this signal. +constexpr int kSignal = SIGURG; + +// Note: This class is only meant for use within this file, and for the +// simplified use case of a single Wait() and a single Signal(), followed by +// discarding the object (never reused). +// This is a replacement of rtc::Event that is async-safe and doesn't use +// pthread api. This is necessary since signal handlers cannot allocate memory +// or use pthread api. This class is ported from Chromium. +class AsyncSafeWaitableEvent { + public: + AsyncSafeWaitableEvent() { + std::atomic_store_explicit(&futex_, 0, std::memory_order_release); + } + + ~AsyncSafeWaitableEvent() {} + + // Returns false in the event of an error and errno is set to indicate the + // cause of the error. + bool Wait() { + // futex() can wake up spuriously if this memory address was previously used + // for a pthread mutex. So, also check the condition. + while (true) { + int res = syscall(SYS_futex, &futex_, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, + nullptr, nullptr, 0); + if (std::atomic_load_explicit(&futex_, std::memory_order_acquire) != 0) + return true; + if (res != 0) + return false; + } + } + + void Signal() { + std::atomic_store_explicit(&futex_, 1, std::memory_order_release); + syscall(SYS_futex, &futex_, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1, nullptr, + nullptr, 0); + } + + private: + std::atomic<int> futex_; +}; + +// Struct to store the arguments to the signal handler. +struct SignalHandlerOutputState { + // This function is called iteratively for each stack trace element and stores + // the element in the array from `unwind_output_state`. + static _Unwind_Reason_Code UnwindBacktrace( + struct _Unwind_Context* unwind_context, + void* unwind_output_state); + + // This event is signalled when signal handler is done executing. + AsyncSafeWaitableEvent signal_handler_finish_event; + // Running counter of array index below. + size_t stack_size_counter = 0; + // Array storing the stack trace. + uintptr_t addresses[kMaxStackSize]; +}; + +// This function is called iteratively for each stack trace element and stores +// the element in the array from `unwind_output_state`. +_Unwind_Reason_Code SignalHandlerOutputState::UnwindBacktrace( + struct _Unwind_Context* unwind_context, + void* unwind_output_state) { + SignalHandlerOutputState* const output_state = + static_cast<SignalHandlerOutputState*>(unwind_output_state); + + // Abort if output state is corrupt. + if (output_state == nullptr) + return _URC_END_OF_STACK; + + // Avoid overflowing the stack trace array. + if (output_state->stack_size_counter >= kMaxStackSize) + return _URC_END_OF_STACK; + + // Store the instruction pointer in the array. Subtract 2 since we want to get + // the call instruction pointer, not the return address which is the + // instruction after. + output_state->addresses[output_state->stack_size_counter] = + _Unwind_GetIP(unwind_context) - 2; + ++output_state->stack_size_counter; + + return _URC_NO_REASON; +} + +class GlobalStackUnwinder { + public: + static GlobalStackUnwinder& Get() { + static GlobalStackUnwinder* const instance = new GlobalStackUnwinder(); + return *instance; + } + const char* CaptureRawStacktrace(int pid, + int tid, + SignalHandlerOutputState* params); + + private: + GlobalStackUnwinder() { current_output_state_.store(nullptr); } + + // Temporarily installed signal handler. + static void SignalHandler(int signum, siginfo_t* info, void* ptr); + + Mutex mutex_; + + // Accessed by signal handler. + static std::atomic<SignalHandlerOutputState*> current_output_state_; + // A signal handler mustn't use locks. + static_assert(std::atomic<SignalHandlerOutputState*>::is_always_lock_free); +}; + +std::atomic<SignalHandlerOutputState*> + GlobalStackUnwinder::current_output_state_; + +// This signal handler is exectued on the interrupted thread. +void GlobalStackUnwinder::SignalHandler(int signum, + siginfo_t* info, + void* ptr) { + // This should have been set by the thread requesting the stack trace. + SignalHandlerOutputState* signal_handler_output_state = + current_output_state_.load(); + if (signal_handler_output_state != nullptr) { + _Unwind_Backtrace(&SignalHandlerOutputState::UnwindBacktrace, + signal_handler_output_state); + signal_handler_output_state->signal_handler_finish_event.Signal(); + } +} + +// Temporarily change the signal handler to a function that records a raw stack +// trace and interrupt the given tid. This function will block until the output +// thread stack trace has been stored in `params`. The return value is an error +// string on failure and null on success. +const char* GlobalStackUnwinder::CaptureRawStacktrace( + int pid, + int tid, + SignalHandlerOutputState* params) { + // This function is under a global lock since we are changing the signal + // handler and using global state for the output. The lock is to ensure only + // one thread at a time gets captured. The lock also means we need to be very + // careful with what statements we put in this function, and we should even + // avoid logging here. + struct sigaction act; + struct sigaction old_act; + memset(&act, 0, sizeof(act)); + act.sa_sigaction = &SignalHandler; + act.sa_flags = SA_RESTART | SA_SIGINFO; + sigemptyset(&act.sa_mask); + + MutexLock loch(&mutex_); + current_output_state_.store(params); + + if (sigaction(kSignal, &act, &old_act) != 0) + return "Failed to change signal action"; + + // Interrupt the thread which will execute SignalHandler() on the given + // thread. + if (tgkill(pid, tid, kSignal) != 0) + return "Failed to interrupt thread"; + + // Wait until the thread is done recording its stack trace. + if (!params->signal_handler_finish_event.Wait()) + return "Failed to wait for thread to finish stack trace"; + + // Restore previous signal handler. + sigaction(kSignal, &old_act, /* old_act= */ nullptr); + + return nullptr; +} + +// Translate addresses into symbolic information using dladdr(). +std::vector<StackTraceElement> FormatStackTrace( + const SignalHandlerOutputState& params) { + std::vector<StackTraceElement> stack_trace; + for (size_t i = 0; i < params.stack_size_counter; ++i) { + const uintptr_t address = params.addresses[i]; + + Dl_info dl_info = {}; + if (!dladdr(reinterpret_cast<void*>(address), &dl_info)) { + RTC_LOG(LS_WARNING) + << "Could not translate address to symbolic information for address " + << address << " at stack depth " << i; + continue; + } + + StackTraceElement stack_trace_element; + stack_trace_element.shared_object_path = dl_info.dli_fname; + stack_trace_element.relative_address = static_cast<uint32_t>( + address - reinterpret_cast<uintptr_t>(dl_info.dli_fbase)); + stack_trace_element.symbol_name = dl_info.dli_sname; + + stack_trace.push_back(stack_trace_element); + } + + return stack_trace; +} + +} // namespace + +std::vector<StackTraceElement> GetStackTrace(int tid) { + // Only a thread itself can unwind its stack, so we will interrupt the given + // tid with a custom signal handler in order to unwind its stack. The stack + // will be recorded to `params` through the use of the global pointer + // `g_signal_handler_param`. + SignalHandlerOutputState params; + + const char* error_string = + GlobalStackUnwinder::Get().CaptureRawStacktrace(getpid(), tid, ¶ms); + if (error_string != nullptr) { + RTC_LOG(LS_ERROR) << error_string << ". tid: " << tid + << ". errno: " << errno; + return {}; + } + if (params.stack_size_counter >= kMaxStackSize) { + RTC_LOG(LS_WARNING) << "Stack trace for thread " << tid << " was truncated"; + } + return FormatStackTrace(params); +} + +std::vector<StackTraceElement> GetStackTrace() { + SignalHandlerOutputState params; + _Unwind_Backtrace(&SignalHandlerOutputState::UnwindBacktrace, ¶ms); + if (params.stack_size_counter >= kMaxStackSize) { + RTC_LOG(LS_WARNING) << "Stack trace was truncated"; + } + return FormatStackTrace(params); +} + +std::string StackTraceToString( + const std::vector<StackTraceElement>& stack_trace) { + rtc::StringBuilder string_builder; + + for (size_t i = 0; i < stack_trace.size(); ++i) { + const StackTraceElement& stack_trace_element = stack_trace[i]; + string_builder.AppendFormat( + "#%02zu pc %08x %s", i, + static_cast<uint32_t>(stack_trace_element.relative_address), + stack_trace_element.shared_object_path); + // The symbol name is only available for unstripped .so files. + if (stack_trace_element.symbol_name != nullptr) + string_builder.AppendFormat(" %s", stack_trace_element.symbol_name); + + string_builder.AppendFormat("\n"); + } + + return string_builder.Release(); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/stacktrace/stacktrace.h b/third_party/libwebrtc/sdk/android/native_api/stacktrace/stacktrace.h new file mode 100644 index 0000000000..4cae1a58dd --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/stacktrace/stacktrace.h @@ -0,0 +1,45 @@ +/* + * Copyright 2019 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_STACKTRACE_STACKTRACE_H_ +#define SDK_ANDROID_NATIVE_API_STACKTRACE_STACKTRACE_H_ + +#include <string> +#include <vector> + +namespace webrtc { + +struct StackTraceElement { + // Pathname of shared object (.so file) that contains address. + const char* shared_object_path; + // Execution address relative to the .so base address. This matches the + // addresses you get with "nm", "objdump", and "ndk-stack", as long as the + // code is compiled with position-independent code. Android requires + // position-independent code since Lollipop. + uint32_t relative_address; + // Name of symbol whose definition overlaps the address. This value is null + // when symbol names are stripped. + const char* symbol_name; +}; + +// Utility to unwind stack for a given thread on Android ARM devices. This works +// on top of unwind.h and unwinds native (C++) stack traces only. +std::vector<StackTraceElement> GetStackTrace(int tid); + +// Unwind the stack of the current thread. +std::vector<StackTraceElement> GetStackTrace(); + +// Get a string representation of the stack trace in a format ndk-stack accepts. +std::string StackTraceToString( + const std::vector<StackTraceElement>& stack_trace); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_STACKTRACE_STACKTRACE_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/video/video_source.cc b/third_party/libwebrtc/sdk/android/native_api/video/video_source.cc new file mode 100644 index 0000000000..e967c2a465 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/video/video_source.cc @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018 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/native_api/video/video_source.h" + +#include "sdk/android/src/jni/android_video_track_source.h" +#include "sdk/android/src/jni/native_capturer_observer.h" + +namespace webrtc { + +namespace { + +// Hides full jni::AndroidVideoTrackSource interface and provides an instance of +// NativeCapturerObserver associated with the video source. Does not extend +// AndroidVideoTrackSource to avoid diamond inheritance on +// VideoTrackSourceInterface. +class JavaVideoTrackSourceImpl : public JavaVideoTrackSourceInterface { + public: + JavaVideoTrackSourceImpl(JNIEnv* env, + rtc::Thread* signaling_thread, + bool is_screencast, + bool align_timestamps) + : android_video_track_source_( + rtc::make_ref_counted<jni::AndroidVideoTrackSource>( + signaling_thread, + env, + is_screencast, + align_timestamps)), + native_capturer_observer_(jni::CreateJavaNativeCapturerObserver( + env, + android_video_track_source_)) {} + + ScopedJavaLocalRef<jobject> GetJavaVideoCapturerObserver( + JNIEnv* env) override { + return ScopedJavaLocalRef<jobject>(env, native_capturer_observer_); + } + + // Delegate VideoTrackSourceInterface methods to android_video_track_source_. + void RegisterObserver(ObserverInterface* observer) override { + android_video_track_source_->RegisterObserver(observer); + } + + void UnregisterObserver(ObserverInterface* observer) override { + android_video_track_source_->UnregisterObserver(observer); + } + + SourceState state() const override { + return android_video_track_source_->state(); + } + + bool remote() const override { return android_video_track_source_->remote(); } + + void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, + const rtc::VideoSinkWants& wants) override { + // The method is defined private in the implementation so we have to access + // it through the interface... + static_cast<VideoTrackSourceInterface*>(android_video_track_source_.get()) + ->AddOrUpdateSink(sink, wants); + } + + void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override { + // The method is defined private in the implementation so we have to access + // it through the interface... + static_cast<VideoTrackSourceInterface*>(android_video_track_source_.get()) + ->RemoveSink(sink); + } + + bool is_screencast() const override { + return android_video_track_source_->is_screencast(); + } + + absl::optional<bool> needs_denoising() const override { + return android_video_track_source_->needs_denoising(); + } + + bool GetStats(Stats* stats) override { + // The method is defined private in the implementation so we have to access + // it through the interface... + return static_cast<VideoTrackSourceInterface*>( + android_video_track_source_.get()) + ->GetStats(stats); + } + + private: + // Encoded sinks not implemented for JavaVideoTrackSourceImpl. + bool SupportsEncodedOutput() const override { return false; } + void GenerateKeyFrame() override {} + void AddEncodedSink( + rtc::VideoSinkInterface<webrtc::RecordableEncodedFrame>* sink) override {} + void RemoveEncodedSink( + rtc::VideoSinkInterface<webrtc::RecordableEncodedFrame>* sink) override {} + + rtc::scoped_refptr<jni::AndroidVideoTrackSource> android_video_track_source_; + ScopedJavaGlobalRef<jobject> native_capturer_observer_; +}; + +} // namespace + +rtc::scoped_refptr<JavaVideoTrackSourceInterface> CreateJavaVideoSource( + JNIEnv* jni, + rtc::Thread* signaling_thread, + bool is_screencast, + bool align_timestamps) { + return rtc::make_ref_counted<JavaVideoTrackSourceImpl>( + jni, signaling_thread, is_screencast, align_timestamps); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/video/video_source.h b/third_party/libwebrtc/sdk/android/native_api/video/video_source.h new file mode 100644 index 0000000000..d46f3e8f53 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/video/video_source.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_VIDEO_VIDEO_SOURCE_H_ +#define SDK_ANDROID_NATIVE_API_VIDEO_VIDEO_SOURCE_H_ + +#include <jni.h> + +#include "api/media_stream_interface.h" +#include "rtc_base/thread.h" +#include "sdk/android/native_api/jni/scoped_java_ref.h" + +namespace webrtc { + +// Interface for class that implements VideoTrackSourceInterface and provides a +// Java object that can be used to feed frames to the source. +class JavaVideoTrackSourceInterface : public VideoTrackSourceInterface { + public: + // Returns CapturerObserver object that can be used to feed frames to the + // video source. + virtual ScopedJavaLocalRef<jobject> GetJavaVideoCapturerObserver( + JNIEnv* env) = 0; +}; + +// Creates an instance of JavaVideoTrackSourceInterface, +rtc::scoped_refptr<JavaVideoTrackSourceInterface> CreateJavaVideoSource( + JNIEnv* env, + rtc::Thread* signaling_thread, + bool is_screencast, + bool align_timestamps); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_VIDEO_VIDEO_SOURCE_H_ diff --git a/third_party/libwebrtc/sdk/android/native_api/video/wrapper.cc b/third_party/libwebrtc/sdk/android/native_api/video/wrapper.cc new file mode 100644 index 0000000000..8faddc3b26 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/video/wrapper.cc @@ -0,0 +1,33 @@ +/* + * Copyright 2018 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/native_api/video/wrapper.h" + +#include <memory> + +#include "sdk/android/native_api/jni/scoped_java_ref.h" +#include "sdk/android/src/jni/video_frame.h" +#include "sdk/android/src/jni/video_sink.h" + +namespace webrtc { + +std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> JavaToNativeVideoSink( + JNIEnv* jni, + jobject video_sink) { + return std::make_unique<jni::VideoSinkWrapper>( + jni, JavaParamRef<jobject>(video_sink)); +} + +ScopedJavaLocalRef<jobject> NativeToJavaVideoFrame(JNIEnv* jni, + const VideoFrame& frame) { + return jni::NativeToJavaVideoFrame(jni, frame); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/sdk/android/native_api/video/wrapper.h b/third_party/libwebrtc/sdk/android/native_api/video/wrapper.h new file mode 100644 index 0000000000..e32cf34806 --- /dev/null +++ b/third_party/libwebrtc/sdk/android/native_api/video/wrapper.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 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. + */ + +#ifndef SDK_ANDROID_NATIVE_API_VIDEO_WRAPPER_H_ +#define SDK_ANDROID_NATIVE_API_VIDEO_WRAPPER_H_ + +#include <jni.h> +#include <memory> + +#include "api/media_stream_interface.h" +#include "api/video/video_frame.h" +#include "sdk/android/native_api/jni/scoped_java_ref.h" + +namespace webrtc { + +// Creates an instance of rtc::VideoSinkInterface<VideoFrame> from Java +// VideoSink. +std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> JavaToNativeVideoSink( + JNIEnv* jni, + jobject video_sink); + +// Creates a Java VideoFrame object from a native VideoFrame. The returned +// object has to be released by calling release. +ScopedJavaLocalRef<jobject> NativeToJavaVideoFrame(JNIEnv* jni, + const VideoFrame& frame); + +} // namespace webrtc + +#endif // SDK_ANDROID_NATIVE_API_VIDEO_WRAPPER_H_ |