Oboe
A library for creating real-time audio apps on Android
Loading...
Searching...
No Matches
FullDuplexStream.h
1/*
2 * Copyright 2023 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#ifndef OBOE_FULL_DUPLEX_STREAM_
18#define OBOE_FULL_DUPLEX_STREAM_
19
20#include <cstdint>
21#include "oboe/Definitions.h"
22#include "oboe/AudioStream.h"
23#include "oboe/AudioStreamCallback.h"
24
25namespace oboe {
26
51public:
53 virtual ~FullDuplexStream() = default;
54
61 mInputStream = stream;
62 }
63
70 return mInputStream;
71 }
72
79 mOutputStream = stream;
80 }
81
88 return mOutputStream;
89 }
90
97 virtual Result start() {
98 mCountCallbacksToDrain = kNumCallbacksToDrain;
99 mCountInputBurstsCushion = mNumInputBurstsCushion;
100 mCountCallbacksToDiscard = kNumCallbacksToDiscard;
101
102 // Determine maximum size that could possibly be called.
105 if (bufferSize > mBufferSize) {
106 mInputBuffer = std::make_unique<float[]>(bufferSize);
107 mBufferSize = bufferSize;
108 }
109
111 if (result != oboe::Result::OK) {
112 return result;
113 }
114 return getOutputStream()->requestStart();
115 }
116
122 virtual Result stop() {
123 Result outputResult = Result::OK;
124 Result inputResult = Result::OK;
125 if (getOutputStream()) {
126 outputResult = mOutputStream->requestStop();
127 }
128 if (getInputStream()) {
129 inputResult = mInputStream->requestStop();
130 }
131 if (outputResult != Result::OK) {
132 return outputResult;
133 } else {
134 return inputResult;
135 }
136 }
137
146 return getInputStream()->read(mInputBuffer.get(), numFrames, 0 /* timeout */);
147 }
148
161 const void *inputData,
162 int numInputFrames,
163 void *outputData,
165 ) = 0;
166
180 AudioStream * /*audioStream*/,
181 void *audioData,
182 int numFrames) {
183 DataCallbackResult callbackResult = DataCallbackResult::Continue;
185
186 // Silence the output.
188 memset(audioData, 0 /* value */, numBytes);
189
190 if (mCountCallbacksToDrain > 0) {
191 // Drain the input.
193 do {
195 if (!result) {
196 // Ignore errors because input stream may not be started yet.
197 break;
198 }
201 } while (actualFramesRead > 0);
202 // Only counts if we actually got some data.
203 if (totalFramesRead > 0) {
204 mCountCallbacksToDrain--;
205 }
206
207 } else if (mCountInputBurstsCushion > 0) {
208 // Let the input fill up a bit so we are not so close to the write pointer.
209 mCountInputBurstsCushion--;
210
211 } else if (mCountCallbacksToDiscard > 0) {
212 mCountCallbacksToDiscard--;
213 // Ignore. Allow the input to reach to equilibrium with the output.
215 if (!resultAvailable) {
216 callbackResult = DataCallbackResult::Stop;
217 } else {
219 if (framesAvailable >= mMinimumFramesBeforeRead) {
221 if (!resultRead) {
222 callbackResult = DataCallbackResult::Stop;
223 }
224 }
225 }
226 } else {
229 if (!resultAvailable) {
230 callbackResult = DataCallbackResult::Stop;
231 } else {
233 if (framesAvailable >= mMinimumFramesBeforeRead) {
234 // Read data into input buffer.
236 if (!resultRead) {
237 callbackResult = DataCallbackResult::Stop;
238 } else {
240 }
241 }
242 }
243
244 if (callbackResult == DataCallbackResult::Continue) {
245 callbackResult = onBothStreamsReady(mInputBuffer.get(), framesRead,
247 }
248 }
249
250 if (callbackResult == DataCallbackResult::Stop) {
252 }
253
254 return callbackResult;
255 }
256
265 mNumInputBurstsCushion = numBursts;
266 }
267
274 return mNumInputBurstsCushion;
275 }
276
283 mMinimumFramesBeforeRead = numFrames;
284 }
285
292 return mMinimumFramesBeforeRead;
293 }
294
295private:
296
297 // TODO add getters and setters
298 static constexpr int32_t kNumCallbacksToDrain = 20;
299 static constexpr int32_t kNumCallbacksToDiscard = 30;
300
301 // let input fill back up, usually 0 or 1
302 int32_t mNumInputBurstsCushion = 0;
303 int32_t mMinimumFramesBeforeRead = 0;
304
305 // We want to reach a state where the input buffer is empty and
306 // the output buffer is full.
307 // These are used in order.
308 // Drain several callback so that input is empty.
309 int32_t mCountCallbacksToDrain = kNumCallbacksToDrain;
310 // Let the input fill back up slightly so we don't run dry.
311 int32_t mCountInputBurstsCushion = mNumInputBurstsCushion;
312 // Discard some callbacks so the input and output reach equilibrium.
313 int32_t mCountCallbacksToDiscard = kNumCallbacksToDiscard;
314
315 AudioStream *mInputStream = nullptr;
316 AudioStream *mOutputStream = nullptr;
317
318 int32_t mBufferSize = 0;
319 std::unique_ptr<float[]> mInputBuffer;
320};
321
322} // namespace oboe
323
324#endif //OBOE_FULL_DUPLEX_STREAM_
int32_t getChannelCount() const
Definition AudioStreamBase.h:53
virtual int32_t getBufferCapacityInFrames() const
Definition AudioStreamBase.h:91
Definition AudioStreamCallback.h:34
Definition AudioStream.h:44
virtual Result requestStart()=0
virtual ResultWithValue< int32_t > read(void *, int32_t, int64_t)
Definition AudioStream.h:386
int32_t getBytesPerFrame() const
Definition AudioStream.h:249
virtual Result requestStop()=0
ResultWithValue< int32_t > getAvailableFrames()
Definition FullDuplexStream.h:50
void setOutputStream(AudioStream *stream)
Definition FullDuplexStream.h:78
int32_t getMinimumFramesBeforeRead() const
Definition FullDuplexStream.h:291
virtual Result stop()
Definition FullDuplexStream.h:122
void setNumInputBurstsCushion(int32_t numBursts)
Definition FullDuplexStream.h:264
virtual ResultWithValue< int32_t > readInput(int32_t numFrames)
Definition FullDuplexStream.h:145
AudioStream * getOutputStream()
Definition FullDuplexStream.h:87
virtual DataCallbackResult onBothStreamsReady(const void *inputData, int numInputFrames, void *outputData, int numOutputFrames)=0
AudioStream * getInputStream()
Definition FullDuplexStream.h:69
DataCallbackResult onAudioReady(AudioStream *, void *audioData, int numFrames)
Definition FullDuplexStream.h:179
int32_t getNumInputBurstsCushion() const
Definition FullDuplexStream.h:273
void setInputStream(AudioStream *stream)
Definition FullDuplexStream.h:60
void setMinimumFramesBeforeRead(int32_t numFrames)
Definition FullDuplexStream.h:282
virtual Result start()
Definition FullDuplexStream.h:97
Definition ResultWithValue.h:47
T value() const
Definition ResultWithValue.h:81
Definition AudioStream.h:31
Result
Definition Definitions.h:172
DataCallbackResult
Definition Definitions.h:160