• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright 2020 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 
8 #include "modules/audioplayer/SkAudioPlayer.h"
9 
10 #include "include/core/SkData.h"
11 #include "oboe/Oboe.h"
12 #include "stream/MemInputStream.h"
13 #include "wav/WavStreamReader.h"
14 
15 namespace {
16 
17 class OboeAudioPlayer final : public SkAudioPlayer, oboe::AudioStreamCallback {
18 public:
OboeAudioPlayer(sk_sp<SkData> data)19     explicit OboeAudioPlayer(sk_sp<SkData> data)
20         : fData(std::move(data))
21         , fMemInputStream(const_cast<unsigned char *>
22           (static_cast<const unsigned char *>(fData->data())), static_cast<int32_t>(fData->size()))
23     {
24       // wrap data in MemInputStream to parse WAV header
25       fReader = std::make_unique<parselib::WavStreamReader>(&fMemInputStream);
26       fReader->parse();
27       // set member variables and builder properties using reader
28       fNumSampleFrames = fReader->getNumSampleFrames();
29 
30       oboe::AudioStreamBuilder builder;
31       builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);
32       builder.setSharingMode(oboe::SharingMode::Exclusive);
33       builder.setSampleRate(fReader->getSampleRate());
34       builder.setChannelCount(fReader->getNumChannels());
35       builder.setCallback(this);
36       builder.setFormat(oboe::AudioFormat::Float);
37 
38       // open the stream (must manually close it when done)
39       fStream = nullptr;
40       builder.openStream(fStream);
41     }
42 
43 private:
44     oboe::DataCallbackResult
onAudioReady(oboe::AudioStream * oboeStream,void * audioData,int32_t numFrames)45     onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
46         // we assume float samples here
47         float *outBuffer = static_cast<float *>(audioData);
48             int framesRead = fReader->getDataFloat(outBuffer, numFrames);
49             fReadFrameIndex += framesRead;
50             int remainingFrames = numFrames - framesRead;
51             if (remainingFrames > 0) {
52                 if (fIsLooping) {
53                     // handle wrap around
54                     fReader->positionToAudio();
55                     fReader->getDataFloat(&outBuffer[framesRead * fReader->getNumChannels()],
56                                          remainingFrames);
57                     fReadFrameIndex += remainingFrames;
58                 } else {
59                     // render silence for rest
60                     renderSilence(&outBuffer[framesRead * fReader->getNumChannels()], remainingFrames);
61                     return oboe::DataCallbackResult::Stop;
62                 }
63             }
64         return oboe::DataCallbackResult::Continue;
65     }
66 
renderSilence(float * start,int numFrames)67     void renderSilence(float *start, int numFrames) {
68         for (int i = 0; i < numFrames * fReader->getNumChannels(); ++i) {
69             start[i] = 0;
70         }
71     }
onGetDuration() const72     double onGetDuration() const override {
73         return fNumSampleFrames * fStream->getChannelCount() / fStream->getSampleRate();
74     }
75 
onGetTime() const76     double onGetTime() const override {
77         return (fReadFrameIndex * fStream->getChannelCount()) / fStream->getSampleRate();
78     }
79 
onSetTime(double t)80     double onSetTime(double t) override {
81         fReadFrameIndex = (t * fStream->getSampleRate()) / fStream->getChannelCount();
82         return onGetTime();
83     }
84 
onSetState(State state)85     State onSetState(State state) override {
86         switch (state) {
87             case State::kPlaying: fStream->start();  break;
88             case State::kStopped: fStream->close();  break;
89             case State::kPaused : fStream->pause(); break;
90         }
91 
92         return state;
93     }
94 
95 
96     // TODO: implement rate function (change sample rate of AudioStream)
onSetRate(float r)97     float onSetRate(float r) override {
98         return r;
99     }
100 
101     // TODO: implement volume function (multiply each sample by desired amplitude)
onSetVolume(float v)102     float onSetVolume(float v) override {
103         return v;
104     }
105 
106     const sk_sp<SkData>                         fData;
107     std::shared_ptr<oboe::AudioStream>          fStream;
108     std::unique_ptr<parselib::WavStreamReader>  fReader;
109     parselib::MemInputStream                    fMemInputStream;
110     int32_t                                     fReadFrameIndex {0};
111     int                                         fNumSampleFrames;
112     bool                                        fIsLooping {false};
113 };
114 
115 } // namespace
116 
Make(sk_sp<SkData> src)117 std::unique_ptr<SkAudioPlayer> SkAudioPlayer::Make(sk_sp<SkData> src) {
118     return std::unique_ptr<SkAudioPlayer>(new OboeAudioPlayer(std::move(src)));
119 }
120