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