/* * Copyright (C) 2018 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. */ #define LOG_TAG "AAudioFlowGraph" //#define LOG_NDEBUG 0 #include #include "AAudioFlowGraph.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph; aaudio_result_t AAudioFlowGraph::configure(audio_format_t sourceFormat, int32_t sourceChannelCount, int32_t sourceSampleRate, audio_format_t sinkFormat, int32_t sinkChannelCount, int32_t sinkSampleRate, bool useMonoBlend, bool useVolumeRamps, float audioBalance, aaudio::resampler::MultiChannelResampler::Quality resamplerQuality) { FlowGraphPortFloatOutput *lastOutput = nullptr; ALOGD("%s() source format = 0x%08x, channels = %d, sample rate = %d, " "sink format = 0x%08x, channels = %d, sample rate = %d, " "useMonoBlend = %d, audioBalance = %f, useVolumeRamps %d", __func__, sourceFormat, sourceChannelCount, sourceSampleRate, sinkFormat, sinkChannelCount, sinkSampleRate, useMonoBlend, audioBalance, useVolumeRamps); switch (sourceFormat) { case AUDIO_FORMAT_PCM_FLOAT: mSource = std::make_unique(sourceChannelCount); break; case AUDIO_FORMAT_PCM_16_BIT: mSource = std::make_unique(sourceChannelCount); break; case AUDIO_FORMAT_PCM_24_BIT_PACKED: mSource = std::make_unique(sourceChannelCount); break; case AUDIO_FORMAT_PCM_32_BIT: mSource = std::make_unique(sourceChannelCount); break; case AUDIO_FORMAT_PCM_8_24_BIT: mSource = std::make_unique(sourceChannelCount); break; default: ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat); return AAUDIO_ERROR_UNIMPLEMENTED; } lastOutput = &mSource->output; if (useMonoBlend) { mMonoBlend = std::make_unique(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 limit to a reasonable value that allows a little headroom. if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT && sinkFormat == AUDIO_FORMAT_PCM_FLOAT) { mLimiter = std::make_unique(sourceChannelCount); lastOutput->connect(&mLimiter->input); lastOutput = &mLimiter->output; } if (sourceSampleRate != sinkSampleRate) { mResampler.reset(aaudio::resampler::MultiChannelResampler::make(sourceChannelCount, sourceSampleRate, sinkSampleRate, resamplerQuality)); mRateConverter = std::make_unique(sourceChannelCount, *mResampler); lastOutput->connect(&mRateConverter->input); lastOutput = &mRateConverter->output; } // Expand the number of channels if required. if (sourceChannelCount == 1 && sinkChannelCount > 1) { mChannelConverter = std::make_unique(sinkChannelCount); lastOutput->connect(&mChannelConverter->input); lastOutput = &mChannelConverter->output; } else if (sourceChannelCount != sinkChannelCount) { ALOGE("%s() Channel reduction not supported.", __func__); return AAUDIO_ERROR_UNIMPLEMENTED; } if (useVolumeRamps) { // 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(sinkChannelCount); mManyToMultiConverter = std::make_unique(sinkChannelCount); lastOutput->connect(&mMultiToManyConverter->input); for (int i = 0; i < sinkChannelCount; i++) { mVolumeRamps.emplace_back(std::make_unique(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(sinkChannelCount); break; case AUDIO_FORMAT_PCM_16_BIT: mSink = std::make_unique(sinkChannelCount); break; case AUDIO_FORMAT_PCM_24_BIT_PACKED: mSink = std::make_unique(sinkChannelCount); break; case AUDIO_FORMAT_PCM_32_BIT: mSink = std::make_unique(sinkChannelCount); break; case AUDIO_FORMAT_PCM_8_24_BIT: mSink = std::make_unique(sinkChannelCount); break; default: ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat); return AAUDIO_ERROR_UNIMPLEMENTED; } lastOutput->connect(&mSink->input); return AAUDIO_OK; } int32_t AAudioFlowGraph::pull(void *destination, int32_t targetFramesToRead) { return mSink->read(destination, targetFramesToRead); } int32_t AAudioFlowGraph::process(const void *source, int32_t numFramesToWrite, void *destination, int32_t targetFramesToRead) { mSource->setData(source, numFramesToWrite); return mSink->read(destination, targetFramesToRead); } /** * @param volume between 0.0 and 1.0 */ void AAudioFlowGraph::setTargetVolume(float 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) { for (auto& ramp : mVolumeRamps) { ramp->setLengthInFrames(numFrames); } }