1 /*
2  * Copyright (C) 2018 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 #define LOG_TAG "AAudioFlowGraph"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include "AAudioFlowGraph.h"
22 
23 #include <flowgraph/Limiter.h>
24 #include <flowgraph/ManyToMultiConverter.h>
25 #include <flowgraph/MonoBlend.h>
26 #include <flowgraph/MonoToMultiConverter.h>
27 #include <flowgraph/MultiToManyConverter.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/SinkI8_24.h>
34 #include <flowgraph/SourceFloat.h>
35 #include <flowgraph/SourceI16.h>
36 #include <flowgraph/SourceI24.h>
37 #include <flowgraph/SourceI32.h>
38 #include <flowgraph/SourceI8_24.h>
39 
40 using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
41 
configure(audio_format_t sourceFormat,int32_t sourceChannelCount,int32_t sourceSampleRate,audio_format_t sinkFormat,int32_t sinkChannelCount,int32_t sinkSampleRate,bool useMonoBlend,bool useVolumeRamps,float audioBalance,aaudio::resampler::MultiChannelResampler::Quality resamplerQuality)42 aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat,
43                           int32_t sourceChannelCount,
44                           int32_t sourceSampleRate,
45                           audio_format_t sinkFormat,
46                           int32_t sinkChannelCount,
47                           int32_t sinkSampleRate,
48                           bool useMonoBlend,
49                           bool useVolumeRamps,
50                           float audioBalance,
51                           aaudio::resampler::MultiChannelResampler::Quality resamplerQuality) {
52     FlowGraphPortFloatOutput *lastOutput = nullptr;
53 
54     ALOGD("%s() source format = 0x%08x, channels = %d, sample rate = %d, "
55           "sink format = 0x%08x, channels = %d, sample rate = %d, "
56           "useMonoBlend = %d, audioBalance = %f, useVolumeRamps %d",
57           __func__, sourceFormat, sourceChannelCount, sourceSampleRate, sinkFormat,
58           sinkChannelCount, sinkSampleRate, useMonoBlend, audioBalance, useVolumeRamps);
59 
60     switch (sourceFormat) {
61         case AUDIO_FORMAT_PCM_FLOAT:
62             mSource = std::make_unique<SourceFloat>(sourceChannelCount);
63             break;
64         case AUDIO_FORMAT_PCM_16_BIT:
65             mSource = std::make_unique<SourceI16>(sourceChannelCount);
66             break;
67         case AUDIO_FORMAT_PCM_24_BIT_PACKED:
68             mSource = std::make_unique<SourceI24>(sourceChannelCount);
69             break;
70         case AUDIO_FORMAT_PCM_32_BIT:
71             mSource = std::make_unique<SourceI32>(sourceChannelCount);
72             break;
73         case AUDIO_FORMAT_PCM_8_24_BIT:
74             mSource = std::make_unique<SourceI8_24>(sourceChannelCount);
75             break;
76         default:
77             ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
78             return AAUDIO_ERROR_UNIMPLEMENTED;
79     }
80     lastOutput = &mSource->output;
81 
82     if (useMonoBlend) {
83         mMonoBlend = std::make_unique<MonoBlend>(sourceChannelCount);
84         lastOutput->connect(&mMonoBlend->input);
85         lastOutput = &mMonoBlend->output;
86     }
87 
88     // For a pure float graph, there is chance that the data range may be very large.
89     // So we should limit to a reasonable value that allows a little headroom.
90     if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT && sinkFormat == AUDIO_FORMAT_PCM_FLOAT) {
91         mLimiter = std::make_unique<Limiter>(sourceChannelCount);
92         lastOutput->connect(&mLimiter->input);
93         lastOutput = &mLimiter->output;
94     }
95 
96     if (sourceSampleRate != sinkSampleRate) {
97         mResampler.reset(aaudio::resampler::MultiChannelResampler::make(sourceChannelCount,
98                 sourceSampleRate, sinkSampleRate, resamplerQuality));
99         mRateConverter = std::make_unique<SampleRateConverter>(sourceChannelCount,
100                                                                *mResampler);
101         lastOutput->connect(&mRateConverter->input);
102         lastOutput = &mRateConverter->output;
103     }
104 
105     // Expand the number of channels if required.
106     if (sourceChannelCount == 1 && sinkChannelCount > 1) {
107         mChannelConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
108         lastOutput->connect(&mChannelConverter->input);
109         lastOutput = &mChannelConverter->output;
110     } else if (sourceChannelCount != sinkChannelCount) {
111         ALOGE("%s() Channel reduction not supported.", __func__);
112         return AAUDIO_ERROR_UNIMPLEMENTED;
113     }
114 
115     if (useVolumeRamps) {
116         // Apply volume ramps to set the left/right audio balance and target volumes.
117         // The signals will be decoupled, volume ramps will be applied, before the signals are
118         // combined again.
119         mMultiToManyConverter = std::make_unique<MultiToManyConverter>(sinkChannelCount);
120         mManyToMultiConverter = std::make_unique<ManyToMultiConverter>(sinkChannelCount);
121         lastOutput->connect(&mMultiToManyConverter->input);
122         for (int i = 0; i < sinkChannelCount; i++) {
123             mVolumeRamps.emplace_back(std::make_unique<RampLinear>(1));
124             mPanningVolumes.emplace_back(1.0f);
125             lastOutput = mMultiToManyConverter->outputs[i].get();
126             lastOutput->connect(&(mVolumeRamps[i].get()->input));
127             lastOutput = &(mVolumeRamps[i].get()->output);
128             lastOutput->connect(mManyToMultiConverter->inputs[i].get());
129         }
130         lastOutput = &mManyToMultiConverter->output;
131         setAudioBalance(audioBalance);
132     }
133 
134     switch (sinkFormat) {
135         case AUDIO_FORMAT_PCM_FLOAT:
136             mSink = std::make_unique<SinkFloat>(sinkChannelCount);
137             break;
138         case AUDIO_FORMAT_PCM_16_BIT:
139             mSink = std::make_unique<SinkI16>(sinkChannelCount);
140             break;
141         case AUDIO_FORMAT_PCM_24_BIT_PACKED:
142             mSink = std::make_unique<SinkI24>(sinkChannelCount);
143             break;
144         case AUDIO_FORMAT_PCM_32_BIT:
145             mSink = std::make_unique<SinkI32>(sinkChannelCount);
146             break;
147         case AUDIO_FORMAT_PCM_8_24_BIT:
148             mSink = std::make_unique<SinkI8_24>(sinkChannelCount);
149             break;
150         default:
151             ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
152             return AAUDIO_ERROR_UNIMPLEMENTED;
153     }
154     lastOutput->connect(&mSink->input);
155 
156     return AAUDIO_OK;
157 }
158 
pull(void * destination,int32_t targetFramesToRead)159 int32_t AAudioFlowGraph::pull(void *destination, int32_t targetFramesToRead) {
160     return mSink->read(destination, targetFramesToRead);
161 }
162 
process(const void * source,int32_t numFramesToWrite,void * destination,int32_t targetFramesToRead)163 int32_t AAudioFlowGraph::process(const void *source, int32_t numFramesToWrite, void *destination,
164                     int32_t targetFramesToRead) {
165     mSource->setData(source, numFramesToWrite);
166     return mSink->read(destination, targetFramesToRead);
167 }
168 
169 /**
170  * @param volume between 0.0 and 1.0
171  */
setTargetVolume(float volume)172 void AAudioFlowGraph::setTargetVolume(float volume) {
173     for (int i = 0; i < mVolumeRamps.size(); i++) {
174         mVolumeRamps[i]->setTarget(volume * mPanningVolumes[i]);
175     }
176     mTargetVolume = volume;
177 }
178 
179 /**
180  * @param audioBalance between -1.0 and 1.0
181  */
setAudioBalance(float audioBalance)182 void AAudioFlowGraph::setAudioBalance(float audioBalance) {
183     if (mPanningVolumes.size() >= 2) {
184         float leftMultiplier = 0;
185         float rightMultiplier = 0;
186         mBalance.computeStereoBalance(audioBalance, &leftMultiplier, &rightMultiplier);
187         mPanningVolumes[0] = leftMultiplier;
188         mPanningVolumes[1] = rightMultiplier;
189         mVolumeRamps[0]->setTarget(mTargetVolume * leftMultiplier);
190         mVolumeRamps[1]->setTarget(mTargetVolume * rightMultiplier);
191     }
192 }
193 
194 /**
195  * @param numFrames to slowly adjust for volume changes
196  */
setRampLengthInFrames(int32_t numFrames)197 void AAudioFlowGraph::setRampLengthInFrames(int32_t numFrames) {
198     for (auto& ramp : mVolumeRamps) {
199         ramp->setLengthInFrames(numFrames);
200     }
201 }
202