aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhil Burk <philburk@mobileer.com>2020-06-16 16:37:37 -0700
committerPhil Burk <philburk@mobileer.com>2020-06-17 11:21:33 -0700
commitcb01be56e08c1e6ac24c3bf202dc5add75895051 (patch)
tree6beeb40bec70bdceb64881948d2e7213a189100a /src
parent388b8c3d8bf011b053f1c242c4ea20ef3cd0f830 (diff)
downloadoboe-cb01be56e08c1e6ac24c3bf202dc5add75895051.tar.gz
oboe: add ChannelCountConverter
Diffstat (limited to 'src')
-rw-r--r--src/common/DataConversionFlowGraph.cpp41
-rw-r--r--src/common/DataConversionFlowGraph.h4
-rw-r--r--src/common/QuirksManager.cpp10
-rw-r--r--src/common/QuirksManager.h3
-rw-r--r--src/flowgraph/ChannelCountConverter.cpp52
-rw-r--r--src/flowgraph/ChannelCountConverter.h52
6 files changed, 139 insertions, 23 deletions
diff --git a/src/common/DataConversionFlowGraph.cpp b/src/common/DataConversionFlowGraph.cpp
index e40a58aa..fd6695b3 100644
--- a/src/common/DataConversionFlowGraph.cpp
+++ b/src/common/DataConversionFlowGraph.cpp
@@ -140,21 +140,20 @@ Result DataConversionFlowGraph::configure(AudioStream *sourceStream, AudioStream
lastOutput = &mSource->output;
}
- if (sourceChannelCount != sinkChannelCount
- && sourceChannelCount != 1
- && sinkChannelCount != 1
- ) {
- LOGW("%s() Channel conversion %d to %d not supported.", __func__,
- sourceChannelCount, sinkChannelCount);
- return Result::ErrorUnimplemented;
- }
-
// If we are going to reduce the number of channels then do it before the
// sample rate converter.
- if (sourceChannelCount > 1 && sinkChannelCount == 1) {
- mMultiToMonoConverter = std::make_unique<MultiToMonoConverter>(sourceChannelCount);
- lastOutput->connect(&mMultiToMonoConverter->input);
- lastOutput = &mMultiToMonoConverter->output;
+ if (sourceChannelCount > sinkChannelCount) {
+ if (sinkChannelCount == 1) {
+ mMultiToMonoConverter = std::make_unique<MultiToMonoConverter>(sourceChannelCount);
+ lastOutput->connect(&mMultiToMonoConverter->input);
+ lastOutput = &mMultiToMonoConverter->output;
+ } else {
+ mChannelCountConverter = std::make_unique<ChannelCountConverter>(
+ sourceChannelCount,
+ sinkChannelCount);
+ lastOutput->connect(&mChannelCountConverter->input);
+ lastOutput = &mChannelCountConverter->output;
+ }
}
// Sample Rate conversion
@@ -173,10 +172,18 @@ Result DataConversionFlowGraph::configure(AudioStream *sourceStream, AudioStream
}
// Expand the number of channels if required.
- if (sourceChannelCount == 1 && sinkChannelCount > 1) {
- mMonoToMultiConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
- lastOutput->connect(&mMonoToMultiConverter->input);
- lastOutput = &mMonoToMultiConverter->output;
+ if (sourceChannelCount < sinkChannelCount) {
+ if (sourceChannelCount == 1) {
+ mMonoToMultiConverter = std::make_unique<MonoToMultiConverter>(sinkChannelCount);
+ lastOutput->connect(&mMonoToMultiConverter->input);
+ lastOutput = &mMonoToMultiConverter->output;
+ } else {
+ mChannelCountConverter = std::make_unique<ChannelCountConverter>(
+ sourceChannelCount,
+ sinkChannelCount);
+ lastOutput->connect(&mChannelCountConverter->input);
+ lastOutput = &mChannelCountConverter->output;
+ }
}
// Sink
diff --git a/src/common/DataConversionFlowGraph.h b/src/common/DataConversionFlowGraph.h
index 3bc3801e..5b8d3f66 100644
--- a/src/common/DataConversionFlowGraph.h
+++ b/src/common/DataConversionFlowGraph.h
@@ -21,10 +21,11 @@
#include <stdint.h>
#include <sys/types.h>
+#include <flowgraph/ChannelCountConverter.h>
#include <flowgraph/MonoToMultiConverter.h>
+#include <flowgraph/MultiToMonoConverter.h>
#include <flowgraph/SampleRateConverter.h>
#include <oboe/Definitions.h>
-#include <flowgraph/MultiToMonoConverter.h>
#include "AudioSourceCaller.h"
#include "FixedBlockWriter.h"
@@ -70,6 +71,7 @@ private:
std::unique_ptr<AudioSourceCaller> mSourceCaller;
std::unique_ptr<flowgraph::MonoToMultiConverter> mMonoToMultiConverter;
std::unique_ptr<flowgraph::MultiToMonoConverter> mMultiToMonoConverter;
+ std::unique_ptr<flowgraph::ChannelCountConverter> mChannelCountConverter;
std::unique_ptr<resampler::MultiChannelResampler> mResampler;
std::unique_ptr<flowgraph::SampleRateConverter> mRateConverter;
std::unique_ptr<flowgraph::FlowGraphSink> mSink;
diff --git a/src/common/QuirksManager.cpp b/src/common/QuirksManager.cpp
index 9c874da8..505cddb1 100644
--- a/src/common/QuirksManager.cpp
+++ b/src/common/QuirksManager.cpp
@@ -59,7 +59,7 @@ bool QuirksManager::DeviceQuirks::isAAudioMMapPossible(const AudioStreamBuilder
|| builder.getSampleRateConversionQuality() != SampleRateConversionQuality::None;
return builder.getPerformanceMode() == PerformanceMode::LowLatency
&& isSampleRateCompatible
- && builder.getChannelCount() <= 2;
+ && builder.getChannelCount() <= kChannelCountStereo;
}
class SamsungDeviceQuirks : public QuirksManager::DeviceQuirks {
@@ -147,18 +147,18 @@ bool QuirksManager::isConversionNeeded(
// Channel Count conversions
if (OboeGlobals::areWorkaroundsEnabled()
&& builder.isChannelConversionAllowed()
- && builder.getChannelCount() == 2 // stereo?
+ && builder.getChannelCount() == kChannelCountStereo
&& isInput
&& isLowLatency
&& (!builder.willUseAAudio() && (getSdkVersion() == __ANDROID_API_O__))
) {
// Workaround for heap size regression in O.
// b/66967812 AudioRecord does not allow FAST track for stereo capture in O
- childBuilder.setChannelCount(1);
+ childBuilder.setChannelCount(kChannelCountMono);
conversionNeeded = true;
LOGI("QuirksManager::%s() using mono internally for low latency on O", __func__);
} else if (OboeGlobals::areWorkaroundsEnabled()
- && builder.getChannelCount() == 1 // mono?
+ && builder.getChannelCount() == kChannelCountMono
&& isInput
&& mDeviceQuirks->isMonoMMapActuallyStereo()
&& builder.willUseAAudio()
@@ -168,7 +168,7 @@ bool QuirksManager::isConversionNeeded(
&& mDeviceQuirks->isAAudioMMapPossible(builder)
) {
// Workaround for mono actually running in stereo mode.
- childBuilder.setChannelCount(2); // Use stereo and extract first channel.
+ childBuilder.setChannelCount(kChannelCountStereo); // Use stereo and extract first channel.
conversionNeeded = true;
LOGI("QuirksManager::%s() using stereo internally to avoid broken mono", __func__);
}
diff --git a/src/common/QuirksManager.h b/src/common/QuirksManager.h
index fb997355..b4e38ded 100644
--- a/src/common/QuirksManager.h
+++ b/src/common/QuirksManager.h
@@ -110,6 +110,9 @@ public:
private:
+ static constexpr int32_t kChannelCountMono = 1;
+ static constexpr int32_t kChannelCountStereo = 2;
+
std::unique_ptr<DeviceQuirks> mDeviceQuirks{};
};
diff --git a/src/flowgraph/ChannelCountConverter.cpp b/src/flowgraph/ChannelCountConverter.cpp
new file mode 100644
index 00000000..03de262c
--- /dev/null
+++ b/src/flowgraph/ChannelCountConverter.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "ChannelCountConverter.h"
+
+using namespace flowgraph;
+
+ChannelCountConverter::ChannelCountConverter(
+ int32_t inputChannelCount,
+ int32_t outputChannelCount)
+ : input(*this, inputChannelCount)
+ , output(*this, outputChannelCount) {
+}
+
+ChannelCountConverter::~ChannelCountConverter() { }
+
+int32_t ChannelCountConverter::onProcess(int32_t numFrames) {
+ const float *inputBuffer = input.getBuffer();
+ float *outputBuffer = output.getBuffer();
+ int32_t inputChannelCount = input.getSamplesPerFrame();
+ int32_t outputChannelCount = output.getSamplesPerFrame();
+ for (int i = 0; i < numFrames; i++) {
+ int inputChannel = 0;
+ for (int outputChannel = 0; outputChannel < outputChannelCount; outputChannel++) {
+ // Copy input channels to output channels.
+ // Wrap if we run out of inputs.
+ // Discard if we run out of outputs.
+ outputBuffer[outputChannel] = inputBuffer[inputChannel];
+ inputChannel = (inputChannel == inputChannelCount)
+ ? 0 : inputChannel + 1;
+ }
+ inputBuffer += inputChannelCount;
+ outputBuffer += outputChannelCount;
+ }
+ return numFrames;
+}
+
diff --git a/src/flowgraph/ChannelCountConverter.h b/src/flowgraph/ChannelCountConverter.h
new file mode 100644
index 00000000..e4b6f4e6
--- /dev/null
+++ b/src/flowgraph/ChannelCountConverter.h
@@ -0,0 +1,52 @@
+/*
+ * 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_CHANNEL_COUNT_CONVERTER_H
+#define FLOWGRAPH_CHANNEL_COUNT_CONVERTER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "FlowGraphNode.h"
+
+namespace flowgraph {
+
+/**
+ * Change the number of number of channels without mixing.
+ * When increasing the channel count, duplicate input channels.
+ * When decreasing the channel count, drop input channels.
+ */
+ class ChannelCountConverter : public FlowGraphNode {
+ public:
+ explicit ChannelCountConverter(
+ int32_t inputChannelCount,
+ int32_t outputChannelCount);
+
+ virtual ~ChannelCountConverter();
+
+ int32_t onProcess(int32_t numFrames) override;
+
+ const char *getName() override {
+ return "ChannelCountConverter";
+ }
+
+ FlowGraphPortFloatInput input;
+ FlowGraphPortFloatOutput output;
+ };
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_CHANNEL_COUNT_CONVERTER_H