xref: /aosp_15_r20/external/oboe/src/common/DataConversionFlowGraph.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /*
2  * Copyright (C) 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 "DataConversionFlowGraph.h"
21 #include "SourceFloatCaller.h"
22 #include "SourceI16Caller.h"
23 #include "SourceI24Caller.h"
24 #include "SourceI32Caller.h"
25 
26 #include <flowgraph/MonoToMultiConverter.h>
27 #include <flowgraph/MultiToMonoConverter.h>
28 #include <flowgraph/RampLinear.h>
29 #include <flowgraph/SinkFloat.h>
30 #include <flowgraph/SinkI16.h>
31 #include <flowgraph/SinkI24.h>
32 #include <flowgraph/SinkI32.h>
33 #include <flowgraph/SourceFloat.h>
34 #include <flowgraph/SourceI16.h>
35 #include <flowgraph/SourceI24.h>
36 #include <flowgraph/SourceI32.h>
37 #include <flowgraph/SampleRateConverter.h>
38 
39 using namespace oboe;
40 using namespace flowgraph;
41 using namespace resampler;
42 
setSource(const void * buffer,int32_t numFrames)43 void DataConversionFlowGraph::setSource(const void *buffer, int32_t numFrames) {
44     mSource->setData(buffer, numFrames);
45 }
46 
convertOboeSRQualityToMCR(SampleRateConversionQuality quality)47 static MultiChannelResampler::Quality convertOboeSRQualityToMCR(SampleRateConversionQuality quality) {
48     switch (quality) {
49         case SampleRateConversionQuality::Fastest:
50             return MultiChannelResampler::Quality::Fastest;
51         case SampleRateConversionQuality::Low:
52             return MultiChannelResampler::Quality::Low;
53         default:
54         case SampleRateConversionQuality::Medium:
55             return MultiChannelResampler::Quality::Medium;
56         case SampleRateConversionQuality::High:
57             return MultiChannelResampler::Quality::High;
58         case SampleRateConversionQuality::Best:
59             return MultiChannelResampler::Quality::Best;
60     }
61 }
62 
63 // Chain together multiple processors.
64 // Callback Output
65 //     Use SourceCaller that calls original app callback from the flowgraph.
66 //     The child callback from FilteredAudioStream read()s from the flowgraph.
67 // Callback Input
68 //     Child callback from FilteredAudioStream writes()s to the flowgraph.
69 //     The output of the flowgraph goes through a BlockWriter to the app callback.
70 // Blocking Write
71 //     Write buffer is set on an AudioSource.
72 //     Data is pulled through the graph and written to the child stream.
73 // Blocking Read
74 //     Reads in a loop from the flowgraph Sink to fill the read buffer.
75 //     A SourceCaller then does a blocking read from the child Stream.
76 //
configure(AudioStream * sourceStream,AudioStream * sinkStream)77 Result DataConversionFlowGraph::configure(AudioStream *sourceStream, AudioStream *sinkStream) {
78 
79     FlowGraphPortFloatOutput *lastOutput = nullptr;
80 
81     bool isOutput = sourceStream->getDirection() == Direction::Output;
82     bool isInput = !isOutput;
83     mFilterStream = isOutput ? sourceStream : sinkStream;
84 
85     AudioFormat sourceFormat = sourceStream->getFormat();
86     int32_t sourceChannelCount = sourceStream->getChannelCount();
87     int32_t sourceSampleRate = sourceStream->getSampleRate();
88     int32_t sourceFramesPerCallback = sourceStream->getFramesPerDataCallback();
89 
90     AudioFormat sinkFormat = sinkStream->getFormat();
91     int32_t sinkChannelCount = sinkStream->getChannelCount();
92     int32_t sinkSampleRate = sinkStream->getSampleRate();
93     int32_t sinkFramesPerCallback = sinkStream->getFramesPerDataCallback();
94 
95     LOGI("%s() flowgraph converts channels: %d to %d, format: %s to %s"
96             ", rate: %d to %d, cbsize: %d to %d, qual = %s",
97             __func__,
98             sourceChannelCount, sinkChannelCount,
99             oboe::convertToText(sourceFormat), oboe::convertToText(sinkFormat),
100             sourceSampleRate, sinkSampleRate,
101             sourceFramesPerCallback, sinkFramesPerCallback,
102             oboe::convertToText(sourceStream->getSampleRateConversionQuality()));
103 
104     // Source
105     // IF OUTPUT and using a callback then call back to the app using a SourceCaller.
106     // OR IF INPUT and NOT using a callback then read from the child stream using a SourceCaller.
107     bool isDataCallbackSpecified = sourceStream->isDataCallbackSpecified();
108     if ((isDataCallbackSpecified && isOutput)
109         || (!isDataCallbackSpecified && isInput)) {
110         int32_t actualSourceFramesPerCallback = (sourceFramesPerCallback == kUnspecified)
111                 ? sourceStream->getFramesPerBurst()
112                 : sourceFramesPerCallback;
113         switch (sourceFormat) {
114             case AudioFormat::Float:
115                 mSourceCaller = std::make_unique<SourceFloatCaller>(sourceChannelCount,
116                                                                     actualSourceFramesPerCallback);
117                 break;
118             case AudioFormat::I16:
119                 mSourceCaller = std::make_unique<SourceI16Caller>(sourceChannelCount,
120                                                                   actualSourceFramesPerCallback);
121                 break;
122             case AudioFormat::I24:
123                 mSourceCaller = std::make_unique<SourceI24Caller>(sourceChannelCount,
124                                                                   actualSourceFramesPerCallback);
125                 break;
126             case AudioFormat::I32:
127                 mSourceCaller = std::make_unique<SourceI32Caller>(sourceChannelCount,
128                                                                   actualSourceFramesPerCallback);
129                 break;
130             default:
131                 LOGE("%s() Unsupported source caller format = %d", __func__, static_cast<int>(sourceFormat));
132                 return Result::ErrorIllegalArgument;
133         }
134         mSourceCaller->setStream(sourceStream);
135         lastOutput = &mSourceCaller->output;
136     } else {
137         // IF OUTPUT and NOT using a callback then write to the child stream using a BlockWriter.
138         // OR IF INPUT and using a callback then write to the app using a BlockWriter.
139         switch (sourceFormat) {
140             case AudioFormat::Float:
141                 mSource = std::make_unique<SourceFloat>(sourceChannelCount);
142                 break;
143             case AudioFormat::I16:
144                 mSource = std::make_unique<SourceI16>(sourceChannelCount);
145                 break;
146             case AudioFormat::I24:
147                 mSource = std::make_unique<SourceI24>(sourceChannelCount);
148                 break;
149             case AudioFormat::I32:
150                 mSource = std::make_unique<SourceI32>(sourceChannelCount);
151                 break;
152             default:
153                 LOGE("%s() Unsupported source format = %d", __func__, static_cast<int>(sourceFormat));
154                 return Result::ErrorIllegalArgument;
155         }
156         if (isInput) {
157             int32_t actualSinkFramesPerCallback = (sinkFramesPerCallback == kUnspecified)
158                     ? sinkStream->getFramesPerBurst()
159                     : sinkFramesPerCallback;
160             // The BlockWriter is after the Sink so use the SinkStream size.
161             mBlockWriter.open(actualSinkFramesPerCallback * sinkStream->getBytesPerFrame());
162             mAppBuffer = std::make_unique<uint8_t[]>(
163                     kDefaultBufferSize * sinkStream->getBytesPerFrame());
164         }
165         lastOutput = &mSource->output;
166     }
167 
168     // If we are going to reduce the number of channels then do it before the
169     // sample rate converter.
170     if (sourceChannelCount > sinkChannelCount) {
171         if (sinkChannelCount == 1) {
172             mMultiToMonoConverter = std::make_unique<MultiToMonoConverter>(sourceChannelCount);
173             lastOutput->connect(&mMultiToMonoConverter->input);
174             lastOutput = &mMultiToMonoConverter->output;
175         } else {
176             mChannelCountConverter = std::make_unique<ChannelCountConverter>(
177                     sourceChannelCount,
178                     sinkChannelCount);
179             lastOutput->connect(&mChannelCountConverter->input);
180             lastOutput = &mChannelCountConverter->output;
181         }
182     }
183 
184     // Sample Rate conversion
185     if (sourceSampleRate != sinkSampleRate) {
186         // Create a resampler to do the math.
187         mResampler.reset(MultiChannelResampler::make(lastOutput->getSamplesPerFrame(),
188                                                      sourceSampleRate,
189                                                      sinkSampleRate,
190                                                      convertOboeSRQualityToMCR(
191                                                              sourceStream->getSampleRateConversionQuality())));
192         // Make a flowgraph node that uses the resampler.
193         mRateConverter = std::make_unique<SampleRateConverter>(lastOutput->getSamplesPerFrame(),
194                                                                *mResampler.get());
195         lastOutput->connect(&mRateConverter->input);
196         lastOutput = &mRateConverter->output;
197     }
198 
199     // Expand the number of channels if required.
200     if (sourceChannelCount < sinkChannelCount) {
201         if (sourceChannelCount == 1) {
202             mMonoToMultiConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
203             lastOutput->connect(&mMonoToMultiConverter->input);
204             lastOutput = &mMonoToMultiConverter->output;
205         } else {
206             mChannelCountConverter = std::make_unique<ChannelCountConverter>(
207                     sourceChannelCount,
208                     sinkChannelCount);
209             lastOutput->connect(&mChannelCountConverter->input);
210             lastOutput = &mChannelCountConverter->output;
211         }
212     }
213 
214     // Sink
215     switch (sinkFormat) {
216         case AudioFormat::Float:
217             mSink = std::make_unique<SinkFloat>(sinkChannelCount);
218             break;
219         case AudioFormat::I16:
220             mSink = std::make_unique<SinkI16>(sinkChannelCount);
221             break;
222         case AudioFormat::I24:
223             mSink = std::make_unique<SinkI24>(sinkChannelCount);
224             break;
225         case AudioFormat::I32:
226             mSink = std::make_unique<SinkI32>(sinkChannelCount);
227             break;
228         default:
229             LOGE("%s() Unsupported sink format = %d", __func__, static_cast<int>(sinkFormat));
230             return Result::ErrorIllegalArgument;;
231     }
232     lastOutput->connect(&mSink->input);
233 
234     return Result::OK;
235 }
236 
read(void * buffer,int32_t numFrames,int64_t timeoutNanos)237 int32_t DataConversionFlowGraph::read(void *buffer, int32_t numFrames, int64_t timeoutNanos) {
238     if (mSourceCaller) {
239         mSourceCaller->setTimeoutNanos(timeoutNanos);
240     }
241     int32_t numRead = mSink->read(buffer, numFrames);
242     return numRead;
243 }
244 
245 // This is similar to pushing data through the flowgraph.
write(void * inputBuffer,int32_t numFrames)246 int32_t DataConversionFlowGraph::write(void *inputBuffer, int32_t numFrames) {
247     // Put the data from the input at the head of the flowgraph.
248     mSource->setData(inputBuffer, numFrames);
249     while (true) {
250         // Pull and read some data in app format into a small buffer.
251         int32_t framesRead = mSink->read(mAppBuffer.get(), flowgraph::kDefaultBufferSize);
252         if (framesRead <= 0) break;
253         // Write to a block adapter, which will call the destination whenever it has enough data.
254         int32_t bytesRead = mBlockWriter.write(mAppBuffer.get(),
255                                                framesRead * mFilterStream->getBytesPerFrame());
256         if (bytesRead < 0) return bytesRead; // TODO review
257     }
258     return numFrames;
259 }
260 
onProcessFixedBlock(uint8_t * buffer,int32_t numBytes)261 int32_t DataConversionFlowGraph::onProcessFixedBlock(uint8_t *buffer, int32_t numBytes) {
262     int32_t numFrames = numBytes / mFilterStream->getBytesPerFrame();
263     mCallbackResult = mFilterStream->getDataCallback()->onAudioReady(mFilterStream, buffer, numFrames);
264     // TODO handle STOP from callback, process data remaining in the block adapter
265     return numBytes;
266 }
267