Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 14:04:28 +01:00
parent 81b91f4139
commit f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions

View file

@ -0,0 +1,235 @@
/*
* 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/native_api/jni/application_context_provider.h"
#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 "sdk/android/src/jni/jvm.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));
}
rtc::scoped_refptr<AudioDeviceModule>
CreateJavaInputAndAAudioOutputAudioDeviceModule(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));
return CreateAudioDeviceModuleFromInputAndOutput(
AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio,
false /* use_stereo_input */, false /* use_stereo_output */,
jni::kLowLatencyModeDelayEstimateInMilliseconds, std::move(audio_input),
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));
}
rtc::scoped_refptr<AudioDeviceModule> CreateAndroidAudioDeviceModule(
AudioDeviceModule::AudioLayer audio_layer) {
auto env = AttachCurrentThreadIfNeeded();
auto j_context = webrtc::GetAppContext(env);
// Select best possible combination of audio layers.
if (audio_layer == AudioDeviceModule::kPlatformDefaultAudio) {
#if defined(WEBRTC_AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
// AAudio based audio for both input and output.
audio_layer = AudioDeviceModule::kAndroidAAudioAudio;
#else
if (jni::IsLowLatencyInputSupported(env, j_context) &&
jni::IsLowLatencyOutputSupported(env, j_context)) {
// Use OpenSL ES for both playout and recording.
audio_layer = AudioDeviceModule::kAndroidOpenSLESAudio;
} else if (jni::IsLowLatencyOutputSupported(env, j_context) &&
!jni::IsLowLatencyInputSupported(env, j_context)) {
// Use OpenSL ES for output on devices that only supports the
// low-latency output audio path.
audio_layer = AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio;
} else {
// Use Java-based audio in both directions when low-latency output is
// not supported.
audio_layer = AudioDeviceModule::kAndroidJavaAudio;
}
#endif
}
switch (audio_layer) {
case AudioDeviceModule::kAndroidJavaAudio:
// Java audio for both input and output audio.
return CreateJavaAudioDeviceModule(env, j_context.obj());
case AudioDeviceModule::kAndroidOpenSLESAudio:
// OpenSL ES based audio for both input and output audio.
return CreateOpenSLESAudioDeviceModule(env, j_context.obj());
case AudioDeviceModule::kAndroidJavaInputAndOpenSLESOutputAudio:
// Java audio for input and OpenSL ES for output audio (i.e. mixed APIs).
// This combination provides low-latency output audio and at the same
// time support for HW AEC using the AudioRecord Java API.
return CreateJavaInputAndOpenSLESOutputAudioDeviceModule(
env, j_context.obj());
#if defined(WEBRTC_AUDIO_DEVICE_INCLUDE_ANDROID_AAUDIO)
case AudioDeviceModule::kAndroidAAudioAudio:
// AAudio based audio for both input and output.
return CreateAAudioAudioDeviceModule(env, j_context.obj());
case AudioDeviceModule::kAndroidJavaInputAndAAudioOutputAudio:
// Java audio for input and AAudio for output audio (i.e. mixed APIs).
return CreateJavaInputAndAAudioOutputAudioDeviceModule(
env, j_context.obj());
#endif
default:
return nullptr;
}
}
} // namespace webrtc

View file

@ -0,0 +1,49 @@
/*
* 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);
rtc::scoped_refptr<AudioDeviceModule>
CreateJavaInputAndAAudioOutputAudioDeviceModule(
JNIEnv* env,
jobject application_context);
rtc::scoped_refptr<AudioDeviceModule> CreateAndroidAudioDeviceModule(
AudioDeviceModule::AudioLayer audio_layer);
} // namespace webrtc
#endif // SDK_ANDROID_NATIVE_API_AUDIO_DEVICE_MODULE_AUDIO_DEVICE_ANDROID_H_

View file

@ -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

View file

@ -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_

View file

@ -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

View file

@ -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.
*/
#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_

View file

