diff --git a/BUILD.gn b/BUILD.gn index 769cd7d5a1..4080562283 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -2353,7 +2353,6 @@ if (skia_enable_tools) { ":skia", "modules/skottie", "modules/sksg:samples", - "//third_party/oboe", ] } } diff --git a/modules/audioplayer/BUILD.gn b/modules/audioplayer/BUILD.gn index 345fc4208a..184b1274a3 100644 --- a/modules/audioplayer/BUILD.gn +++ b/modules/audioplayer/BUILD.gn @@ -19,6 +19,10 @@ component("audioplayer") { "sfml-system", "sfml-audio", ] + } else if (is_android) { + sources += [ "SkAudioPlayer_oboe.cpp" ] + deps += [ "../../third_party/oboe" ] + libs = [ "OpenSLES" ] } else { sources += [ "SkAudioPlayer_none.cpp" ] } diff --git a/modules/audioplayer/SkAudioPlayer_oboe.cpp b/modules/audioplayer/SkAudioPlayer_oboe.cpp new file mode 100644 index 0000000000..6e5769237a --- /dev/null +++ b/modules/audioplayer/SkAudioPlayer_oboe.cpp @@ -0,0 +1,119 @@ +/* +* Copyright 2020 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "modules/audioplayer/SkAudioPlayer.h" + +#include "include/core/SkData.h" +#include "oboe/Oboe.h" +#include "stream/MemInputStream.h" +#include "wav/WavStreamReader.h" + +namespace { + +class OboeAudioPlayer final : public SkAudioPlayer, oboe::AudioStreamCallback { +public: + explicit OboeAudioPlayer(sk_sp data) + : fData(std::move(data)) + , fMemInputStream(const_cast + (static_cast(fData->data())), static_cast(fData->size())) + { + // wrap data in MemInputStream to parse WAV header + fReader = std::make_unique(&fMemInputStream); + fReader->parse(); + // set member variables and builder properties using reader + fNumSampleFrames = fReader->getNumSampleFrames(); + + oboe::AudioStreamBuilder builder; + builder.setPerformanceMode(oboe::PerformanceMode::LowLatency); + builder.setSharingMode(oboe::SharingMode::Exclusive); + builder.setSampleRate(fReader->getSampleRate()); + builder.setChannelCount(fReader->getNumChannels()); + builder.setCallback(this); + builder.setFormat(oboe::AudioFormat::Float); + + // open the stream (must manually close it when done) + fStream = nullptr; + builder.openStream(fStream); + } + +private: + oboe::DataCallbackResult + onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override { + // we assume float samples here + float *outBuffer = static_cast(audioData); + int framesRead = fReader->getDataFloat(outBuffer, numFrames); + fReadFrameIndex += framesRead; + int remainingFrames = numFrames - framesRead; + if (remainingFrames > 0) { + if (fIsLooping) { + // handle wrap around + fReader->positionToAudio(); + fReader->getDataFloat(&outBuffer[framesRead * fReader->getNumChannels()], + remainingFrames); + fReadFrameIndex += remainingFrames; + } else { + // render silence for rest + renderSilence(&outBuffer[framesRead * fReader->getNumChannels()], remainingFrames); + return oboe::DataCallbackResult::Stop; + } + } + return oboe::DataCallbackResult::Continue; + } + + void renderSilence(float *start, int numFrames) { + for (int i = 0; i < numFrames * fReader->getNumChannels(); ++i) { + start[i] = 0; + } + } + double onGetDuration() const override { + return fNumSampleFrames * fStream->getChannelCount() / fStream->getSampleRate(); + } + + double onGetTime() const override { + return (fReadFrameIndex * fStream->getChannelCount()) / fStream->getSampleRate(); + } + + double onSetTime(double t) override { + fReadFrameIndex = (t * fStream->getSampleRate()) / fStream->getChannelCount(); + return onGetTime(); + } + + State onSetState(State state) override { + switch (state) { + case State::kPlaying: fStream->start(); break; + case State::kStopped: fStream->close(); break; + case State::kPaused : fStream->pause(); break; + } + + return state; + } + + + // TODO: implement rate function (change sample rate of AudioStream) + float onSetRate(float r) override { + return r; + } + + // TODO: implement volume function (multiply each sample by desired amplitude) + float onSetVolume(float v) override { + return v; + } + + const sk_sp fData; + std::shared_ptr fStream; + std::unique_ptr fReader; + parselib::MemInputStream fMemInputStream; + int32_t fReadFrameIndex {0}; + int fNumSampleFrames; + bool fIsLooping {false}; +}; + +} // namespace + +std::unique_ptr SkAudioPlayer::Make(sk_sp src) { + return std::unique_ptr(new OboeAudioPlayer(std::move(src))); +} diff --git a/third_party/oboe/BUILD.gn b/third_party/oboe/BUILD.gn index c4195f40f1..f200af1969 100644 --- a/third_party/oboe/BUILD.gn +++ b/third_party/oboe/BUILD.gn @@ -9,6 +9,7 @@ third_party("oboe") { public_include_dirs = [ "../externals/oboe/include", "../externals/oboe/samples/parselib/src/main/cpp", + "../externals/oboe/src/flowgraph", ] include_dirs = [ "../externals/oboe/src" ] @@ -43,10 +44,12 @@ third_party("oboe") { "../externals/oboe/src/fifo/FifoController.cpp", "../externals/oboe/src/fifo/FifoControllerBase.cpp", "../externals/oboe/src/fifo/FifoControllerIndirect.cpp", + "../externals/oboe/src/flowgraph/ChannelCountConverter.cpp", "../externals/oboe/src/flowgraph/ClipToRange.cpp", "../externals/oboe/src/flowgraph/FlowGraphNode.cpp", "../externals/oboe/src/flowgraph/ManyToMultiConverter.cpp", "../externals/oboe/src/flowgraph/MonoToMultiConverter.cpp", + "../externals/oboe/src/flowgraph/MultiToMonoConverter.cpp", "../externals/oboe/src/flowgraph/RampLinear.cpp", "../externals/oboe/src/flowgraph/SampleRateConverter.cpp", "../externals/oboe/src/flowgraph/SinkFloat.cpp",