• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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