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); + } +}