/* * 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))); }