Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch/android/external audio processing #37

Merged
merged 48 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
d88822e
[PBE-5300] add android-external-audio-processing
kanat Aug 14, 2024
282c5d5
[PBE-5300] add external_processor.cc
kanat Aug 14, 2024
b48fffe
[PBE-5300] clean up jni
kanat Aug 14, 2024
cf33646
[PBE-5300] clean java layer
kanat Aug 14, 2024
16e7b88
[PBE-5300] rename files & classes
kanat Aug 14, 2024
8e1d579
[PBE-5300] add external processor
kanat Aug 15, 2024
c022c61
[PBE-5300] fix java compilation
kanat Aug 15, 2024
7df3456
[PBE-5300] remove NonNull annotation
kanat Aug 15, 2024
edc1443
[PBE-5300] add missing include
kanat Aug 15, 2024
da080d3
[PBE-5300] pass external_processor
kanat Aug 15, 2024
a045a8d
[PBE-5300] fix unguarded headers
kanat Aug 15, 2024
8273695
[PBE-5300] fix JNI_ExternalAudioProcessingFactory params
kanat Aug 15, 2024
bb719d1
[PBE-5300] change include order
kanat Aug 15, 2024
50de2bf
[PBE-5300] jni experiment 1
kanat Aug 15, 2024
13d5db4
[PBE-5300] jni experiment 2
kanat Aug 16, 2024
1e85068
[PBE-5300] jni experiment 3
kanat Aug 16, 2024
62aab5e
[PBE-5300] jni experiment 4
kanat Aug 16, 2024
c54e717
[PBE-5300] jni experiment 5
kanat Aug 16, 2024
806562f
[PBE-5300] jni experiment 6
kanat Aug 16, 2024
24a9af2
[PBE-5300] jni experiment 7
kanat Aug 16, 2024
4c25949
[PBE-5300] jni experiment 8
kanat Aug 16, 2024
aa7db14
[PBE-5300] jni experiment 9
kanat Aug 16, 2024
926d6eb
[PBE-5300] jni experiment 10
kanat Aug 16, 2024
102442a
[PBE-5300] jni experiment 11
kanat Aug 16, 2024
e076a5d
[PBE-5300] jni experiment 12
kanat Aug 16, 2024
6b0d0cd
[PBE-5300] jni experiment 13
kanat Aug 16, 2024
bc17383
[PBE-5300] jni experiment 14
kanat Aug 16, 2024
261f48e
[PBE-5300] jni experiment 15
kanat Aug 16, 2024
3bab90b
[PBE-5300] add dynamic processing
kanat Aug 19, 2024
eb3cec4
fix nativeGetInstance
kanat Aug 19, 2024
e120e21
rename to nativeGetApm
kanat Aug 19, 2024
37af1c6
fix compilation
kanat Aug 19, 2024
42492df
hardcode name
kanat Aug 19, 2024
61f5bb0
fix jni compilation
kanat Aug 19, 2024
e9c6b2a
fix compilation issue
kanat Aug 19, 2024
13ca69f
fix dynamic_processing.cc
kanat Aug 19, 2024
2e02164
rename to dynamic_apm_ptr
kanat Aug 19, 2024
3b1bcf3
convert dynamic to external
kanat Aug 21, 2024
34d1bc9
fix compilation issues
kanat Aug 21, 2024
e35aec7
fix nativeDestroyAudioProcessingModule return type
kanat Aug 21, 2024
a4a2f7a
include external_processor_loader
kanat Aug 21, 2024
5b2cb2a
update BUILD.gn
kanat Aug 21, 2024
91de7c2
fix loadExternalProcessor return type
kanat Aug 21, 2024
abe3bd2
define Create & Destroy
kanat Aug 21, 2024
48c1f02
delete loader include
kanat Aug 21, 2024
5b77b04
fix Load to Create
kanat Aug 21, 2024
ff2ad85
migrate to external functions
kanat Aug 22, 2024
60947ed
clean up logs
kanat Sep 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions extensions/android-external-audio-processing/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import("../../webrtc.gni")
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")

rtc_library("external_processing") {
visibility = [ "*" ]
configs += [ "../../modules/audio_processing:apm_debug_dump", ]
configs += [ "//build/config/android:hide_all_but_jni" ]
defines = ["WEBRTC_ANDROID", "WEBRTC_POSIX",]
sources = [
"include/external_processor.hpp",
"external_processing.hpp",
"external_processing.cc",
"external_processing_factory_jni.cc",
]
lib_dirs = []
deps = [
":generated_external_jni",
":external_java",
"../../rtc_base:logging",
"../../sdk/android:native_api_jni",
"../../modules/audio_processing:audio_processing",
]
}

rtc_android_library("external_java") {
visibility = [ "*" ]
sources = [
"java/src/org/webrtc/ExternalAudioProcessingFactory.java",
]
deps = ["//sdk/android:peerconnection_java",]
}

generate_jni("generated_external_jni") {
sources = [
"java/src/org/webrtc/ExternalAudioProcessingFactory.java",
]
namespace = "external"
jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h"
}
177 changes: 177 additions & 0 deletions extensions/android-external-audio-processing/external_processing.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#include "external_processing.hpp"

#include <dlfcn.h>
#include <syslog.h>

#include "rtc_base/time_utils.h"

namespace external {

ExternalProcessing* ExternalProcessing::m_instance = nullptr;

ExternalProcessing::ExternalProcessing() {
::syslog(LOG_INFO, "ExternalProcessing: #Constructor;");
}

ExternalProcessing::~ExternalProcessing() {
::syslog(LOG_INFO, "ExternalProcessing: #Destructor;");

Destroy();
}

bool ExternalProcessing::Create(const char* libname) {
::syslog(LOG_INFO, "ExternalProcessing: #Create; libname: %s", libname);

// Load the shared library
dlerror(); // Clear any existing errors
void* handle = dlopen(libname, RTLD_LAZY);
if (!handle) {
::syslog(LOG_ERR, "ExternalProcessing: #Create; Failed to load library: %s",
dlerror());
return false;
}

// Load external processor functions
for (size_t functionId = 0; functionId < kFunctionCount; ++functionId) {
const char* functionName = kFunctionNames[functionId];
syslog(LOG_INFO, "ExternalProcessing: #Create; Loading function: %s",
functionName);
void* functionPtr = dlsym(handle, functionName);
const char* dlsym_error = dlerror();
if (dlsym_error) {
syslog(LOG_ERR,
"ExternalProcessing: #Create; Failed to load the function: %s",
dlsym_error);
return false;
}
m_functionPointers[functionId] = functionPtr;
}

void* createPtr = m_functionPointers[FunctionId::ExternalProcessorCreate];
if (!createPtr) {
::syslog(LOG_ERR,
"ExternalProcessing: #Create; Failed to access "
"ExternalProcessorCreate function");
dlclose(handle);
return false;
}

auto createFunc =
reinterpret_cast<ExternalProcessorCreateFuncType>(createPtr);
if (!createFunc()) {
::syslog(LOG_ERR,
"ExternalProcessing: #Create; Failed to invoke "
"ExternalProcessorCreate function");
dlclose(handle);
return false;
}

m_handle = handle;

::syslog(LOG_INFO, "ExternalProcessing: #Create; completed successfully");

return true;
}

bool ExternalProcessing::Destroy() {
::syslog(LOG_INFO, "ExternalProcessing: #Destroy;");

void* destroyPtr = m_functionPointers[FunctionId::ExternalProcessorDestroy];
if (destroyPtr) {
::syslog(LOG_INFO,
"ExternalProcessing: #Destroy; Invoke ExternalProcessorDestroy "
"function");

auto destroyFunc =
reinterpret_cast<ExternalProcessorDestroyFuncType>(destroyPtr);
if (destroyFunc()) {
::syslog(LOG_INFO,
"ExternalProcessing: #Destroy; Invoked ExternalProcessorDestroy "
"successfully");
}
}
for (auto& functionPtr : m_functionPointers) {
functionPtr = nullptr;
}
if (m_handle) {
dlclose(m_handle);
m_handle = nullptr;
}

return true;
}

void ExternalProcessing::Initialize(int sample_rate_hz, int num_channels) {
if (m_functionPointers.size() <=
static_cast<size_t>(FunctionId::ExternalProcessorInitialize)) {
::syslog(LOG_ERR,
"ExternalProcessing: #Initialize; m_functionPointers is not large "
"enough");
return;
}
void* initializePtr =
m_functionPointers[FunctionId::ExternalProcessorInitialize];
if (!initializePtr) {
::syslog(LOG_ERR,
"ExternalProcessing: #Initialize; Failed to access "
"ExternalProcessorInitialize function");
return;
}

auto initializeFunc =
reinterpret_cast<ExternalProcessorInitializeFuncType>(initializePtr);
if (!initializeFunc(sample_rate_hz, num_channels)) {
::syslog(LOG_ERR,
"ExternalProcessing: #Initialize; Failed to invoke "
"ExternalProcessorInitialize function");
return;
}
::syslog(LOG_INFO,
"ExternalProcessing: #Initialize; Invoked "
"ExternalProcessorInitialize; sample_rate_hz: %i, "
"num_channels: %i",
sample_rate_hz, num_channels);
}

void ExternalProcessing::Process(webrtc::AudioBuffer* audio) {
float* const* channels = audio->channels();
size_t num_frames = audio->num_frames();
size_t num_bands = audio->num_bands();
size_t num_channels = audio->num_channels();

if (m_functionPointers.size() <=
static_cast<size_t>(FunctionId::ExternalProcessorProcessFrame)) {
::syslog(
LOG_ERR,
"ExternalProcessing: #Process; m_functionPointers is not large enough");
return;
}
void* processPtr =
m_functionPointers[FunctionId::ExternalProcessorProcessFrame];
if (!processPtr) {
::syslog(LOG_ERR,
"ExternalProcessing: #Process; Failed to access "
"ExternalProcessorProcessFrame function");
return;
}

auto processFunc =
reinterpret_cast<ExternalProcessorProcessFrameFuncType>(processPtr);
if (!processFunc(channels, num_frames, num_bands, num_channels)) {
::syslog(LOG_ERR,
"ExternalProcessing: #Process; Failed to invoke "
"ExternalProcessorProcessFrame function");
return;
}
}

std::string ExternalProcessing::ToString() const {
return "ExternalProcessing";
}

void ExternalProcessing::SetRuntimeSetting(
webrtc::AudioProcessing::RuntimeSetting setting) {
::syslog(LOG_INFO, "ExternalProcessing: #SetRuntimeSetting;");
}

} // end of namespace external
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef EXTERNAL_PROCESSING_HPP
#define EXTERNAL_PROCESSING_HPP

