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