/* * Copyright (C) 2022 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 #include #define LOG_TAG "BundleContext" #include #include #include #include #include "BundleContext.h" #include "BundleTypes.h" #include "math.h" namespace aidl::android::hardware::audio::effect { using ::aidl::android::media::audio::common::AudioChannelLayout; using ::aidl::android::media::audio::common::AudioDeviceDescription; using ::aidl::android::media::audio::common::AudioDeviceType; BundleContext::BundleContext(int statusDepth, const Parameter::Common& common, const lvm::BundleEffectType& type) : EffectContext(statusDepth, common), mType(type) { int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount( common.input.base.channelMask); mSamplesPerSecond = common.input.base.sampleRate * inputChannelCount; } BundleContext::~BundleContext() { deInit(); } RetCode BundleContext::init() { // init with pre-defined preset NORMAL for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) { mBandGainmB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100; } // Initialise control params LVM_ControlParams_t controlParams; RetCode retStatus = initControlParameter(controlParams); RETURN_VALUE_IF(retStatus != RetCode::SUCCESS, RetCode::ERROR_ILLEGAL_PARAMETER, " UnsupportedParams"); // allocate lvm instance LVM_ReturnStatus_en status; LVM_InstParams_t params = {.BufferMode = LVM_UNMANAGED_BUFFERS, .MaxBlockSize = lvm::MAX_CALL_SIZE, .EQNB_NumBands = lvm::MAX_NUM_BANDS, .PSA_Included = LVM_PSA_ON}; status = LVM_GetInstanceHandle(&mInstance, ¶ms); GOTO_IF_LVM_ERROR(status, deinit, "LVM_GetInstanceHandleFailed"); // set control status = LVM_SetControlParameters(mInstance, &controlParams); GOTO_IF_LVM_ERROR(status, deinit, "LVM_SetControlParametersFailed"); /* Set the headroom parameters */ LVM_HeadroomParams_t headroomParams; initHeadroomParameter(headroomParams); status = LVM_SetHeadroomParams(mInstance, &headroomParams); GOTO_IF_LVM_ERROR(status, deinit, "LVM_SetHeadroomParamsFailed"); return RetCode::SUCCESS; deinit: deInit(); return RetCode::ERROR_EFFECT_LIB_ERROR; } void BundleContext::deInit() { if (mInstance) { LVM_DelInstanceHandle(&mInstance); mInstance = nullptr; } } RetCode BundleContext::enable() { if (mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER; // Bass boost or Virtualizer can be temporarily disabled if playing over device speaker due to // their nature. bool tempDisabled = false; switch (mType) { case lvm::BundleEffectType::EQUALIZER: if (mSamplesToExitCountEq <= 0) mNumberEffectsEnabled++; mSamplesToExitCountEq = (mSamplesPerSecond * 0.1); mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::EQUALIZER)); break; case lvm::BundleEffectType::BASS_BOOST: if (mSamplesToExitCountBb <= 0) mNumberEffectsEnabled++; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::BASS_BOOST)); mSamplesToExitCountBb = (mSamplesPerSecond * 0.1); tempDisabled = mBassTempDisabled; break; case lvm::BundleEffectType::VIRTUALIZER: if (mSamplesToExitCountVirt <= 0) mNumberEffectsEnabled++; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VIRTUALIZER)); mSamplesToExitCountVirt = (mSamplesPerSecond * 0.1); tempDisabled = mVirtualizerTempDisabled; break; case lvm::BundleEffectType::VOLUME: if ((mEffectInDrain & (1 << int(lvm::BundleEffectType::VOLUME))) == 0) mNumberEffectsEnabled++; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME)); break; } mEnabled = true; return (tempDisabled ? RetCode::SUCCESS : enableOperatingMode()); } RetCode BundleContext::enableOperatingMode() { LVM_ControlParams_t params; RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, "failGetControlParams"); switch (mType) { case lvm::BundleEffectType::EQUALIZER: params.EQNB_OperatingMode = LVM_EQNB_ON; break; case lvm::BundleEffectType::BASS_BOOST: params.BE_OperatingMode = LVM_BE_ON; break; case lvm::BundleEffectType::VIRTUALIZER: params.VirtualizerOperatingMode = LVM_MODE_ON; break; case lvm::BundleEffectType::VOLUME: break; } RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, "failSetControlParams"); return limitLevel(); } RetCode BundleContext::disable() { if (!mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER; switch (mType) { case lvm::BundleEffectType::EQUALIZER: mEffectInDrain |= 1 << int(lvm::BundleEffectType::EQUALIZER); break; case lvm::BundleEffectType::BASS_BOOST: mEffectInDrain |= 1 << int(lvm::BundleEffectType::BASS_BOOST); break; case lvm::BundleEffectType::VIRTUALIZER: mEffectInDrain |= 1 << int(lvm::BundleEffectType::VIRTUALIZER); break; case lvm::BundleEffectType::VOLUME: mEffectInDrain |= 1 << int(lvm::BundleEffectType::VOLUME); break; } mEnabled = false; return disableOperatingMode(); } RetCode BundleContext::disableOperatingMode() { LVM_ControlParams_t params; RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, "failGetControlParams"); switch (mType) { case lvm::BundleEffectType::EQUALIZER: params.EQNB_OperatingMode = LVM_EQNB_OFF; break; case lvm::BundleEffectType::BASS_BOOST: params.BE_OperatingMode = LVM_BE_OFF; break; case lvm::BundleEffectType::VIRTUALIZER: params.VirtualizerOperatingMode = LVM_MODE_OFF; break; case lvm::BundleEffectType::VOLUME: break; } RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, "failSetControlParams"); return limitLevel(); } RetCode BundleContext::limitLevel() { int gainCorrection = 0; // Count the energy contribution per band for EQ and BassBoost only if they are active. float energyContribution = 0; float energyCross = 0; float energyBassBoost = 0; float crossCorrection = 0; LVM_ControlParams_t params; RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed"); bool eqEnabled = params.EQNB_OperatingMode == LVM_EQNB_ON; bool bbEnabled = params.BE_OperatingMode == LVM_BE_ON; bool viEnabled = params.VirtualizerOperatingMode == LVM_MODE_ON; if (eqEnabled) { for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) { float bandFactor = mBandGainmB[i] / 1500.0; float bandCoefficient = lvm::kBandEnergyCoefficient[i]; float bandEnergy = bandFactor * bandCoefficient * bandCoefficient; if (bandEnergy > 0) energyContribution += bandEnergy; } // cross EQ coefficients float bandFactorSum = 0; for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) { float bandFactor1 = mBandGainmB[i] / 1500.0; float bandFactor2 = mBandGainmB[i + 1] / 1500.0; if (bandFactor1 > 0 && bandFactor2 > 0) { float crossEnergy = bandFactor1 * bandFactor2 * lvm::kBandEnergyCrossCoefficient[i]; bandFactorSum += bandFactor1 * bandFactor2; if (crossEnergy > 0) energyCross += crossEnergy; } } bandFactorSum -= 1.0; if (bandFactorSum > 0) crossCorrection = bandFactorSum * 0.7; } // BassBoost contribution if (bbEnabled) { float boostFactor = mBassStrengthSaved / 1000.0; float boostCoefficient = lvm::kBassBoostEnergyCoefficient; energyContribution += boostFactor * boostCoefficient * boostCoefficient; if (eqEnabled) { for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) { float bandFactor = mBandGainmB[i] / 1500.0; float bandCrossCoefficient = lvm::kBassBoostEnergyCrossCoefficient[i]; float bandEnergy = boostFactor * bandFactor * bandCrossCoefficient; if (bandEnergy > 0) energyBassBoost += bandEnergy; } } } // Virtualizer contribution if (viEnabled) { energyContribution += lvm::kVirtualizerContribution * lvm::kVirtualizerContribution; } double totalEnergyEstimation = sqrt(energyContribution + energyCross + energyBassBoost) - crossCorrection; // roundoff int maxLevelRound = (int)(totalEnergyEstimation + 0.99); if (maxLevelRound + mVolumedB > 0) { gainCorrection = maxLevelRound + mVolumedB; } params.VC_EffectLevel = mVolumedB - gainCorrection; if (params.VC_EffectLevel < -96) { params.VC_EffectLevel = -96; } /* Activate the initial settings */ RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed"); if (mFirstVolume) { RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetVolumeNoSmoothing(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " setVolumeNoSmoothingFailed"); mFirstVolume = false; } return RetCode::SUCCESS; } bool BundleContext::isDeviceSupportedBassBoost( const std::vector& devices) { for (const auto& device : devices) { if (device != AudioDeviceDescription{AudioDeviceType::OUT_SPEAKER, ""} && device != AudioDeviceDescription{AudioDeviceType::OUT_CARKIT, AudioDeviceDescription::CONNECTION_BT_SCO} && device != AudioDeviceDescription{AudioDeviceType::OUT_SPEAKER, AudioDeviceDescription::CONNECTION_BT_A2DP} && device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX, AudioDeviceDescription::CONNECTION_VIRTUAL}) { return false; } } return true; } bool BundleContext::isDeviceSupportedVirtualizer( const std::vector& devices) { for (const auto& device : devices) { if (device != AudioDeviceDescription{AudioDeviceType::OUT_HEADSET, AudioDeviceDescription::CONNECTION_ANALOG} && device != AudioDeviceDescription{AudioDeviceType::OUT_HEADPHONE, AudioDeviceDescription::CONNECTION_ANALOG} && device != AudioDeviceDescription{AudioDeviceType::OUT_HEADPHONE, AudioDeviceDescription::CONNECTION_BT_A2DP} && device != AudioDeviceDescription{AudioDeviceType::OUT_HEADSET, AudioDeviceDescription::CONNECTION_USB} && device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX, AudioDeviceDescription::CONNECTION_VIRTUAL}) { return false; } } return true; } bool BundleContext::isConfigSupportedVirtualizer(size_t channelCount, const AudioDeviceDescription& device) { return (channelCount >= 1 && channelCount <= FCC_2) && isDeviceSupportedVirtualizer({device}); } RetCode BundleContext::setOutputDevice( const std::vector& devices) { mOutputDevice = devices; switch (mType) { case lvm::BundleEffectType::BASS_BOOST: if (!isDeviceSupportedBassBoost(devices)) { // If a device doesn't support bass boost, the effect must be temporarily disabled. // The effect must still report its original state as this can only be changed by // the start/stop commands. if (mEnabled) { disableOperatingMode(); } mBassTempDisabled = true; } else { // If a device supports bass boost and the effect has been temporarily disabled // previously then re-enable it if (!mEnabled) { enableOperatingMode(); } mBassTempDisabled = false; } break; case lvm::BundleEffectType::VIRTUALIZER: if (!isDeviceSupportedVirtualizer(devices)) { if (mEnabled) { disableOperatingMode(); } mVirtualizerTempDisabled = true; } else { if (!mEnabled) { enableOperatingMode(); } mVirtualizerTempDisabled = false; } break; default: break; } return RetCode::SUCCESS; } LVM_INT16 BundleContext::LVC_ToDB_s32Tos16(LVM_INT32 Lin_fix) const { LVM_INT16 db_fix; LVM_INT16 Shift; LVM_INT16 SmallRemainder; LVM_UINT32 Remainder = (LVM_UINT32)Lin_fix; /* Count leading bits, 1 cycle in assembly*/ for (Shift = 0; Shift < 32; Shift++) { if ((Remainder & 0x80000000U) != 0) { break; } Remainder = Remainder << 1; } /* * Based on the approximation equation (for Q11.4 format): * * dB = -96 * Shift + 16 * (8 * Remainder - 2 * Remainder^2) */ db_fix = (LVM_INT16)(-96 * Shift); /* Six dB steps in Q11.4 format*/ SmallRemainder = (LVM_INT16)((Remainder & 0x7fffffff) >> 24); db_fix = (LVM_INT16)(db_fix + SmallRemainder); SmallRemainder = (LVM_INT16)(SmallRemainder * SmallRemainder); db_fix = (LVM_INT16)(db_fix - (LVM_INT16)((LVM_UINT16)SmallRemainder >> 9)); /* Correct for small offset */ db_fix = (LVM_INT16)(db_fix - 5); return db_fix; } /* static */ float BundleContext::VolToDb(float vol) { float dB = audio_utils_power_from_amplitude(vol); return std::max(dB, -96.f); } RetCode BundleContext::setVolumeStereo(const Parameter::VolumeStereo& volume) { LVM_ControlParams_t params; // Convert volume to dB float leftdB = VolToDb(volume.left); float rightdB = VolToDb(volume.right); float maxdB = std::max(leftdB, rightdB); float pandB = rightdB - leftdB; setVolumeLevel(maxdB); RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, ""); params.VC_Balance = pandB; RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, ""); mVolumeStereo = volume; return RetCode::SUCCESS; } RetCode BundleContext::setEqualizerPreset(const std::size_t presetIdx) { if (presetIdx < 0 || presetIdx >= lvm::MAX_NUM_PRESETS) { return RetCode::ERROR_ILLEGAL_PARAMETER; } std::vector bandLevels; bandLevels.reserve(lvm::MAX_NUM_BANDS); for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) { bandLevels.emplace_back(Equalizer::BandLevel{static_cast(i), lvm::kSoftPresets[presetIdx][i] * 100}); } RetCode ret = updateControlParameter(bandLevels); if (RetCode::SUCCESS == ret) { mCurPresetIdx = presetIdx; } else { LOG(ERROR) << __func__ << " failed to setPreset " << presetIdx; } return ret; } RetCode BundleContext::setEqualizerBandLevels(const std::vector& bandLevels) { RETURN_VALUE_IF(bandLevels.size() > lvm::MAX_NUM_BANDS || bandLevels.empty(), RetCode::ERROR_ILLEGAL_PARAMETER, "sizeExceedMax"); RetCode ret = updateControlParameter(bandLevels); if (RetCode::SUCCESS == ret) { mCurPresetIdx = lvm::PRESET_CUSTOM; } else { LOG(ERROR) << __func__ << " failed with " << ::android::internal::ToString(bandLevels); } return ret; } std::vector BundleContext::getEqualizerBandLevels() const { std::vector bandLevels; bandLevels.reserve(lvm::MAX_NUM_BANDS); for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) { bandLevels.emplace_back(Equalizer::BandLevel{static_cast(i), mBandGainmB[i]}); } return bandLevels; } std::vector BundleContext::getEqualizerCenterFreqs() { std::vector freqs; LVM_ControlParams_t params; /* Get the current settings */ RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), freqs, " getControlParamFailed"); for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) { freqs.push_back((int32_t)params.pEQNB_BandDefinition[i].Frequency * 1000); } return freqs; } bool BundleContext::isBandLevelIndexInRange( const std::vector& bandLevels) const { const auto [min, max] = std::minmax_element(bandLevels.begin(), bandLevels.end(), [](const auto& a, const auto& b) { return a.index < b.index; }); return min->index >= 0 && static_cast(max->index) < lvm::MAX_NUM_BANDS; } RetCode BundleContext::updateControlParameter(const std::vector& bandLevels) { RETURN_VALUE_IF(!isBandLevelIndexInRange(bandLevels), RetCode::ERROR_ILLEGAL_PARAMETER, "indexOutOfRange"); std::array tempLevel(mBandGainmB); for (const auto& it : bandLevels) { tempLevel[it.index] = it.levelMb; } LVM_ControlParams_t params; RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed"); for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) { params.pEQNB_BandDefinition[i].Frequency = lvm::kPresetsFrequencies[i]; params.pEQNB_BandDefinition[i].QFactor = lvm::kPresetsQFactors[i]; params.pEQNB_BandDefinition[i].Gain = tempLevel[i] > 0 ? (tempLevel[i] + 50) / 100 : (tempLevel[i] - 50) / 100; } RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed"); mBandGainmB = tempLevel; return RetCode::SUCCESS; } RetCode BundleContext::setBassBoostStrength(int strength) { // Update Control Parameter LVM_ControlParams_t params; RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed"); params.BE_EffectLevel = (LVM_INT16)((15 * strength) / 1000); params.BE_CentreFreq = LVM_BE_CENTRE_90Hz; RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed"); mBassStrengthSaved = strength; return limitLevel(); } RetCode BundleContext::setVolumeLevel(float level) { if (mMuteEnabled) { mLevelSaveddB = level; } else { mVolumedB = level; } return limitLevel(); } float BundleContext::getVolumeLevel() const { return (mMuteEnabled ? mLevelSaveddB : mVolumedB); } RetCode BundleContext::setVolumeMute(bool mute) { mMuteEnabled = mute; if (mMuteEnabled) { mLevelSaveddB = mVolumedB; mVolumedB = -96; } else { mVolumedB = mLevelSaveddB; } return limitLevel(); } RetCode BundleContext::setVirtualizerStrength(int strength) { // Update Control Parameter LVM_ControlParams_t params; RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed"); params.CS_EffectLevel = ((strength * 32767) / 1000); RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms), RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed"); mVirtStrengthSaved = strength; return limitLevel(); } RetCode BundleContext::setForcedDevice( const ::aidl::android::media::audio::common::AudioDeviceDescription& device) { RetCode ret = RetCode::SUCCESS; bool enableVirtualizer = mType == lvm::BundleEffectType::VIRTUALIZER && mEnabled; if (isDeviceSupportedVirtualizer({device})) { mVirtualizerForcedDevice = device; } else { // disabling forced virtualization mode AudioDeviceDescription noneDevice; if (device != noneDevice) { // device is not supported, make it behave as a reset of forced mode but return an error ret = RetCode::ERROR_ILLEGAL_PARAMETER; } // verify whether the virtualization should be enabled or disabled if (!isDeviceSupportedVirtualizer(mOutputDevice)) { enableVirtualizer = false; } mVirtualizerForcedDevice = noneDevice; } if (enableVirtualizer) { if (mVirtualizerTempDisabled) { LOG(VERBOSE) << __func__ << " re-enable virtualizer"; enableOperatingMode(); mVirtualizerTempDisabled = false; } } else { if (!mVirtualizerTempDisabled) { LOG(VERBOSE) << __func__ << " disable virtualizer"; disableOperatingMode(); mVirtualizerTempDisabled = true; } } return ret; } RetCode BundleContext::initControlParameter(LVM_ControlParams_t& params) const { int outputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount( mCommon.output.base.channelMask); auto outputChannelMaskConv = aidl2legacy_AudioChannelLayout_audio_channel_mask_t( mCommon.output.base.channelMask, /*isInput*/ false); RETURN_VALUE_IF(!outputChannelMaskConv.ok(), RetCode::ERROR_ILLEGAL_PARAMETER, " outputChannelMaskNotValid"); params.NrChannels = outputChannelCount; params.ChMask = outputChannelMaskConv.value(); params.SampleRate = lvmFsForSampleRate(mCommon.input.base.sampleRate); int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount( mCommon.input.base.channelMask); if (inputChannelCount == 1) { params.SourceFormat = LVM_MONO; } else if (inputChannelCount == 2) { params.SourceFormat = LVM_STEREO; } else if (inputChannelCount > 2 && inputChannelCount <= LVM_MAX_CHANNELS) { params.SourceFormat = LVM_MULTICHANNEL; } /* General parameters */ params.OperatingMode = LVM_MODE_ON; params.SpeakerType = LVM_HEADPHONES; /* Concert Sound parameters */ params.VirtualizerOperatingMode = LVM_MODE_OFF; params.VirtualizerType = LVM_CONCERTSOUND; params.VirtualizerReverbLevel = 100; params.CS_EffectLevel = LVM_CS_EFFECT_NONE; params.EQNB_OperatingMode = LVM_EQNB_OFF; params.EQNB_NBands = lvm::MAX_NUM_BANDS; params.pEQNB_BandDefinition = getDefaultEqualizerBandDefs(); /* Volume Control parameters */ params.VC_EffectLevel = 0; params.VC_Balance = 0; /* Treble Enhancement parameters */ params.TE_OperatingMode = LVM_TE_OFF; params.TE_EffectLevel = 0; /* PSA Control parameters */ params.PSA_Enable = LVM_PSA_OFF; params.PSA_PeakDecayRate = (LVM_PSA_DecaySpeed_en)0; /* Bass Enhancement parameters */ params.BE_OperatingMode = LVM_BE_OFF; params.BE_EffectLevel = 0; params.BE_CentreFreq = LVM_BE_CENTRE_90Hz; params.BE_HPF = LVM_BE_HPF_ON; /* PSA Control parameters */ params.PSA_Enable = LVM_PSA_OFF; params.PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM; return RetCode::SUCCESS; } void BundleContext::initHeadroomParameter(LVM_HeadroomParams_t& params) const { params.pHeadroomDefinition = getDefaultEqualizerHeadroomBanDefs(); params.NHeadroomBands = 2; params.Headroom_OperatingMode = LVM_HEADROOM_OFF; } LVM_EQNB_BandDef_t *BundleContext::getDefaultEqualizerBandDefs() { static LVM_EQNB_BandDef_t* BandDefs = []() { static LVM_EQNB_BandDef_t tempDefs[lvm::MAX_NUM_BANDS]; /* N-Band Equaliser parameters */ for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) { tempDefs[i].Frequency = lvm::kPresetsFrequencies[i]; tempDefs[i].QFactor = lvm::kPresetsQFactors[i]; tempDefs[i].Gain = lvm::kSoftPresets[0/* normal */][i]; } return tempDefs; }(); return BandDefs; } LVM_HeadroomBandDef_t *BundleContext::getDefaultEqualizerHeadroomBanDefs() { static LVM_HeadroomBandDef_t HeadroomBandDef[LVM_HEADROOM_MAX_NBANDS] = { { .Limit_Low = 20, .Limit_High = 4999, .Headroom_Offset = 0, }, { .Limit_Low = 5000, .Limit_High = 24000, .Headroom_Offset = 0, }, }; return HeadroomBandDef; } std::vector BundleContext::getSpeakerAngles( const Virtualizer::SpeakerAnglesPayload payload) { std::vector angles; auto chCount = ::aidl::android::hardware::audio::common::getChannelCount(payload.layout); RETURN_VALUE_IF(!isConfigSupportedVirtualizer(chCount, payload.device), angles, "payloadNotSupported"); if (chCount == 1) { angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT, .azimuthDegree = 0, .elevationDegree = 0}}; } else { angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT, .azimuthDegree = -90, .elevationDegree = 0}, {.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_RIGHT, .azimuthDegree = 90, .elevationDegree = 0}}; } return angles; } IEffect::Status BundleContext::process(float* in, float* out, int samples) { IEffect::Status status = {EX_NULL_POINTER, 0, 0}; RETURN_VALUE_IF(!in, status, "nullInput"); RETURN_VALUE_IF(!out, status, "nullOutput"); status = {EX_ILLEGAL_STATE, 0, 0}; int64_t inputFrameCount = getCommon().input.frameCount; int64_t outputFrameCount = getCommon().output.frameCount; RETURN_VALUE_IF(inputFrameCount != outputFrameCount, status, "FrameCountMismatch"); int isDataAvailable = true; auto frameSize = getInputFrameSize(); RETURN_VALUE_IF(0 == frameSize, status, "zeroFrameSize"); if ((mEffectProcessCalled & 1 << int(mType)) != 0) { const int undrainedEffects = mEffectInDrain & ~mEffectProcessCalled; if ((undrainedEffects & 1 << int(lvm::BundleEffectType::EQUALIZER)) != 0) { mSamplesToExitCountEq = 0; --mNumberEffectsEnabled; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::EQUALIZER)); } if ((undrainedEffects & 1 << int(lvm::BundleEffectType::BASS_BOOST)) != 0) { mSamplesToExitCountBb = 0; --mNumberEffectsEnabled; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::BASS_BOOST)); } if ((undrainedEffects & 1 << int(lvm::BundleEffectType::VIRTUALIZER)) != 0) { mSamplesToExitCountVirt = 0; --mNumberEffectsEnabled; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VIRTUALIZER)); } if ((undrainedEffects & 1 << int(lvm::BundleEffectType::VOLUME)) != 0) { --mNumberEffectsEnabled; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME)); } } mEffectProcessCalled |= 1 << int(mType); if (!mEnabled) { switch (mType) { case lvm::BundleEffectType::EQUALIZER: if (mSamplesToExitCountEq > 0) { mSamplesToExitCountEq -= samples; } if (mSamplesToExitCountEq <= 0) { isDataAvailable = false; if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::EQUALIZER)) != 0) { mNumberEffectsEnabled--; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::EQUALIZER)); } } break; case lvm::BundleEffectType::BASS_BOOST: if (mSamplesToExitCountBb > 0) { mSamplesToExitCountBb -= samples; } if (mSamplesToExitCountBb <= 0) { isDataAvailable = false; if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::BASS_BOOST)) != 0) { mNumberEffectsEnabled--; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::BASS_BOOST)); } } break; case lvm::BundleEffectType::VIRTUALIZER: if (mSamplesToExitCountVirt > 0) { mSamplesToExitCountVirt -= samples; } if (mSamplesToExitCountVirt <= 0) { isDataAvailable = false; if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::VIRTUALIZER)) != 0) { mNumberEffectsEnabled--; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VIRTUALIZER)); } } break; case lvm::BundleEffectType::VOLUME: isDataAvailable = false; if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::VOLUME)) != 0) { mNumberEffectsEnabled--; mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME)); } break; } } if (isDataAvailable) { mNumberEffectsCalled++; } if (mNumberEffectsCalled >= mNumberEffectsEnabled) { // We expect the # effects called to be equal to # effects enabled in sequence (including // draining effects). Warn if this is not the case due to inconsistent calls. ALOGW_IF(mNumberEffectsCalled > mNumberEffectsEnabled, "%s Number of effects called %d is greater than number of effects enabled %d", __func__, mNumberEffectsCalled, mNumberEffectsEnabled); mEffectProcessCalled = 0; // reset our consistency check. mNumberEffectsCalled = 0; int frames = samples * sizeof(float) / frameSize; int bufferIndex = 0; // LVM library supports max of int16_t frames at a time and should be multiple of // kBlockSizeMultiple. constexpr int kBlockSizeMultiple = 4; constexpr int kMaxBlockFrames = (std::numeric_limits::max() / kBlockSizeMultiple) * kBlockSizeMultiple; while (frames > 0) { /* Process the samples */ LVM_ReturnStatus_en lvmStatus; int processFrames = std::min(frames, kMaxBlockFrames); lvmStatus = LVM_Process(mInstance, in + bufferIndex, out + bufferIndex, processFrames, 0); if (lvmStatus != LVM_SUCCESS) { LOG(ERROR) << "LVM_Process failed with error: " << lvmStatus; return {EX_UNSUPPORTED_OPERATION, 0, 0}; } frames -= processFrames; int processedSize = processFrames * frameSize / sizeof(float); bufferIndex += processedSize; } } else { for (int i = 0; i < samples; i++) { out[i] = in[i]; } } return {STATUS_OK, samples, samples}; } } // namespace aidl::android::hardware::audio::effect