Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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, ¶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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
|
|
@ -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
|
||||
|
|
@ -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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue