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