#include <syslog.h>

#include "include/external_processor.hpp"

#include "modules/audio_processing/audio_buffer.h"
#include "modules/audio_processing/audio_processing_impl.h"
#include "modules/audio_processing/include/audio_processing.h"

namespace external {

class ExternalProcessing : public webrtc::CustomProcessing {
public:
ExternalProcessing(const ExternalProcessing&) = delete;
ExternalProcessing(ExternalProcessing&&) = delete;
ExternalProcessing& operator=(const ExternalProcessing&) = delete;
ExternalProcessing& operator=(ExternalProcessing&&) = delete;
~ExternalProcessing();

static ExternalProcessing* getInstance() {
if (m_instance == nullptr) {
m_instance = new ExternalProcessing();
}
return m_instance;
}

bool Create(const char* libname);

bool Destroy();

void Initialize(int sample_rate_hz, int num_channels) override;
void Process(webrtc::AudioBuffer* audio) override;
std::string ToString() const override;
void SetRuntimeSetting(
webrtc::AudioProcessing::RuntimeSetting setting) override;

private:
ExternalProcessing();

void* m_handle = nullptr;
std::array<void *, kFunctionCount> m_functionPointers = {};

static ExternalProcessing* m_instance;
};
} // namespace external

#endif // EXTERNAL_PROCESSING_HPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <syslog.h>

