1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android/log.h>
18 
19 // parselib includes
20 #include <stream/MemInputStream.h>
21 #include <wav/WavStreamReader.h>
22 
23 // local includes
24 #include "OneShotSampleSource.h"
25 #include "SimpleMultiPlayer.h"
26 
27 static const char* TAG = "SimpleMultiPlayer";
28 
29 using namespace oboe;
30 using namespace parselib;
31 
32 namespace iolib {
33 
34 constexpr int32_t kBufferSizeInBursts = 2; // Use 2 bursts as the buffer size (double buffer)
35 
SimpleMultiPlayer()36 SimpleMultiPlayer::SimpleMultiPlayer()
37   : mChannelCount(0), mOutputReset(false)
38 {}
39 
onAudioReady(AudioStream * oboeStream,void * audioData,int32_t numFrames)40 DataCallbackResult SimpleMultiPlayer::onAudioReady(AudioStream *oboeStream, void *audioData,
41         int32_t numFrames) {
42 
43     StreamState streamState = oboeStream->getState();
44     if (streamState != StreamState::Open && streamState != StreamState::Started) {
45         __android_log_print(ANDROID_LOG_ERROR, TAG, "  streamState:%d", streamState);
46     }
47     if (streamState == StreamState::Disconnected) {
48         __android_log_print(ANDROID_LOG_ERROR, TAG, "  streamState::Disconnected");
49     }
50 
51     memset(audioData, 0, numFrames * mChannelCount * sizeof(float));
52 
53     // OneShotSampleSource* sources = mSampleSources.get();
54     for(int32_t index = 0; index < mNumSampleBuffers; index++) {
55         if (mSampleSources[index]->isPlaying()) {
56             mSampleSources[index]->mixAudio((float*)audioData, mChannelCount, numFrames);
57         }
58     }
59 
60     return DataCallbackResult::Continue;
61 }
62 
onErrorAfterClose(AudioStream * oboeStream,Result error)63 void SimpleMultiPlayer::onErrorAfterClose(AudioStream *oboeStream, Result error) {
64     __android_log_print(ANDROID_LOG_INFO, TAG, "==== onErrorAfterClose() error:%d", error);
65 
66     resetAll();
67     if (openStream() && startStream()) {
68         mOutputReset = true;
69     }
70 }
71 
onErrorBeforeClose(AudioStream *,Result error)72 void SimpleMultiPlayer::onErrorBeforeClose(AudioStream *, Result error) {
73     __android_log_print(ANDROID_LOG_INFO, TAG, "==== onErrorBeforeClose() error:%d", error);
74 }
75 
openStream()76 bool SimpleMultiPlayer::openStream() {
77     __android_log_print(ANDROID_LOG_INFO, TAG, "openStream()");
78 
79     // Create an audio stream
80     AudioStreamBuilder builder;
81     builder.setChannelCount(mChannelCount);
82     // we will resample source data to device rate, so take default sample rate
83     builder.setCallback(this);
84     builder.setPerformanceMode(PerformanceMode::LowLatency);
85     builder.setSharingMode(SharingMode::Exclusive);
86     builder.setSampleRateConversionQuality(SampleRateConversionQuality::Medium);
87 
88     Result result = builder.openStream(mAudioStream);
89     if (result != Result::OK){
90         __android_log_print(
91                 ANDROID_LOG_ERROR,
92                 TAG,
93                 "openStream failed. Error: %s", convertToText(result));
94         return false;
95     }
96 
97     // Reduce stream latency by setting the buffer size to a multiple of the burst size
98     // Note: this will fail with ErrorUnimplemented if we are using a callback with OpenSL ES
99     // See oboe::AudioStreamBuffered::setBufferSizeInFrames
100     result = mAudioStream->setBufferSizeInFrames(
101             mAudioStream->getFramesPerBurst() * kBufferSizeInBursts);
102     if (result != Result::OK) {
103         __android_log_print(
104                 ANDROID_LOG_WARN,
105                 TAG,
106                 "setBufferSizeInFrames failed. Error: %s", convertToText(result));
107     }
108 
109     mSampleRate = mAudioStream->getSampleRate();
110 
111     return true;
112 }
113 
startStream()114 bool SimpleMultiPlayer::startStream() {
115     Result result = mAudioStream->requestStart();
116     if (result != Result::OK){
117         __android_log_print(
118                 ANDROID_LOG_ERROR,
119                 TAG,
120                 "requestStart failed. Error: %s", convertToText(result));
121         return false;
122     }
123 
124     return true;
125 }
126 
setupAudioStream(int32_t channelCount)127 void SimpleMultiPlayer::setupAudioStream(int32_t channelCount) {
128     __android_log_print(ANDROID_LOG_INFO, TAG, "setupAudioStream()");
129     mChannelCount = channelCount;
130 
131     openStream();
132 }
133 
teardownAudioStream()134 void SimpleMultiPlayer::teardownAudioStream() {
135     __android_log_print(ANDROID_LOG_INFO, TAG, "teardownAudioStream()");
136     // tear down the player
137     if (mAudioStream) {
138         mAudioStream->stop();
139         mAudioStream->close();
140         mAudioStream.reset();
141     }
142 }
143 
addSampleSource(SampleSource * source,SampleBuffer * buffer)144 void SimpleMultiPlayer::addSampleSource(SampleSource* source, SampleBuffer* buffer) {
145     buffer->resampleData(mSampleRate);
146 
147     mSampleBuffers.push_back(buffer);
148     mSampleSources.push_back(source);
149     mNumSampleBuffers++;
150 }
151 
unloadSampleData()152 void SimpleMultiPlayer::unloadSampleData() {
153     __android_log_print(ANDROID_LOG_INFO, TAG, "unloadSampleData()");
154     resetAll();
155 
156     for (int32_t bufferIndex = 0; bufferIndex < mNumSampleBuffers; bufferIndex++) {
157         delete mSampleBuffers[bufferIndex];
158         delete mSampleSources[bufferIndex];
159     }
160 
161     mSampleBuffers.clear();
162     mSampleSources.clear();
163 
164     mNumSampleBuffers = 0;
165 }
166 
triggerDown(int32_t index)167 void SimpleMultiPlayer::triggerDown(int32_t index) {
168     if (index < mNumSampleBuffers) {
169         mSampleSources[index]->setPlayMode();
170     }
171 }
172 
triggerUp(int32_t index)173 void SimpleMultiPlayer::triggerUp(int32_t index) {
174     if (index < mNumSampleBuffers) {
175         mSampleSources[index]->setStopMode();
176     }
177 }
178 
resetAll()179 void SimpleMultiPlayer::resetAll() {
180     for (int32_t bufferIndex = 0; bufferIndex < mNumSampleBuffers; bufferIndex++) {
181         mSampleSources[bufferIndex]->setStopMode();
182     }
183 }
184 
setPan(int index,float pan)185 void SimpleMultiPlayer::setPan(int index, float pan) {
186     mSampleSources[index]->setPan(pan);
187 }
188 
getPan(int index)189 float SimpleMultiPlayer::getPan(int index) {
190     return mSampleSources[index]->getPan();
191 }
192 
setGain(int index,float gain)193 void SimpleMultiPlayer::setGain(int index, float gain) {
194     mSampleSources[index]->setGain(gain);
195 }
196 
getGain(int index)197 float SimpleMultiPlayer::getGain(int index) {
198     return mSampleSources[index]->getGain();
199 }
200 
201 }
202