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), mSampleRate(0), mNumSampleBuffers(0)
38 {}
39
onAudioReady(AudioStream * oboeStream,void * audioData,int32_t numFrames)40 DataCallbackResult SimpleMultiPlayer::MyDataCallback::onAudioReady(AudioStream *oboeStream,
41 void *audioData,
42 int32_t numFrames) {
43
44 StreamState streamState = oboeStream->getState();
45 if (streamState != StreamState::Open && streamState != StreamState::Started) {
46 __android_log_print(ANDROID_LOG_ERROR, TAG, " streamState:%d", streamState);
47 }
48 if (streamState == StreamState::Disconnected) {
49 __android_log_print(ANDROID_LOG_ERROR, TAG, " streamState::Disconnected");
50 }
51
52 memset(audioData, 0, static_cast<size_t>(numFrames) * static_cast<size_t>
53 (mParent->mChannelCount) * sizeof(float));
54
55 // OneShotSampleSource* sources = mSampleSources.get();
56 for(int32_t index = 0; index < mParent->mNumSampleBuffers; index++) {
57 if (mParent->mSampleSources[index]->isPlaying()) {
58 mParent->mSampleSources[index]->mixAudio((float*)audioData, mParent->mChannelCount,
59 numFrames);
60 }
61 }
62
63 return DataCallbackResult::Continue;
64 }
65
onErrorAfterClose(AudioStream * oboeStream,Result error)66 void SimpleMultiPlayer::MyErrorCallback::onErrorAfterClose(AudioStream *oboeStream, Result error) {
67 __android_log_print(ANDROID_LOG_INFO, TAG, "==== onErrorAfterClose() error:%d", error);
68
69 mParent->resetAll();
70 if (mParent->openStream() && mParent->startStream()) {
71 mParent->mOutputReset = true;
72 }
73 }
74
openStream()75 bool SimpleMultiPlayer::openStream() {
76 __android_log_print(ANDROID_LOG_INFO, TAG, "openStream()");
77
78 // Use shared_ptr to prevent use of a deleted callback.
79 mDataCallback = std::make_shared<MyDataCallback>(this);
80 mErrorCallback = std::make_shared<MyErrorCallback>(this);
81
82 // Create an audio stream
83 AudioStreamBuilder builder;
84 builder.setChannelCount(mChannelCount);
85 // we will resample source data to device rate, so take default sample rate
86 builder.setDataCallback(mDataCallback);
87 builder.setErrorCallback(mErrorCallback);
88 builder.setPerformanceMode(PerformanceMode::LowLatency);
89 builder.setSharingMode(SharingMode::Exclusive);
90 builder.setSampleRateConversionQuality(SampleRateConversionQuality::Medium);
91
92 Result result = builder.openStream(mAudioStream);
93 if (result != Result::OK){
94 __android_log_print(
95 ANDROID_LOG_ERROR,
96 TAG,
97 "openStream failed. Error: %s", convertToText(result));
98 return false;
99 }
100
101 // Reduce stream latency by setting the buffer size to a multiple of the burst size
102 // Note: this will fail with ErrorUnimplemented if we are using a callback with OpenSL ES
103 // See oboe::AudioStreamBuffered::setBufferSizeInFrames
104 result = mAudioStream->setBufferSizeInFrames(
105 mAudioStream->getFramesPerBurst() * kBufferSizeInBursts);
106 if (result != Result::OK) {
107 __android_log_print(
108 ANDROID_LOG_WARN,
109 TAG,
110 "setBufferSizeInFrames failed. Error: %s", convertToText(result));
111 }
112
113 mSampleRate = mAudioStream->getSampleRate();
114
115 return true;
116 }
117
startStream()118 bool SimpleMultiPlayer::startStream() {
119 int tryCount = 0;
120 while (tryCount < 3) {
121 bool wasOpenSuccessful = true;
122 // Assume that apenStream() was called successfully before startStream() call.
123 if (tryCount > 0) {
124 usleep(20 * 1000); // Sleep between tries to give the system time to settle.
125 wasOpenSuccessful = openStream(); // Try to open the stream again after the first try.
126 }
127 if (wasOpenSuccessful) {
128 Result result = mAudioStream->requestStart();
129 if (result != Result::OK){
130 __android_log_print(
131 ANDROID_LOG_ERROR,
132 TAG,
133 "requestStart failed. Error: %s", convertToText(result));
134 mAudioStream->close();
135 mAudioStream.reset();
136 } else {
137 return true;
138 }
139 }
140 tryCount++;
141 }
142
143 return false;
144 }
145
setupAudioStream(int32_t channelCount)146 void SimpleMultiPlayer::setupAudioStream(int32_t channelCount) {
147 __android_log_print(ANDROID_LOG_INFO, TAG, "setupAudioStream()");
148 mChannelCount = channelCount;
149
150 openStream();
151 }
152
teardownAudioStream()153 void SimpleMultiPlayer::teardownAudioStream() {
154 __android_log_print(ANDROID_LOG_INFO, TAG, "teardownAudioStream()");
155 // tear down the player
156 if (mAudioStream) {
157 mAudioStream->stop();
158 mAudioStream->close();
159 mAudioStream.reset();
160 }
161 }
162
addSampleSource(SampleSource * source,SampleBuffer * buffer)163 void SimpleMultiPlayer::addSampleSource(SampleSource* source, SampleBuffer* buffer) {
164 buffer->resampleData(mSampleRate);
165
166 mSampleBuffers.push_back(buffer);
167 mSampleSources.push_back(source);
168 mNumSampleBuffers++;
169 }
170
unloadSampleData()171 void SimpleMultiPlayer::unloadSampleData() {
172 __android_log_print(ANDROID_LOG_INFO, TAG, "unloadSampleData()");
173 resetAll();
174
175 for (int32_t bufferIndex = 0; bufferIndex < mNumSampleBuffers; bufferIndex++) {
176 delete mSampleBuffers[bufferIndex];
177 delete mSampleSources[bufferIndex];
178 }
179
180 mSampleBuffers.clear();
181 mSampleSources.clear();
182
183 mNumSampleBuffers = 0;
184 }
185
triggerDown(int32_t index)186 void SimpleMultiPlayer::triggerDown(int32_t index) {
187 if (index < mNumSampleBuffers) {
188 mSampleSources[index]->setPlayMode();
189 }
190 }
191
triggerUp(int32_t index)192 void SimpleMultiPlayer::triggerUp(int32_t index) {
193 if (index < mNumSampleBuffers) {
194 mSampleSources[index]->setStopMode();
195 }
196 }
197
resetAll()198 void SimpleMultiPlayer::resetAll() {
199 for (int32_t bufferIndex = 0; bufferIndex < mNumSampleBuffers; bufferIndex++) {
200 mSampleSources[bufferIndex]->setStopMode();
201 }
202 }
203
setPan(int index,float pan)204 void SimpleMultiPlayer::setPan(int index, float pan) {
205 mSampleSources[index]->setPan(pan);
206 }
207
getPan(int index)208 float SimpleMultiPlayer::getPan(int index) {
209 return mSampleSources[index]->getPan();
210 }
211
setGain(int index,float gain)212 void SimpleMultiPlayer::setGain(int index, float gain) {
213 mSampleSources[index]->setGain(gain);
214 }
215
getGain(int index)216 float SimpleMultiPlayer::getGain(int index) {
217 return mSampleSources[index]->getGain();
218 }
219
220 }
221