From 1ab061a6901ca6c2c10c3a57938b861a1bfc4b72 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 12 May 2022 17:55:49 +0800 Subject: [PATCH] fix oboe --- build.rs | 11 +++- src/oboe.cc | 118 +++++++++++++++++++++++++++++++++++++++ src/oboe.patch | 147 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 src/oboe.cc create mode 100644 src/oboe.patch diff --git a/build.rs b/build.rs index d3cb36ac5..1f2245d7e 100644 --- a/build.rs +++ b/build.rs @@ -40,7 +40,7 @@ fn install_oboe() { } else { target_arch = "arm".to_owned(); } - let target = format!("{}-android-static", target_arch); + let target = format!("{}-android", target_arch); let vcpkg_root = std::env::var("VCPKG_ROOT").unwrap(); let mut path: std::path::PathBuf = vcpkg_root.into(); path.push("installed"); @@ -63,12 +63,17 @@ fn install_oboe() { } fn main() { + hbb_common::gen_version(); + install_oboe(); + // there is problem with cfg(target_os) in build.rs, so use our workaround + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); + if target_os == "android" || target_os == "ios" { + return; + } #[cfg(all(windows, feature = "inline"))] build_manifest(); #[cfg(windows)] build_windows(); #[cfg(target_os = "macos")] println!("cargo:rustc-link-lib=framework=ApplicationServices"); - hbb_common::gen_version(); - install_oboe(); } diff --git a/src/oboe.cc b/src/oboe.cc new file mode 100644 index 000000000..a3c8238a7 --- /dev/null +++ b/src/oboe.cc @@ -0,0 +1,118 @@ +#include +#include +#include +#include + +// I got link problem with std::mutex, so use pthread instead +class CThreadLock +{ +public: + CThreadLock(); + virtual ~CThreadLock(); + + void Lock(); + void Unlock(); + +private: + pthread_mutex_t mutexlock; +}; + +CThreadLock::CThreadLock() +{ + // init lock here + pthread_mutex_init(&mutexlock, 0); +} + +CThreadLock::~CThreadLock() +{ + // deinit lock here + pthread_mutex_destroy(&mutexlock); +} +void CThreadLock::Lock() +{ + // lock + pthread_mutex_lock(&mutexlock); +} +void CThreadLock::Unlock() +{ + // unlock + pthread_mutex_unlock(&mutexlock); +} + +class Player : public oboe::AudioStreamDataCallback +{ +public: + Player(int channels, int sample_rate) + { + this->channels = channels; + oboe::AudioStreamBuilder builder; + // The builder set methods can be chained for convenience. + builder.setSharingMode(oboe::SharingMode::Exclusive) + ->setPerformanceMode(oboe::PerformanceMode::LowLatency) + ->setChannelCount(channels) + ->setSampleRate(sample_rate) + ->setFormat(oboe::AudioFormat::Float) + ->setDataCallback(this) + ->openManagedStream(outStream); + // Typically, start the stream after querying some stream information, as well as some input from the user + outStream->requestStart(); + } + + ~Player() { + outStream->requestStop(); + } + + oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override + { + float *floatData = (float *)audioData; + int i = 0; + mtx.Lock(); + auto n = channels * numFrames; + for (; i < n && i < (int)buffer.size(); ++i, ++floatData) + { + *floatData = buffer.front(); + buffer.pop_front(); + } + mtx.Unlock(); + for (; i < n; ++i, ++floatData) + { + *floatData = 0; + } + return oboe::DataCallbackResult::Continue; + } + + void push(const float *v, int n) + { + mtx.Lock(); + for (auto i = 0; i < n; ++i, ++v) + buffer.push_back(*v); + // in case memory overuse + if (buffer.size() > 48 * 1024 * 120) + buffer.clear(); + mtx.Unlock(); + } + +private: + oboe::ManagedStream outStream; + int channels; + std::deque buffer; + CThreadLock mtx; +}; + +extern "C" +{ + void *create_oboe_player(int channels, int sample_rate) + { + return new Player(channels, sample_rate); + } + + void push_oboe_data(void *player, const float* v, int n) + { + static_cast(player)->push(v, n); + } + + void destroy_oboe_player(void *player) + { + delete static_cast(player); + } +} \ No newline at end of file diff --git a/src/oboe.patch b/src/oboe.patch new file mode 100644 index 000000000..8910afec6 --- /dev/null +++ b/src/oboe.patch @@ -0,0 +1,147 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 51a45b2..75be96a 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -60,7 +60,7 @@ set (oboe_sources + src/common/Version.cpp + ) + +-add_library(oboe ${oboe_sources}) ++ add_library(oboe STATIC ${oboe_sources}) + + # Specify directories which the compiler should look for headers + target_include_directories(oboe +@@ -91,4 +91,4 @@ install(TARGETS oboe + ARCHIVE DESTINATION lib/${ANDROID_ABI}) + + # Also install the headers +-install(DIRECTORY include/oboe DESTINATION include) +\ No newline at end of file ++install(DIRECTORY include/oboe DESTINATION include) +diff --git a/src/common/AudioStreamBuilder.cpp b/src/common/AudioStreamBuilder.cpp +index dffcd75..79984a4 100644 +--- a/src/common/AudioStreamBuilder.cpp ++++ b/src/common/AudioStreamBuilder.cpp +@@ -215,3 +215,122 @@ Result AudioStreamBuilder::openStream(std::shared_ptr &sharedStream + } + + } // namespace oboe ++ ++#include ++#include ++#include ++#include ++ ++// I got link problem with std::mutex, so use pthread instead ++class CThreadLock ++{ ++public: ++ CThreadLock(); ++ virtual ~CThreadLock(); ++ ++ void Lock(); ++ void Unlock(); ++ ++private: ++ pthread_mutex_t mutexlock; ++}; ++ ++CThreadLock::CThreadLock() ++{ ++ // init lock here ++ pthread_mutex_init(&mutexlock, 0); ++} ++ ++CThreadLock::~CThreadLock() ++{ ++ // deinit lock here ++ pthread_mutex_destroy(&mutexlock); ++} ++void CThreadLock::Lock() ++{ ++ // lock ++ pthread_mutex_lock(&mutexlock); ++} ++void CThreadLock::Unlock() ++{ ++ // unlock ++ pthread_mutex_unlock(&mutexlock); ++} ++ ++class Player : public oboe::AudioStreamDataCallback ++{ ++public: ++ ~Player() { ++ outStream->requestStop(); ++ } ++ ++ Player(int channels, int sample_rate) ++ { ++ this->channels = channels; ++ oboe::AudioStreamBuilder builder; ++ // The builder set methods can be chained for convenience. ++ builder.setSharingMode(oboe::SharingMode::Exclusive) ++ ->setPerformanceMode(oboe::PerformanceMode::LowLatency) ++ ->setChannelCount(channels) ++ ->setSampleRate(sample_rate) ++ ->setFormat(oboe::AudioFormat::Float) ++ ->setDataCallback(this) ++ ->openManagedStream(outStream); ++ // Typically, start the stream after querying some stream information, as well as some input from the user ++ outStream->requestStart(); ++ } ++ ++ oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override ++ { ++ float *floatData = (float *)audioData; ++ int i = 0; ++ mtx.Lock(); ++ auto n = channels * numFrames; ++ for (; i < n && i < (int)buffer.size(); ++i, ++floatData) ++ { ++ *floatData = buffer.front(); ++ buffer.pop_front(); ++ } ++ mtx.Unlock(); ++ for (; i < n; ++i, ++floatData) ++ { ++ *floatData = 0; ++ } ++ return oboe::DataCallbackResult::Continue; ++ } ++ ++ void push(const float *v, int n) ++ { ++ mtx.Lock(); ++ for (auto i = 0; i < n; ++i, ++v) ++ buffer.push_back(*v); ++ // in case memory overuse ++ if (buffer.size() > 48 * 1024 * 120) ++ buffer.clear(); ++ mtx.Unlock(); ++ } ++ ++private: ++ oboe::ManagedStream outStream; ++ int channels; ++ std::deque buffer; ++ CThreadLock mtx; ++}; ++ ++extern "C" ++{ ++ void *create_oboe_player(int channels, int sample_rate) ++ { ++ return new Player(channels, sample_rate); ++ } ++ ++ void push_oboe_data(void *player, const float* v, int n) ++ { ++ static_cast(player)->push(v, n); ++ } ++ ++ void destroy_oboe_player(void *player) ++ { ++ delete static_cast(player); ++ } ++}