Skip to content

Commit

Permalink
oboe: add ChannelCountConverter
Browse files Browse the repository at this point in the history
  • Loading branch information
philburk committed Jun 17, 2020
1 parent 388b8c3 commit cb01be5
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 24 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ set (oboe_sources
src/fifo/FifoController.cpp
src/fifo/FifoControllerBase.cpp
src/fifo/FifoControllerIndirect.cpp
src/flowgraph/FlowGraphNode.cpp
src/flowgraph/FlowGraphNode.cpp
src/flowgraph/ChannelCountConverter.cpp
src/flowgraph/ClipToRange.cpp
src/flowgraph/ManyToMultiConverter.cpp
src/flowgraph/MonoToMultiConverter.cpp
Expand Down
41 changes: 24 additions & 17 deletions src/common/DataConversionFlowGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/common/DataConversionFlowGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -70,6 +71,7 @@ class DataConversionFlowGraph : public FixedBlockProcessor {
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;
Expand Down
10 changes: 5 additions & 5 deletions src/common/QuirksManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
Expand All @@ -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__);
}
Expand Down
3 changes: 3 additions & 0 deletions src/common/QuirksManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ class QuirksManager {

private:

static constexpr int32_t kChannelCountMono = 1;
static constexpr int32_t kChannelCountStereo = 2;

std::unique_ptr<DeviceQuirks> mDeviceQuirks{};

};
Expand Down
52 changes: 52 additions & 0 deletions src/flowgraph/ChannelCountConverter.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

52 changes: 52 additions & 0 deletions src/flowgraph/ChannelCountConverter.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit cb01be5

Please sign in to comment.