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