@ -0,0 +1,22 @@
/*
* 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/jni/application_context_provider.h"
#include "sdk/android/generated_native_api_jni/ApplicationContextProvider_jni.h"
#include "sdk/android/native_api/jni/scoped_java_ref.h"
namespace webrtc {
ScopedJavaLocalRef<jobject> GetAppContext(JNIEnv* jni) {
return ScopedJavaLocalRef<jobject>(
jni::Java_ApplicationContextProvider_getApplicationContext(jni));
}
} // namespace webrtc

View file

@ -0,0 +1,21 @@
/*
* 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_JNI_APPLICATION_CONTEXT_PROVIDER_H_
#define SDK_ANDROID_NATIVE_API_JNI_APPLICATION_CONTEXT_PROVIDER_H_
#include "sdk/android/native_api/jni/scoped_java_ref.h"
namespace webrtc {
ScopedJavaLocalRef<jobject> GetAppContext(JNIEnv* jni);
} // namespace webrtc
#endif // SDK_ANDROID_NATIVE_API_JNI_APPLICATION_CONTEXT_PROVIDER_H_

View file

@ -0,0 +1,88 @@
/*
* 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* c_name) {
if (g_class_loader != nullptr) {
// The class loader will be null in the JNI code called from the ClassLoader
// ctor when we are bootstrapping ourself.
return g_class_loader->FindClass(env, c_name);
}
// jni_zero generated code uses dots instead of slashes.
// Convert to use slashes since that's what JNI's FindClass expects.
// See
// https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/jni/check_jni.cc;l=349;drc=0f62043c1670cd365aba1894ad8046cdfc1c905d
std::string name(c_name);
std::replace(name.begin(), name.end(), '.', '/');
return ScopedJavaLocalRef<jclass>(env, env->FindClass(name.c_str()));
}
} // namespace webrtc

View file

@ -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_

View file

@ -0,0 +1,402 @@
/*
* 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) {
#ifdef RTC_JNI_GENERATOR_LEGACY_SYMBOLS
return JNI_Boolean::Java_Boolean_ConstructorJLB_Z(env, b);
#else
return JNI_Boolean::Java_Boolean_Constructor__boolean(env, b);
#endif
}
ScopedJavaLocalRef<jobject> NativeToJavaDouble(JNIEnv* env, double d) {
#ifdef RTC_JNI_GENERATOR_LEGACY_SYMBOLS
return JNI_Double::Java_Double_ConstructorJLD_D(env, d);
#else
return JNI_Double::Java_Double_Constructor__double(env, d);
#endif
}
ScopedJavaLocalRef<jobject> NativeToJavaInteger(JNIEnv* jni, int32_t i) {
#ifdef RTC_JNI_GENERATOR_LEGACY_SYMBOLS
return JNI_Integer::Java_Integer_ConstructorJLI_I(jni, i);
#else
return JNI_Integer::Java_Integer_Constructor__int(jni, i);
#endif
}
ScopedJavaLocalRef<jobject> NativeToJavaLong(JNIEnv* env, int64_t u) {
#ifdef RTC_JNI_GENERATOR_LEGACY_SYMBOLS
return JNI_Long::Java_Long_ConstructorJLLO_J(env, u);
#else
return JNI_Long::Java_Long_Constructor__long(env, u);
#endif
}
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;
}
std::vector<float> JavaToNativeFloatArray(JNIEnv* env,
const JavaRef<jfloatArray>& jarray) {
// jfloat is a "machine-dependent native type" which represents a 32-bit
// float. C++ makes no guarantees about the size of floating point types, and
// some exotic architectures don't even have 32-bit floats (or even binary
// floats), but on all architectures we care about this is a float.
static_assert(std::is_same<float, jfloat>::value, "jfloat must be float");
float* array_ptr =
env->GetFloatArrayElements(jarray.obj(), /*isCopy=*/nullptr);
size_t array_length = env->GetArrayLength(jarray.obj());
std::vector<float> container(array_ptr, array_ptr + array_length);
env->ReleaseFloatArrayElements(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)
#ifdef RTC_JNI_GENERATOR_LEGACY_SYMBOLS
: env_(env),
j_list_(JNI_ArrayList::Java_ArrayList_ConstructorJUALI(env)) {}
#else
: env_(env), j_list_(JNI_ArrayList::Java_ArrayList_Constructor(env)) {
}
#endif
JavaListBuilder::~JavaListBuilder() = default;
void JavaListBuilder::add(const JavaRef<jobject>& element) {
#ifdef RTC_JNI_GENERATOR_LEGACY_SYMBOLS
JNI_ArrayList::Java_ArrayList_addZ_JUE(env_, j_list_, element);
#else
JNI_ArrayList::Java_ArrayList_add(env_, j_list_, element);
#endif
}
JavaMapBuilder::JavaMapBuilder(JNIEnv* env)
: env_(env),
#ifdef RTC_JNI_GENERATOR_LEGACY_SYMBOLS
j_map_(JNI_LinkedHashMap::Java_LinkedHashMap_ConstructorJULIHM(env)) {
}
#else
j_map_(JNI_LinkedHashMap::Java_LinkedHashMap_Constructor(env)) {
}
#endif
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(const 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

View file

@ -0,0 +1,368 @@
/*
* 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);
std::vector<float> JavaToNativeFloatArray(JNIEnv* env,
const JavaRef<jfloatArray>& 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(const 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_

View file

@ -0,0 +1,63 @@
/*
* 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_
#include <jni.h>
#include <cstdint>
// 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_

View file

@ -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

View file

@ -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_

View file

@ -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_

View file

@ -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

View file

@ -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_

View file

@ -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

View file

@ -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_

View file

@ -0,0 +1,287 @@
/*
* 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, &params);
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, &params);
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

View file

@ -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_

View file

@ -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

View file

@ -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_

View file

@ -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

View file

@ -0,0 +1,37 @@
/*
* 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_