Add MMAP Audio Balance
Similar to adding Mono audio, this cl adds the audio balance settings
to MMAP Audio.
Bug:209521805
Test: Settings -> Accessibility -> Audio Adjustment -> Audio Balance
Use OboeTester and play outputs with various settings on the slider
Change-Id: I3269f6fe39b5f720da69739c49eb787e57f93b0a
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 38bcb7c..f50b53a 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -214,6 +214,7 @@
"flowgraph/MonoBlend.cpp",
"flowgraph/MonoToMultiConverter.cpp",
"flowgraph/MultiToMonoConverter.cpp",
+ "flowgraph/MultiToManyConverter.cpp",
"flowgraph/RampLinear.cpp",
"flowgraph/SampleRateConverter.cpp",
"flowgraph/SinkFloat.cpp",
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index d3e2912..5b46ae0 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -21,8 +21,10 @@
#include "AAudioFlowGraph.h"
#include <flowgraph/ClipToRange.h>
+#include <flowgraph/ManyToMultiConverter.h>
#include <flowgraph/MonoBlend.h>
#include <flowgraph/MonoToMultiConverter.h>
+#include <flowgraph/MultiToManyConverter.h>
#include <flowgraph/RampLinear.h>
#include <flowgraph/SinkFloat.h>
#include <flowgraph/SinkI16.h>
@@ -39,12 +41,15 @@
int32_t sourceChannelCount,
audio_format_t sinkFormat,
int32_t sinkChannelCount,
- bool useMonoBlend) {
+ bool useMonoBlend,
+ float audioBalance) {
FlowGraphPortFloatOutput *lastOutput = nullptr;
// TODO change back to ALOGD
- ALOGI("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
- __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount);
+ ALOGI("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d, "
+ "useMonoBlend = %d, audioBalance = %f",
+ __func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount,
+ useMonoBlend, audioBalance);
switch (sourceFormat) {
case AUDIO_FORMAT_PCM_FLOAT:
@@ -65,10 +70,11 @@
}
lastOutput = &mSource->output;
- // Apply volume as a ramp to avoid pops.
- mVolumeRamp = std::make_unique<RampLinear>(sourceChannelCount);
- lastOutput->connect(&mVolumeRamp->input);
- lastOutput = &mVolumeRamp->output;
+ if (useMonoBlend) {
+ mMonoBlend = std::make_unique<MonoBlend>(sourceChannelCount);
+ lastOutput->connect(&mMonoBlend->input);
+ lastOutput = &mMonoBlend->output;
+ }
// For a pure float graph, there is chance that the data range may be very large.
// So we should clip to a reasonable value that allows a little headroom.
@@ -78,12 +84,6 @@
lastOutput = &mClipper->output;
}
- if (useMonoBlend) {
- mMonoBlend = std::make_unique<MonoBlend>(sourceChannelCount);
- lastOutput->connect(&mMonoBlend->input);
- lastOutput = &mMonoBlend->output;
- }
-
// Expand the number of channels if required.
if (sourceChannelCount == 1 && sinkChannelCount > 1) {
mChannelConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
@@ -94,6 +94,23 @@
return AAUDIO_ERROR_UNIMPLEMENTED;
}
+ // Apply volume ramps to set the left/right audio balance and target volumes.
+ // The signals will be decoupled, volume ramps will be applied, before the signals are
+ // combined again.
+ mMultiToManyConverter = std::make_unique<MultiToManyConverter>(sinkChannelCount);
+ mManyToMultiConverter = std::make_unique<ManyToMultiConverter>(sinkChannelCount);
+ lastOutput->connect(&mMultiToManyConverter->input);
+ for (int i = 0; i < sinkChannelCount; i++) {
+ mVolumeRamps.emplace_back(std::make_unique<RampLinear>(1));
+ mPanningVolumes.emplace_back(1.0f);
+ lastOutput = mMultiToManyConverter->outputs[i].get();
+ lastOutput->connect(&(mVolumeRamps[i].get()->input));
+ lastOutput = &(mVolumeRamps[i].get()->output);
+ lastOutput->connect(mManyToMultiConverter->inputs[i].get());
+ }
+ lastOutput = &mManyToMultiConverter->output;
+ setAudioBalance(audioBalance);
+
switch (sinkFormat) {
case AUDIO_FORMAT_PCM_FLOAT:
mSink = std::make_unique<SinkFloat>(sinkChannelCount);
@@ -125,9 +142,32 @@
* @param volume between 0.0 and 1.0
*/
void AAudioFlowGraph::setTargetVolume(float volume) {
- mVolumeRamp->setTarget(volume);
+ for (int i = 0; i < mVolumeRamps.size(); i++) {
+ mVolumeRamps[i]->setTarget(volume * mPanningVolumes[i]);
+ }
+ mTargetVolume = volume;
}
+/**
+ * @param audioBalance between -1.0 and 1.0
+ */
+void AAudioFlowGraph::setAudioBalance(float audioBalance) {
+ if (mPanningVolumes.size() >= 2) {
+ float leftMultiplier = 0;
+ float rightMultiplier = 0;
+ mBalance.computeStereoBalance(audioBalance, &leftMultiplier, &rightMultiplier);
+ mPanningVolumes[0] = leftMultiplier;
+ mPanningVolumes[1] = rightMultiplier;
+ mVolumeRamps[0]->setTarget(mTargetVolume * leftMultiplier);
+ mVolumeRamps[1]->setTarget(mTargetVolume * rightMultiplier);
+ }
+}
+
+/**
+ * @param numFrames to slowly adjust for volume changes
+ */
void AAudioFlowGraph::setRampLengthInFrames(int32_t numFrames) {
- mVolumeRamp->setLengthInFrames(numFrames);
+ for (auto& ramp : mVolumeRamps) {
+ ramp->setLengthInFrames(numFrames);
+ }
}
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.h b/media/libaaudio/src/client/AAudioFlowGraph.h
index e719d91..2056b70 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.h
+++ b/media/libaaudio/src/client/AAudioFlowGraph.h
@@ -23,9 +23,12 @@
#include <system/audio.h>
#include <aaudio/AAudio.h>
+#include <audio_utils/Balance.h>
#include <flowgraph/ClipToRange.h>
+#include <flowgraph/ManyToMultiConverter.h>
#include <flowgraph/MonoBlend.h>
#include <flowgraph/MonoToMultiConverter.h>
+#include <flowgraph/MultiToManyConverter.h>
#include <flowgraph/RampLinear.h>
class AAudioFlowGraph {
@@ -37,13 +40,17 @@
* @param sourceChannelCount
* @param sinkFormat
* @param sinkChannelCount
+ * @param useMonoBlend
+ * @param audioBalance
+ * @param channelMask
* @return
*/
aaudio_result_t configure(audio_format_t sourceFormat,
int32_t sourceChannelCount,
audio_format_t sinkFormat,
int32_t sinkChannelCount,
- bool useMonoBlend);
+ bool useMonoBlend,
+ float audioBalance);
void process(const void *source, void *destination, int32_t numFrames);
@@ -52,14 +59,27 @@
*/
void setTargetVolume(float volume);
+ /**
+ * @param audioBalance between -1.0 and 1.0
+ */
+ void setAudioBalance(float audioBalance);
+
+ /**
+ * @param numFrames to slowly adjust for volume changes
+ */
void setRampLengthInFrames(int32_t numFrames);
private:
std::unique_ptr<flowgraph::FlowGraphSourceBuffered> mSource;
std::unique_ptr<flowgraph::MonoBlend> mMonoBlend;
- std::unique_ptr<flowgraph::RampLinear> mVolumeRamp;
std::unique_ptr<flowgraph::ClipToRange> mClipper;
std::unique_ptr<flowgraph::MonoToMultiConverter> mChannelConverter;
+ std::unique_ptr<flowgraph::ManyToMultiConverter> mManyToMultiConverter;
+ std::unique_ptr<flowgraph::MultiToManyConverter> mMultiToManyConverter;
+ std::vector<std::unique_ptr<flowgraph::RampLinear>> mVolumeRamps;
+ std::vector<float> mPanningVolumes;
+ float mTargetVolume = 1.0f;
+ android::audio_utils::Balance mBalance;
std::unique_ptr<flowgraph::FlowGraphSink> mSink;
};
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 1b8e224..afdc2ac 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -272,12 +272,15 @@
}
// Exclusive output streams should combine channels when mono audio adjustment
- // is enabled.
+ // is enabled. They should also adjust for audio balance.
if ((getDirection() == AAUDIO_DIRECTION_OUTPUT) &&
(getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE)) {
bool isMasterMono = false;
android::AudioSystem::getMasterMono(&isMasterMono);
setRequireMonoBlend(isMasterMono);
+ float audioBalance = 0;
+ android::AudioSystem::getMasterBalance(&audioBalance);
+ setAudioBalance(audioBalance);
}
// For debugging and analyzing the distribution of MMAP timestamps.
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index c17c7a0..8292573 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -53,7 +53,8 @@
getSamplesPerFrame(),
getDeviceFormat(),
getDeviceChannelCount(),
- getRequireMonoBlend());
+ getRequireMonoBlend(),
+ getAudioBalance());
if (result != AAUDIO_OK) {
safeReleaseClose();
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index a3af753..5fb4528 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -281,6 +281,10 @@
return mRequireMonoBlend;
}
+ float getAudioBalance() const {
+ return mAudioBalance;
+ }
+
/**
* This is only valid after setChannelMask() and setFormat()
* have been called.
@@ -642,6 +646,13 @@
mRequireMonoBlend = requireMonoBlend;
}
+ /**
+ * This should not be called after the open() call.
+ */
+ void setAudioBalance(float audioBalance) {
+ mAudioBalance = audioBalance;
+ }
+
std::string mMetricsId; // set once during open()
std::mutex mStreamLock;
@@ -684,6 +695,7 @@
aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
bool mIsPrivacySensitive = false;
bool mRequireMonoBlend = false;
+ float mAudioBalance = 0;
int32_t mSessionId = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp b/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp
new file mode 100644
index 0000000..f074364
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/MultiToManyConverter.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include "FlowGraphNode.h"
+#include "MultiToManyConverter.h"
+
+using namespace flowgraph;
+
+MultiToManyConverter::MultiToManyConverter(int32_t channelCount)
+ : outputs(channelCount)
+ , input(*this, channelCount) {
+ for (int i = 0; i < channelCount; i++) {
+ outputs[i] = std::make_unique<FlowGraphPortFloatOutput>(*this, 1);
+ }
+}
+
+MultiToManyConverter::~MultiToManyConverter() = default;
+
+int32_t MultiToManyConverter::onProcess(int32_t numFrames) {
+ int32_t channelCount = input.getSamplesPerFrame();
+
+ for (int ch = 0; ch < channelCount; ch++) {
+ const float *inputBuffer = input.getBuffer() + ch;
+ float *outputBuffer = outputs[ch]->getBuffer();
+
+ for (int i = 0; i < numFrames; i++) {
+ *outputBuffer++ = *inputBuffer;
+ inputBuffer += channelCount;
+ }
+ }
+
+ return numFrames;
+}
+
diff --git a/media/libaaudio/src/flowgraph/MultiToManyConverter.h b/media/libaaudio/src/flowgraph/MultiToManyConverter.h
new file mode 100644
index 0000000..de31475
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/MultiToManyConverter.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
+#define FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "FlowGraphNode.h"
+
+namespace flowgraph {
+
+/**
+ * Convert a multi-channel interleaved stream to multiple mono-channel
+ * outputs
+ */
+ class MultiToManyConverter : public FlowGraphNode {
+ public:
+ explicit MultiToManyConverter(int32_t channelCount);
+
+ virtual ~MultiToManyConverter();
+
+ int32_t onProcess(int32_t numFrames) override;
+
+ const char *getName() override {
+ return "MultiToManyConverter";
+ }
+
+ std::vector<std::unique_ptr<flowgraph::FlowGraphPortFloatOutput>> outputs;
+ flowgraph::FlowGraphPortFloatInput input;
+ };
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_MULTI_TO_MANY_CONVERTER_H