xref: /aosp_15_r20/external/oboe/src/opensles/AudioStreamBuffered.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu /*
2*05767d91SRobert Wu  * Copyright (C) 2016 The Android Open Source Project
3*05767d91SRobert Wu  *
4*05767d91SRobert Wu  * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu  * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu  * You may obtain a copy of the License at
7*05767d91SRobert Wu  *
8*05767d91SRobert Wu  *      http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu  *
10*05767d91SRobert Wu  * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu  * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu  * See the License for the specific language governing permissions and
14*05767d91SRobert Wu  * limitations under the License.
15*05767d91SRobert Wu  */
16*05767d91SRobert Wu 
17*05767d91SRobert Wu #include <memory>
18*05767d91SRobert Wu 
19*05767d91SRobert Wu #include "oboe/Oboe.h"
20*05767d91SRobert Wu 
21*05767d91SRobert Wu #include "common/OboeDebug.h"
22*05767d91SRobert Wu #include "opensles/AudioStreamBuffered.h"
23*05767d91SRobert Wu #include "common/AudioClock.h"
24*05767d91SRobert Wu 
25*05767d91SRobert Wu namespace oboe {
26*05767d91SRobert Wu 
27*05767d91SRobert Wu constexpr int kDefaultBurstsPerBuffer = 16;  // arbitrary, allows dynamic latency tuning
28*05767d91SRobert Wu constexpr int kMinBurstsPerBuffer     = 4;  // arbitrary, allows dynamic latency tuning
29*05767d91SRobert Wu constexpr int kMinFramesPerBuffer     = 48 * 32; // arbitrary
30*05767d91SRobert Wu 
31*05767d91SRobert Wu /*
32*05767d91SRobert Wu  * AudioStream with a FifoBuffer
33*05767d91SRobert Wu  */
AudioStreamBuffered(const AudioStreamBuilder & builder)34*05767d91SRobert Wu AudioStreamBuffered::AudioStreamBuffered(const AudioStreamBuilder &builder)
35*05767d91SRobert Wu         : AudioStream(builder) {
36*05767d91SRobert Wu }
37*05767d91SRobert Wu 
allocateFifo()38*05767d91SRobert Wu void AudioStreamBuffered::allocateFifo() {
39*05767d91SRobert Wu     // If the caller does not provide a callback use our own internal
40*05767d91SRobert Wu     // callback that reads data from the FIFO.
41*05767d91SRobert Wu     if (usingFIFO()) {
42*05767d91SRobert Wu         // FIFO is configured with the same format and channels as the stream.
43*05767d91SRobert Wu         int32_t capacityFrames = getBufferCapacityInFrames();
44*05767d91SRobert Wu         if (capacityFrames == oboe::kUnspecified) {
45*05767d91SRobert Wu             capacityFrames = getFramesPerBurst() * kDefaultBurstsPerBuffer;
46*05767d91SRobert Wu         } else {
47*05767d91SRobert Wu             int32_t minFramesPerBufferByBursts = getFramesPerBurst() * kMinBurstsPerBuffer;
48*05767d91SRobert Wu             if (capacityFrames <= minFramesPerBufferByBursts) {
49*05767d91SRobert Wu                 capacityFrames = minFramesPerBufferByBursts;
50*05767d91SRobert Wu             } else {
51*05767d91SRobert Wu                 capacityFrames = std::max(kMinFramesPerBuffer, capacityFrames);
52*05767d91SRobert Wu                 // round up to nearest burst
53*05767d91SRobert Wu                 int32_t numBursts = (capacityFrames + getFramesPerBurst() - 1)
54*05767d91SRobert Wu                         / getFramesPerBurst();
55*05767d91SRobert Wu                 capacityFrames = numBursts * getFramesPerBurst();
56*05767d91SRobert Wu             }
57*05767d91SRobert Wu         }
58*05767d91SRobert Wu 
59*05767d91SRobert Wu         mFifoBuffer = std::make_unique<FifoBuffer>(getBytesPerFrame(), capacityFrames);
60*05767d91SRobert Wu         mBufferCapacityInFrames = capacityFrames;
61*05767d91SRobert Wu         mBufferSizeInFrames = mBufferCapacityInFrames;
62*05767d91SRobert Wu     }
63*05767d91SRobert Wu }
64*05767d91SRobert Wu 
updateFramesWritten()65*05767d91SRobert Wu void AudioStreamBuffered::updateFramesWritten() {
66*05767d91SRobert Wu     if (mFifoBuffer) {
67*05767d91SRobert Wu         mFramesWritten = static_cast<int64_t>(mFifoBuffer->getWriteCounter());
68*05767d91SRobert Wu     } // or else it will get updated by processBufferCallback()
69*05767d91SRobert Wu }
70*05767d91SRobert Wu 
updateFramesRead()71*05767d91SRobert Wu void AudioStreamBuffered::updateFramesRead() {
72*05767d91SRobert Wu     if (mFifoBuffer) {
73*05767d91SRobert Wu         mFramesRead = static_cast<int64_t>(mFifoBuffer->getReadCounter());
74*05767d91SRobert Wu     } // or else it will get updated by processBufferCallback()
75*05767d91SRobert Wu }
76*05767d91SRobert Wu 
77*05767d91SRobert Wu // This is called by the OpenSL ES callback to read or write the back end of the FIFO.
onDefaultCallback(void * audioData,int numFrames)78*05767d91SRobert Wu DataCallbackResult AudioStreamBuffered::onDefaultCallback(void *audioData, int numFrames) {
79*05767d91SRobert Wu     int32_t framesTransferred  = 0;
80*05767d91SRobert Wu 
81*05767d91SRobert Wu     if (getDirection() == oboe::Direction::Output) {
82*05767d91SRobert Wu         // Read from the FIFO and write to audioData, clear part of buffer if not enough data.
83*05767d91SRobert Wu         framesTransferred = mFifoBuffer->readNow(audioData, numFrames);
84*05767d91SRobert Wu     } else {
85*05767d91SRobert Wu         // Read from audioData and write to the FIFO
86*05767d91SRobert Wu         framesTransferred = mFifoBuffer->write(audioData, numFrames); // There is no writeNow()
87*05767d91SRobert Wu     }
88*05767d91SRobert Wu 
89*05767d91SRobert Wu     if (framesTransferred < numFrames) {
90*05767d91SRobert Wu         LOGD("AudioStreamBuffered::%s(): xrun! framesTransferred = %d, numFrames = %d",
91*05767d91SRobert Wu                 __func__, framesTransferred, numFrames);
92*05767d91SRobert Wu         // TODO If we do not allow FIFO to wrap then our timestamps will drift when there is an XRun!
93*05767d91SRobert Wu         incrementXRunCount();
94*05767d91SRobert Wu     }
95*05767d91SRobert Wu     markCallbackTime(static_cast<int32_t>(numFrames)); // so foreground knows how long to wait.
96*05767d91SRobert Wu     return DataCallbackResult::Continue;
97*05767d91SRobert Wu }
98*05767d91SRobert Wu 
markCallbackTime(int32_t numFrames)99*05767d91SRobert Wu void AudioStreamBuffered::markCallbackTime(int32_t numFrames) {
100*05767d91SRobert Wu     mLastBackgroundSize = numFrames;
101*05767d91SRobert Wu     mBackgroundRanAtNanoseconds = AudioClock::getNanoseconds();
102*05767d91SRobert Wu }
103*05767d91SRobert Wu 
predictNextCallbackTime()104*05767d91SRobert Wu int64_t AudioStreamBuffered::predictNextCallbackTime() {
105*05767d91SRobert Wu     if (mBackgroundRanAtNanoseconds == 0) {
106*05767d91SRobert Wu         return 0;
107*05767d91SRobert Wu     }
108*05767d91SRobert Wu     int64_t nanosPerBuffer = (kNanosPerSecond * mLastBackgroundSize) / getSampleRate();
109*05767d91SRobert Wu     const int64_t margin = 200 * kNanosPerMicrosecond; // arbitrary delay so we wake up just after
110*05767d91SRobert Wu     return mBackgroundRanAtNanoseconds + nanosPerBuffer + margin;
111*05767d91SRobert Wu }
112*05767d91SRobert Wu 
113*05767d91SRobert Wu // Common code for read/write.
114*05767d91SRobert Wu // @return Result::OK with frames read/written, or Result::Error*
transfer(void * readBuffer,const void * writeBuffer,int32_t numFrames,int64_t timeoutNanoseconds)115*05767d91SRobert Wu ResultWithValue<int32_t> AudioStreamBuffered::transfer(
116*05767d91SRobert Wu         void *readBuffer,
117*05767d91SRobert Wu         const void *writeBuffer,
118*05767d91SRobert Wu         int32_t numFrames,
119*05767d91SRobert Wu         int64_t timeoutNanoseconds) {
120*05767d91SRobert Wu     // Validate arguments.
121*05767d91SRobert Wu     if (readBuffer != nullptr && writeBuffer != nullptr) {
122*05767d91SRobert Wu         LOGE("AudioStreamBuffered::%s(): both buffers are not NULL", __func__);
123*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorInternal);
124*05767d91SRobert Wu     }
125*05767d91SRobert Wu     if (getDirection() == Direction::Input && readBuffer == nullptr) {
126*05767d91SRobert Wu         LOGE("AudioStreamBuffered::%s(): readBuffer is NULL", __func__);
127*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorNull);
128*05767d91SRobert Wu     }
129*05767d91SRobert Wu     if (getDirection() == Direction::Output && writeBuffer == nullptr) {
130*05767d91SRobert Wu         LOGE("AudioStreamBuffered::%s(): writeBuffer is NULL", __func__);
131*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorNull);
132*05767d91SRobert Wu     }
133*05767d91SRobert Wu     if (numFrames < 0) {
134*05767d91SRobert Wu         LOGE("AudioStreamBuffered::%s(): numFrames is negative", __func__);
135*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorOutOfRange);
136*05767d91SRobert Wu     } else if (numFrames == 0) {
137*05767d91SRobert Wu         return ResultWithValue<int32_t>(numFrames);
138*05767d91SRobert Wu     }
139*05767d91SRobert Wu     if (timeoutNanoseconds < 0) {
140*05767d91SRobert Wu         LOGE("AudioStreamBuffered::%s(): timeoutNanoseconds is negative", __func__);
141*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorOutOfRange);
142*05767d91SRobert Wu     }
143*05767d91SRobert Wu 
144*05767d91SRobert Wu     int32_t result = 0;
145*05767d91SRobert Wu     uint8_t *readData = reinterpret_cast<uint8_t *>(readBuffer);
146*05767d91SRobert Wu     const uint8_t *writeData = reinterpret_cast<const uint8_t *>(writeBuffer);
147*05767d91SRobert Wu     int32_t framesLeft = numFrames;
148*05767d91SRobert Wu     int64_t timeToQuit = 0;
149*05767d91SRobert Wu     bool repeat = true;
150*05767d91SRobert Wu 
151*05767d91SRobert Wu     // Calculate when to timeout.
152*05767d91SRobert Wu     if (timeoutNanoseconds > 0) {
153*05767d91SRobert Wu         timeToQuit = AudioClock::getNanoseconds() + timeoutNanoseconds;
154*05767d91SRobert Wu     }
155*05767d91SRobert Wu 
156*05767d91SRobert Wu     // Loop until we get the data, or we have an error, or we timeout.
157*05767d91SRobert Wu     do {
158*05767d91SRobert Wu         // read or write
159*05767d91SRobert Wu         if (getDirection() == Direction::Input) {
160*05767d91SRobert Wu             result = mFifoBuffer->read(readData, framesLeft);
161*05767d91SRobert Wu             if (result > 0) {
162*05767d91SRobert Wu                 readData += mFifoBuffer->convertFramesToBytes(result);
163*05767d91SRobert Wu                 framesLeft -= result;
164*05767d91SRobert Wu             }
165*05767d91SRobert Wu         } else {
166*05767d91SRobert Wu             // between zero and capacity
167*05767d91SRobert Wu             uint32_t fullFrames = mFifoBuffer->getFullFramesAvailable();
168*05767d91SRobert Wu             // Do not write above threshold size.
169*05767d91SRobert Wu             int32_t emptyFrames = getBufferSizeInFrames() - static_cast<int32_t>(fullFrames);
170*05767d91SRobert Wu             int32_t framesToWrite = std::max(0, std::min(framesLeft, emptyFrames));
171*05767d91SRobert Wu             result = mFifoBuffer->write(writeData, framesToWrite);
172*05767d91SRobert Wu             if (result > 0) {
173*05767d91SRobert Wu                 writeData += mFifoBuffer->convertFramesToBytes(result);
174*05767d91SRobert Wu                 framesLeft -= result;
175*05767d91SRobert Wu             }
176*05767d91SRobert Wu         }
177*05767d91SRobert Wu 
178*05767d91SRobert Wu         // If we need more data then sleep and try again.
179*05767d91SRobert Wu         if (framesLeft > 0 && result >= 0 && timeoutNanoseconds > 0) {
180*05767d91SRobert Wu             int64_t timeNow = AudioClock::getNanoseconds();
181*05767d91SRobert Wu             if (timeNow >= timeToQuit) {
182*05767d91SRobert Wu                 LOGE("AudioStreamBuffered::%s(): TIMEOUT", __func__);
183*05767d91SRobert Wu                 repeat = false; // TIMEOUT
184*05767d91SRobert Wu             } else {
185*05767d91SRobert Wu                 // Figure out how long to sleep.
186*05767d91SRobert Wu                 int64_t sleepForNanos;
187*05767d91SRobert Wu                 int64_t wakeTimeNanos = predictNextCallbackTime();
188*05767d91SRobert Wu                 if (wakeTimeNanos <= 0) {
189*05767d91SRobert Wu                     // No estimate available. Sleep for one burst.
190*05767d91SRobert Wu                     sleepForNanos = (getFramesPerBurst() * kNanosPerSecond) / getSampleRate();
191*05767d91SRobert Wu                 } else {
192*05767d91SRobert Wu                     // Don't sleep past timeout.
193*05767d91SRobert Wu                     if (wakeTimeNanos > timeToQuit) {
194*05767d91SRobert Wu                         wakeTimeNanos = timeToQuit;
195*05767d91SRobert Wu                     }
196*05767d91SRobert Wu                     sleepForNanos = wakeTimeNanos - timeNow;
197*05767d91SRobert Wu                     // Avoid rapid loop with no sleep.
198*05767d91SRobert Wu                     const int64_t minSleepTime = kNanosPerMillisecond; // arbitrary
199*05767d91SRobert Wu                     if (sleepForNanos < minSleepTime) {
200*05767d91SRobert Wu                         sleepForNanos = minSleepTime;
201*05767d91SRobert Wu                     }
202*05767d91SRobert Wu                 }
203*05767d91SRobert Wu 
204*05767d91SRobert Wu                 AudioClock::sleepForNanos(sleepForNanos);
205*05767d91SRobert Wu             }
206*05767d91SRobert Wu 
207*05767d91SRobert Wu         } else {
208*05767d91SRobert Wu             repeat = false;
209*05767d91SRobert Wu         }
210*05767d91SRobert Wu     } while(repeat);
211*05767d91SRobert Wu 
212*05767d91SRobert Wu     if (result < 0) {
213*05767d91SRobert Wu         return ResultWithValue<int32_t>(static_cast<Result>(result));
214*05767d91SRobert Wu     } else {
215*05767d91SRobert Wu         int32_t framesWritten = numFrames - framesLeft;
216*05767d91SRobert Wu         return ResultWithValue<int32_t>(framesWritten);
217*05767d91SRobert Wu     }
218*05767d91SRobert Wu }
219*05767d91SRobert Wu 
220*05767d91SRobert Wu // Write to the FIFO so the callback can read from it.
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)221*05767d91SRobert Wu ResultWithValue<int32_t> AudioStreamBuffered::write(const void *buffer,
222*05767d91SRobert Wu                                    int32_t numFrames,
223*05767d91SRobert Wu                                    int64_t timeoutNanoseconds) {
224*05767d91SRobert Wu     if (getState() == StreamState::Closed){
225*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorClosed);
226*05767d91SRobert Wu     }
227*05767d91SRobert Wu 
228*05767d91SRobert Wu     if (getDirection() == Direction::Input) {
229*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorUnavailable); // TODO review, better error code?
230*05767d91SRobert Wu     }
231*05767d91SRobert Wu     Result result = updateServiceFrameCounter();
232*05767d91SRobert Wu     if (result != Result::OK) return ResultWithValue<int32_t>(static_cast<Result>(result));
233*05767d91SRobert Wu     return transfer(nullptr, buffer, numFrames, timeoutNanoseconds);
234*05767d91SRobert Wu }
235*05767d91SRobert Wu 
236*05767d91SRobert Wu // Read data from the FIFO that was written by the callback.
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)237*05767d91SRobert Wu ResultWithValue<int32_t> AudioStreamBuffered::read(void *buffer,
238*05767d91SRobert Wu                                   int32_t numFrames,
239*05767d91SRobert Wu                                   int64_t timeoutNanoseconds) {
240*05767d91SRobert Wu     if (getState() == StreamState::Closed){
241*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorClosed);
242*05767d91SRobert Wu     }
243*05767d91SRobert Wu 
244*05767d91SRobert Wu     if (getDirection() == Direction::Output) {
245*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorUnavailable); // TODO review, better error code?
246*05767d91SRobert Wu     }
247*05767d91SRobert Wu     Result result = updateServiceFrameCounter();
248*05767d91SRobert Wu     if (result != Result::OK) return ResultWithValue<int32_t>(static_cast<Result>(result));
249*05767d91SRobert Wu     return transfer(buffer, nullptr, numFrames, timeoutNanoseconds);
250*05767d91SRobert Wu }
251*05767d91SRobert Wu 
252*05767d91SRobert Wu // Only supported when we are not using a callback.
setBufferSizeInFrames(int32_t requestedFrames)253*05767d91SRobert Wu ResultWithValue<int32_t> AudioStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames)
254*05767d91SRobert Wu {
255*05767d91SRobert Wu     if (getState() == StreamState::Closed){
256*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorClosed);
257*05767d91SRobert Wu     }
258*05767d91SRobert Wu 
259*05767d91SRobert Wu     if (!mFifoBuffer) {
260*05767d91SRobert Wu         return ResultWithValue<int32_t>(Result::ErrorUnimplemented);
261*05767d91SRobert Wu     }
262*05767d91SRobert Wu 
263*05767d91SRobert Wu     if (requestedFrames > mFifoBuffer->getBufferCapacityInFrames()) {
264*05767d91SRobert Wu         requestedFrames = mFifoBuffer->getBufferCapacityInFrames();
265*05767d91SRobert Wu     } else if (requestedFrames < getFramesPerBurst()) {
266*05767d91SRobert Wu         requestedFrames = getFramesPerBurst();
267*05767d91SRobert Wu     }
268*05767d91SRobert Wu     mBufferSizeInFrames = requestedFrames;
269*05767d91SRobert Wu     return ResultWithValue<int32_t>(requestedFrames);
270*05767d91SRobert Wu }
271*05767d91SRobert Wu 
getBufferCapacityInFrames() const272*05767d91SRobert Wu int32_t AudioStreamBuffered::getBufferCapacityInFrames() const {
273*05767d91SRobert Wu     if (mFifoBuffer) {
274*05767d91SRobert Wu         return mFifoBuffer->getBufferCapacityInFrames();
275*05767d91SRobert Wu     } else {
276*05767d91SRobert Wu         return AudioStream::getBufferCapacityInFrames();
277*05767d91SRobert Wu     }
278*05767d91SRobert Wu }
279*05767d91SRobert Wu 
isXRunCountSupported() const280*05767d91SRobert Wu bool AudioStreamBuffered::isXRunCountSupported() const {
281*05767d91SRobert Wu     // XRun count is only supported if we're using blocking I/O (not callbacks)
282*05767d91SRobert Wu     return (!isDataCallbackSpecified());
283*05767d91SRobert Wu }
284*05767d91SRobert Wu 
285*05767d91SRobert Wu } // namespace oboe
286