xref: /aosp_15_r20/external/oboe/src/common/FilterAudioStream.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 <memory>
18 
19 #include "OboeDebug.h"
20 #include "FilterAudioStream.h"
21 
22 using namespace oboe;
23 using namespace flowgraph;
24 
25 // Output callback uses FixedBlockReader::read()
26 //                <= SourceFloatCaller::onProcess()
27 //                <=== DataConversionFlowGraph::read()
28 //                <== FilterAudioStream::onAudioReady()
29 //
30 // Output blocking uses no block adapter because AAudio can accept
31 // writes of any size. It uses DataConversionFlowGraph::read() <== FilterAudioStream::write() <= app
32 //
33 // Input callback uses FixedBlockWriter::write()
34 //                <= DataConversionFlowGraph::write()
35 //                <= FilterAudioStream::onAudioReady()
36 //
37 // Input blocking uses FixedBlockReader::read() // TODO may not need block adapter
38 //                <= SourceFloatCaller::onProcess()
39 //                <=== SinkFloat::read()
40 //                <= DataConversionFlowGraph::read()
41 //                <== FilterAudioStream::read()
42 //                <= app
43 
configureFlowGraph()44 Result FilterAudioStream::configureFlowGraph() {
45     mFlowGraph = std::make_unique<DataConversionFlowGraph>();
46     bool isOutput = getDirection() == Direction::Output;
47 
48     AudioStream *sourceStream =  isOutput ? this : mChildStream.get();
49     AudioStream *sinkStream =  isOutput ? mChildStream.get() : this;
50 
51     mRateScaler = ((double) getSampleRate()) / mChildStream->getSampleRate();
52 
53     return mFlowGraph->configure(sourceStream, sinkStream);
54 }
55 
56 // Put the data to be written at the source end of the flowgraph.
57 // Then read (pull) the data from the flowgraph and write it to the
58 // child stream.
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)59 ResultWithValue<int32_t> FilterAudioStream::write(const void *buffer,
60                                int32_t numFrames,
61                                int64_t timeoutNanoseconds) {
62     int32_t framesWritten = 0;
63     mFlowGraph->setSource(buffer, numFrames);
64     while (true) {
65         int32_t numRead = mFlowGraph->read(mBlockingBuffer.get(),
66                 getFramesPerBurst(),
67                 timeoutNanoseconds);
68         if (numRead < 0) {
69             return ResultWithValue<int32_t>::createBasedOnSign(numRead);
70         }
71         if (numRead == 0) {
72             break; // finished processing the source buffer
73         }
74         auto writeResult = mChildStream->write(mBlockingBuffer.get(),
75                                                numRead,
76                                                timeoutNanoseconds);
77         if (!writeResult) {
78             return writeResult;
79         }
80         framesWritten += writeResult.value();
81     }
82     return ResultWithValue<int32_t>::createBasedOnSign(framesWritten);
83 }
84 
85 // Read (pull) the data we want from the sink end of the flowgraph.
86 // The necessary data will be read from the child stream using a flowgraph callback.
read(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)87 ResultWithValue<int32_t> FilterAudioStream::read(void *buffer,
88                                                   int32_t numFrames,
89                                                   int64_t timeoutNanoseconds) {
90     int32_t framesRead = mFlowGraph->read(buffer, numFrames, timeoutNanoseconds);
91     return ResultWithValue<int32_t>::createBasedOnSign(framesRead);
92 }
93 
onAudioReady(AudioStream * oboeStream,void * audioData,int32_t numFrames)94 DataCallbackResult FilterAudioStream::onAudioReady(AudioStream *oboeStream,
95                                 void *audioData,
96                                 int32_t numFrames) {
97     int32_t framesProcessed;
98     if (oboeStream->getDirection() == Direction::Output) {
99         framesProcessed = mFlowGraph->read(audioData, numFrames, 0 /* timeout */);
100     } else {
101         framesProcessed = mFlowGraph->write(audioData, numFrames);
102     }
103     return (framesProcessed < numFrames)
104            ? DataCallbackResult::Stop
105            : mFlowGraph->getDataCallbackResult();
106 }
107