xref: /aosp_15_r20/external/oboe/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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