diff --git a/client/Makefile b/client/Makefile index c206df4c..645681c2 100644 --- a/client/Makefile +++ b/client/Makefile @@ -58,9 +58,9 @@ endif ifeq ($(TARGET), ANDROID) CXX = $(PROGRAM_PREFIX)clang++ -CXXFLAGS += -pthread -fPIC -DHAS_TREMOR -DHAS_OPENSL -I$(NDK_DIR)/include -LDFLAGS = -L$(NDK_DIR)/lib -pie -lvorbisidec -logg -lopus -lFLAC -lOpenSLES -latomic -llog -static-libstdc++ -OBJ += player/opensl_player.o +CXXFLAGS += -pthread -fPIC -DHAS_TREMOR -DHAS_OBOE -I$(NDK_DIR)/include -I/home/johannes/Develop/oboe/include +LDFLAGS = -L$(NDK_DIR)/lib -pie -lvorbisidec -logg -lopus -lFLAC -lOpenSLES -loboe -latomic -llog -static-libstdc++ +OBJ += player/oboe_player.o else ifeq ($(TARGET), OPENWRT) diff --git a/client/controller.cpp b/client/controller.cpp index 6242108a..621869c3 100644 --- a/client/controller.cpp +++ b/client/controller.cpp @@ -130,6 +130,8 @@ void Controller::onMessageReceived(ClientConnection* /*connection*/, const msg:: player_ = make_unique(pcmDevice_, stream_); #elif HAS_OPENSL player_ = make_unique(pcmDevice_, stream_); +#elif HAS_OBOE + player_ = make_unique(pcmDevice_, stream_); #elif HAS_COREAUDIO player_ = make_unique(pcmDevice_, stream_); #else diff --git a/client/controller.hpp b/client/controller.hpp index cc3914cb..e7646ef1 100644 --- a/client/controller.hpp +++ b/client/controller.hpp @@ -30,6 +30,8 @@ #include "player/alsa_player.hpp" #elif HAS_OPENSL #include "player/opensl_player.hpp" +#elif HAS_OBOE +#include "player/oboe_player.hpp" #elif HAS_COREAUDIO #include "player/coreaudio_player.hpp" #endif diff --git a/client/player/oboe_player.cpp b/client/player/oboe_player.cpp new file mode 100644 index 00000000..0d87905e --- /dev/null +++ b/client/player/oboe_player.cpp @@ -0,0 +1,87 @@ +/*** + This file is part of snapcast + Copyright (C) 2014-2020 Johannes Pohl + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +***/ + +#include +#include + +#include "common/aixlog.hpp" +#include "common/snap_exception.hpp" +#include "common/str_compat.hpp" +#include "oboe_player.hpp" + +using namespace std; + + +OboePlayer::OboePlayer(const PcmDevice& pcmDevice, std::shared_ptr stream) : Player(pcmDevice, stream), ms_(50), buff_size(0), pubStream_(stream) +{ + + oboe::AudioStreamBuilder builder; + // The builder set methods can be chained for convenience. + builder.setSharingMode(oboe::SharingMode::Exclusive) + ->setPerformanceMode(oboe::PerformanceMode::LowLatency) + ->setChannelCount(stream->getFormat().channels) + ->setSampleRate(stream->getFormat().rate) + ->setFormat(oboe::AudioFormat::I16) + ->setCallback(this) + ->openManagedStream(out_stream_); +} + + +OboePlayer::~OboePlayer() +{ +} + + +oboe::DataCallbackResult OboePlayer::onAudioReady(oboe::AudioStream* oboeStream, void* audioData, int32_t numFrames) +{ + + int32_t buffer_fill_size = oboeStream->getBufferCapacityInFrames() - numFrames; + double delay_ms = static_cast(buffer_fill_size) / stream_->getFormat().msRate(); + chronos::usec delay(static_cast(delay_ms * 1000.)); + //LOG(INFO) << "onAudioReady frames: " << numFrames << ", capacity: " << oboeStream->getBufferCapacityInFrames() << ", size: " << oboeStream->getBufferSizeInFrames() << ", delay ms: " << delay_ms << "\n"; + + if (!stream_->getPlayerChunk(audioData, delay, numFrames)) + { + // LOG(INFO) << "Failed to get chunk. Playing silence.\n"; + memset(audioData, 0, numFrames); + } + else + { + adjustVolume(static_cast(audioData), numFrames); + } + + return oboe::DataCallbackResult::Continue; +} + + +void OboePlayer::start() +{ + // Typically, start the stream after querying some stream information, as well as some input from the user + out_stream_->requestStart(); +} + + +void OboePlayer::stop() +{ + out_stream_->requestStop(); +} + + +void OboePlayer::worker() +{ +} diff --git a/client/player/oboe_player.hpp b/client/player/oboe_player.hpp new file mode 100644 index 00000000..b9986c98 --- /dev/null +++ b/client/player/oboe_player.hpp @@ -0,0 +1,56 @@ +/*** + This file is part of snapcast + Copyright (C) 2014-2020 Johannes Pohl + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +***/ + +#ifndef OBOE_PLAYER_HPP +#define OBOE_PLAYER_HPP + +#include + +#include "player.hpp" + +typedef int (*AndroidAudioCallback)(short* buffer, int num_samples); + + +/// OpenSL Audio Player +/** + * Player implementation for Oboe + */ +class OboePlayer : public Player, public oboe::AudioStreamCallback +{ +public: + OboePlayer(const PcmDevice& pcmDevice, std::shared_ptr stream); + virtual ~OboePlayer(); + + void start() override; + void stop() override; + +protected: + oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override; + + void worker() override; + + oboe::ManagedStream out_stream_; + + size_t ms_; + size_t frames_; + size_t buff_size; + std::shared_ptr pubStream_; +}; + + +#endif diff --git a/client/player/opensl_player.hpp b/client/player/opensl_player.hpp index 801c5fd2..8387024b 100644 --- a/client/player/opensl_player.hpp +++ b/client/player/opensl_player.hpp @@ -16,8 +16,8 @@ along with this program. If not, see . ***/ -#ifndef OPEN_SL_PLAYER_H -#define OPEN_SL_PLAYER_H +#ifndef OPEN_SL_PLAYER_HPP +#define OPEN_SL_PLAYER_HPP #include #include @@ -38,8 +38,8 @@ public: OpenslPlayer(const PcmDevice& pcmDevice, std::shared_ptr stream); virtual ~OpenslPlayer(); - virtual void start(); - virtual void stop(); + void start() override; + void stop() override; void playerCallback(SLAndroidSimpleBufferQueueItf bq); @@ -47,7 +47,7 @@ protected: void initOpensl(); void uninitOpensl(); - virtual void worker(); + void worker() override; void throwUnsuccess(const std::string& phase, const std::string& what, SLresult result); std::string resultToString(SLresult result) const; diff --git a/externals/Makefile b/externals/Makefile index 03288b2d..410954a2 100644 --- a/externals/Makefile +++ b/externals/Makefile @@ -14,9 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -.PHONY: all check-env flac ogg opus tremor +.PHONY: all check-env flac ogg opus tremor oboe -all: flac ogg opus tremor +all: flac ogg opus tremor oboe check-env: # if [ ! -d "flac" ]; then \ @@ -115,4 +115,14 @@ tremor: check-env rm stamp-h1; \ rm vorbisidec.pc; +oboe: check-env + @cd oboe; \ + export CC="$(CC)"; \ + export CXX="$(CXX)"; \ + export CPPFLAGS="$(CPPFLAGS)"; \ + mkdir build; \ + cd build; \ + cmake ..; \ + make; \ + make DESTDIR=$(NDK_DIR) install;