• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "FullDuplexStream.h"
18 
onAudioReady(oboe::AudioStream * outputStream,void * audioData,int numFrames)19 oboe::DataCallbackResult FullDuplexStream::onAudioReady(
20         oboe::AudioStream *outputStream,
21         void *audioData,
22         int numFrames) {
23     oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Continue;
24     int32_t actualFramesRead = 0;
25 
26     // Silence the output.
27     int32_t numBytes = numFrames * outputStream->getBytesPerFrame();
28     memset(audioData, 0 /* value */, numBytes);
29 
30     if (mCountCallbacksToDrain > 0) {
31         // Drain the input.
32         int32_t totalFramesRead = 0;
33         do {
34             oboe::ResultWithValue<int32_t> result = mInputStream->read(mInputBuffer.get(),
35                                                                            numFrames,
36                                                                            0 /* timeout */);
37             if (!result) {
38                 // Ignore errors because input stream may not be started yet.
39                 break;
40             }
41             actualFramesRead = result.value();
42             totalFramesRead += actualFramesRead;
43         } while (actualFramesRead > 0);
44         // Only counts if we actually got some data.
45         if (totalFramesRead > 0) {
46             mCountCallbacksToDrain--;
47         }
48 
49     } else if (mCountInputBurstsCushion > 0) {
50         // Let the input fill up a bit so we are not so close to the write pointer.
51         mCountInputBurstsCushion--;
52 
53     } else if (mCountCallbacksToDiscard > 0) {
54         // Ignore. Allow the input to reach to equilibrium with the output.
55         oboe::ResultWithValue<int32_t> result = mInputStream->read(mInputBuffer.get(),
56                                                                        numFrames,
57                                                                        0 /* timeout */);
58         if (!result) {
59             callbackResult = oboe::DataCallbackResult::Stop;
60         }
61         mCountCallbacksToDiscard--;
62 
63     } else {
64         // Read data into input buffer.
65         oboe::ResultWithValue<int32_t> result = mInputStream->read(mInputBuffer.get(),
66                                                                        numFrames,
67                                                                        0 /* timeout */);
68         if (!result) {
69             callbackResult = oboe::DataCallbackResult::Stop;
70         } else {
71             int32_t framesRead = result.value();
72 
73             callbackResult = onBothStreamsReady(
74                     mInputStream, mInputBuffer.get(), framesRead,
75                     mOutputStream, audioData, numFrames
76             );
77         }
78     }
79 
80     if (callbackResult == oboe::DataCallbackResult::Stop) {
81         mInputStream->requestStop();
82     }
83 
84     return callbackResult;
85 }
86 
start()87 oboe::Result FullDuplexStream::start() {
88     mCountCallbacksToDrain = kNumCallbacksToDrain;
89     mCountInputBurstsCushion = mNumInputBurstsCushion;
90     mCountCallbacksToDiscard = kNumCallbacksToDiscard;
91 
92     // Determine maximum size that could possibly be called.
93     int32_t bufferSize = mOutputStream->getBufferCapacityInFrames()
94             * mOutputStream->getChannelCount();
95     if (bufferSize > mBufferSize) {
96         mInputBuffer = std::make_unique<float[]>(bufferSize);
97         mBufferSize = bufferSize;
98     }
99     oboe::Result result = mInputStream->requestStart();
100     if (result != oboe::Result::OK) {
101         return result;
102     }
103     return mOutputStream->requestStart();
104 }
105 
stop()106 oboe::Result FullDuplexStream::stop() {
107     oboe::Result outputResult = oboe::Result::OK;
108     oboe::Result inputResult = oboe::Result::OK;
109     if (mOutputStream) {
110         outputResult = mOutputStream->requestStop();
111     }
112     if (mInputStream) {
113         inputResult = mInputStream->requestStop();
114     }
115     if (outputResult != oboe::Result::OK) {
116         return outputResult;
117     } else {
118         return inputResult;
119     }
120 }
121 
getNumInputBurstsCushion() const122 int32_t FullDuplexStream::getNumInputBurstsCushion() const {
123     return mNumInputBurstsCushion;
124 }
125 
setNumInputBurstsCushion(int32_t numBursts)126 void FullDuplexStream::setNumInputBurstsCushion(int32_t numBursts) {
127     FullDuplexStream::mNumInputBurstsCushion = numBursts;
128 }
129