#include <cstring>

#include "extensions/android-external-audio-processing/generated_external_jni/ExternalAudioProcessingFactory_jni.h"
#include "external_processing.hpp"
#include "rtc_base/checks.h"
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/thread.h"
#include "rtc_base/time_utils.h"
#include "sdk/android/src/jni/jni_helpers.h"

namespace external {

webrtc::AudioProcessing* apm_ptr = nullptr;

static jlong JNI_ExternalAudioProcessingFactory_CreateAudioProcessingModule(
JNIEnv* env,
const webrtc::JavaParamRef<jstring>& libnameRef
) {

if (libnameRef.is_null()) {
::syslog(LOG_ERR, "EXTERNAL-JNI: #GetApm; libname is null");
return 0;
}

const char* libname = env->GetStringUTFChars(libnameRef.obj(), nullptr);

::syslog(LOG_INFO, "EXTERNAL-JNI: #GetApm; libname: %s", libname);

auto instance = ExternalProcessing::getInstance();
if (!instance->Create(libname)) {
::syslog(LOG_ERR, "EXTERNAL-JNI: #GetApm; Failed to load external processor");
env->ReleaseStringUTFChars(libnameRef.obj(), libname);
return 0;
}

env->ReleaseStringUTFChars(libnameRef.obj(), libname);

std::unique_ptr<webrtc::CustomProcessing> external_processing(instance);
auto apm = webrtc::AudioProcessingBuilder()
.SetCapturePostProcessing(std::move(external_processing))
.Create();
webrtc::AudioProcessing::Config config;
config.echo_canceller.enabled = false;
config.echo_canceller.mobile_mode = true;
apm->ApplyConfig(config);
apm_ptr = apm.release();
return webrtc::jni::jlongFromPointer(apm_ptr);
}

static void JNI_ExternalAudioProcessingFactory_DestroyAudioProcessingModule(
JNIEnv* env
) {
ExternalProcessing::getInstance()->Destroy();
delete apm_ptr;
apm_ptr = nullptr;
}

} // end of namespace external
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef EXTERNAL_PROCESSOR_HPP
#define EXTERNAL_PROCESSOR_HPP

#include <cstdint>
#include <array>

namespace external {

static constexpr unsigned int kFunctionCount = 4;

// Function ID struct
struct FunctionId {
static constexpr unsigned int ExternalProcessorCreate = 0;
static constexpr unsigned int ExternalProcessorInitialize = 1;
static constexpr unsigned int ExternalProcessorProcessFrame = 2;
static constexpr unsigned int ExternalProcessorDestroy = 3;
};

static constexpr std::array<const char *, kFunctionCount> kFunctionNames =
{
"ExternalProcessorCreate",
"ExternalProcessorInitialize",
"ExternalProcessorProcessFrame",
"ExternalProcessorDestroy"
};

// Function type definitions
using ExternalProcessorCreateFuncType = bool(*)();
using ExternalProcessorInitializeFuncType = bool(*)(int sample_rate_hz, int num_channels);
using ExternalProcessorProcessFrameFuncType = bool(*)(float* const* channels,
size_t num_frames,
size_t num_bands,
size_t num_channels);
using ExternalProcessorDestroyFuncType = bool(*)();

extern "C" bool ExternalProcessorCreate();

extern "C" bool ExternalProcessorInitialize(int sample_rate_hz,
int num_channels);

extern "C" bool ExternalProcessorProcessFrame(float* const* channels,
size_t num_frames,
size_t num_bands,
size_t num_channels);

extern "C" bool ExternalProcessorDestroy();

} // namespace external

#endif // EXTERNAL_PROCESSOR_HPP
Loading