blob: 5b46ae0d3ac70e8b3c27793b419cbcc85712c729 [file] [log] [blame]
Phil Burk0127c1b2018-03-29 13:48:06 -07001/*
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>
Robert Wu8393bed2021-12-08 02:08:48 +000024#include <flowgraph/ManyToMultiConverter.h>
Robert Wud7400832021-12-04 01:11:19 +000025#include <flowgraph/MonoBlend.h>
Phil Burk0127c1b2018-03-29 13:48:06 -070026#include <flowgraph/MonoToMultiConverter.h>
Robert Wu8393bed2021-12-08 02:08:48 +000027#include <flowgraph/MultiToManyConverter.h>
Phil Burk0127c1b2018-03-29 13:48:06 -070028#include <flowgraph/RampLinear.h>
29#include <flowgraph/SinkFloat.h>
30#include <flowgraph/SinkI16.h>
31#include <flowgraph/SinkI24.h>
Phil Burk04e805b2018-03-27 09:13:53 -070032#include <flowgraph/SinkI32.h>
Phil Burk0127c1b2018-03-29 13:48:06 -070033#include <flowgraph/SourceFloat.h>
34#include <flowgraph/SourceI16.h>
35#include <flowgraph/SourceI24.h>
Phil Burk04e805b2018-03-27 09:13:53 -070036#include <flowgraph/SourceI32.h>
Phil Burk0127c1b2018-03-29 13:48:06 -070037
38using namespace flowgraph;
39
40aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat,
41 int32_t sourceChannelCount,
42 audio_format_t sinkFormat,
Robert Wud7400832021-12-04 01:11:19 +000043 int32_t sinkChannelCount,
Robert Wu8393bed2021-12-08 02:08:48 +000044 bool useMonoBlend,
45 float audioBalance) {
Robert Wu057f0832021-12-03 20:41:07 +000046 FlowGraphPortFloatOutput *lastOutput = nullptr;
Phil Burk0127c1b2018-03-29 13:48:06 -070047
Phil Burk04e805b2018-03-27 09:13:53 -070048 // TODO change back to ALOGD
Robert Wu8393bed2021-12-08 02:08:48 +000049 ALOGI("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d, "
50 "useMonoBlend = %d, audioBalance = %f",
51 __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount,
52 useMonoBlend, audioBalance);
Phil Burk0127c1b2018-03-29 13:48:06 -070053
54 switch (sourceFormat) {
55 case AUDIO_FORMAT_PCM_FLOAT:
56 mSource = std::make_unique<SourceFloat>(sourceChannelCount);
57 break;
58 case AUDIO_FORMAT_PCM_16_BIT:
59 mSource = std::make_unique<SourceI16>(sourceChannelCount);
60 break;
61 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
62 mSource = std::make_unique<SourceI24>(sourceChannelCount);
63 break;
Phil Burk04e805b2018-03-27 09:13:53 -070064 case AUDIO_FORMAT_PCM_32_BIT:
65 mSource = std::make_unique<SourceI32>(sourceChannelCount);
66 break;
67 default:
Phil Burk0127c1b2018-03-29 13:48:06 -070068 ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
69 return AAUDIO_ERROR_UNIMPLEMENTED;
70 }
71 lastOutput = &mSource->output;
72
Robert Wu8393bed2021-12-08 02:08:48 +000073 if (useMonoBlend) {
74 mMonoBlend = std::make_unique<MonoBlend>(sourceChannelCount);
75 lastOutput->connect(&mMonoBlend->input);
76 lastOutput = &mMonoBlend->output;
77 }
Phil Burk0127c1b2018-03-29 13:48:06 -070078
79 // For a pure float graph, there is chance that the data range may be very large.
80 // So we should clip to a reasonable value that allows a little headroom.
81 if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT && sinkFormat == AUDIO_FORMAT_PCM_FLOAT) {
82 mClipper = std::make_unique<ClipToRange>(sourceChannelCount);
83 lastOutput->connect(&mClipper->input);
84 lastOutput = &mClipper->output;
85 }
86
87 // Expand the number of channels if required.
88 if (sourceChannelCount == 1 && sinkChannelCount > 1) {
89 mChannelConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
90 lastOutput->connect(&mChannelConverter->input);
91 lastOutput = &mChannelConverter->output;
92 } else if (sourceChannelCount != sinkChannelCount) {
93 ALOGE("%s() Channel reduction not supported.", __func__);
94 return AAUDIO_ERROR_UNIMPLEMENTED;
95 }
96
Robert Wu8393bed2021-12-08 02:08:48 +000097 // Apply volume ramps to set the left/right audio balance and target volumes.
98 // The signals will be decoupled, volume ramps will be applied, before the signals are
99 // combined again.
100 mMultiToManyConverter = std::make_unique<MultiToManyConverter>(sinkChannelCount);
101 mManyToMultiConverter = std::make_unique<ManyToMultiConverter>(sinkChannelCount);
102 lastOutput->connect(&mMultiToManyConverter->input);
103 for (int i = 0; i < sinkChannelCount; i++) {
104 mVolumeRamps.emplace_back(std::make_unique<RampLinear>(1));
105 mPanningVolumes.emplace_back(1.0f);
106 lastOutput = mMultiToManyConverter->outputs[i].get();
107 lastOutput->connect(&(mVolumeRamps[i].get()->input));
108 lastOutput = &(mVolumeRamps[i].get()->output);
109 lastOutput->connect(mManyToMultiConverter->inputs[i].get());
110 }
111 lastOutput = &mManyToMultiConverter->output;
112 setAudioBalance(audioBalance);
113
Phil Burk0127c1b2018-03-29 13:48:06 -0700114 switch (sinkFormat) {
115 case AUDIO_FORMAT_PCM_FLOAT:
116 mSink = std::make_unique<SinkFloat>(sinkChannelCount);
117 break;
118 case AUDIO_FORMAT_PCM_16_BIT:
119 mSink = std::make_unique<SinkI16>(sinkChannelCount);
120 break;
121 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
122 mSink = std::make_unique<SinkI24>(sinkChannelCount);
123 break;
Phil Burk04e805b2018-03-27 09:13:53 -0700124 case AUDIO_FORMAT_PCM_32_BIT:
125 mSink = std::make_unique<SinkI32>(sinkChannelCount);
126 break;
127 default:
Phil Burk0127c1b2018-03-29 13:48:06 -0700128 ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
129 return AAUDIO_ERROR_UNIMPLEMENTED;
130 }
131 lastOutput->connect(&mSink->input);
132
133 return AAUDIO_OK;
134}
135
136void AAudioFlowGraph::process(const void *source, void *destination, int32_t numFrames) {
137 mSource->setData(source, numFrames);
138 mSink->read(destination, numFrames);
139}
140
141/**
142 * @param volume between 0.0 and 1.0
143 */
144void AAudioFlowGraph::setTargetVolume(float volume) {
Robert Wu8393bed2021-12-08 02:08:48 +0000145 for (int i = 0; i < mVolumeRamps.size(); i++) {
146 mVolumeRamps[i]->setTarget(volume * mPanningVolumes[i]);
147 }
148 mTargetVolume = volume;
Phil Burk0127c1b2018-03-29 13:48:06 -0700149}
150
Robert Wu8393bed2021-12-08 02:08:48 +0000151/**
152 * @param audioBalance between -1.0 and 1.0
153 */
154void AAudioFlowGraph::setAudioBalance(float audioBalance) {
155 if (mPanningVolumes.size() >= 2) {
156 float leftMultiplier = 0;
157 float rightMultiplier = 0;
158 mBalance.computeStereoBalance(audioBalance, &leftMultiplier, &rightMultiplier);
159 mPanningVolumes[0] = leftMultiplier;
160 mPanningVolumes[1] = rightMultiplier;
161 mVolumeRamps[0]->setTarget(mTargetVolume * leftMultiplier);
162 mVolumeRamps[1]->setTarget(mTargetVolume * rightMultiplier);
163 }
164}
165
166/**
167 * @param numFrames to slowly adjust for volume changes
168 */
Phil Burk0127c1b2018-03-29 13:48:06 -0700169void AAudioFlowGraph::setRampLengthInFrames(int32_t numFrames) {
Robert Wu8393bed2021-12-08 02:08:48 +0000170 for (auto& ramp : mVolumeRamps) {
171 ramp->setLengthInFrames(numFrames);
172 }
Phil Burk0127c1b2018-03-29 13:48:06 -0700173}