Loading audio/aidl/default/Module.cpp +50 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ using aidl::android::media::audio::common::AudioDevice; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; using aidl::android::media::audio::common::AudioGainConfig; using aidl::android::media::audio::common::AudioInputFlags; using aidl::android::media::audio::common::AudioIoFlags; using aidl::android::media::audio::common::AudioMMapPolicy; Loading Loading @@ -1200,7 +1201,9 @@ ndk::ScopedAStatus Module::setAudioPortConfigImpl( } if (in_requested.gain.has_value()) { // Let's pretend that gain can always be applied. if (!setAudioPortConfigGain(*portIt, in_requested.gain.value())) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } out_suggested->gain = in_requested.gain.value(); } Loading Loading @@ -1242,6 +1245,52 @@ ndk::ScopedAStatus Module::setAudioPortConfigImpl( return ndk::ScopedAStatus::ok(); } bool Module::setAudioPortConfigGain(const AudioPort& port, const AudioGainConfig& gainRequested) { auto& ports = getConfig().ports; if (gainRequested.index < 0 || gainRequested.index >= (int)port.gains.size()) { LOG(ERROR) << __func__ << ": gains for port " << port.id << " is undefined"; return false; } int stepValue = port.gains[gainRequested.index].stepValue; if (stepValue == 0) { LOG(ERROR) << __func__ << ": port gain step value is 0"; return false; } int minValue = port.gains[gainRequested.index].minValue; int maxValue = port.gains[gainRequested.index].maxValue; if (gainRequested.values[0] > maxValue || gainRequested.values[0] < minValue) { LOG(ERROR) << __func__ << ": gain value " << gainRequested.values[0] << " out of range of min and max gain config"; return false; } int gainIndex = (gainRequested.values[0] - minValue) / stepValue; int totalSteps = (maxValue - minValue) / stepValue; if (totalSteps == 0) { LOG(ERROR) << __func__ << ": difference between port gain min value " << minValue << " and max value " << maxValue << " is less than step value " << stepValue; return false; } // Root-power quantities are used in curve: // 10^((minMb / 100 + (maxMb / 100 - minMb / 100) * gainIndex / totalSteps) / (10 * 2)) // where 100 is the conversion from mB to dB, 10 comes from the log 10 conversion from power // ratios, and 2 means are the square of amplitude. float gain = pow(10, (minValue + (maxValue - minValue) * (gainIndex / (float)totalSteps)) / 2000); if (gain < 0) { LOG(ERROR) << __func__ << ": gain " << gain << " is less than 0"; return false; } for (const auto& route : getConfig().routes) { if (route.sinkPortId != port.id) { continue; } for (const auto sourcePortId : route.sourcePortIds) { mStreams.setGain(sourcePortId, gain); } } return true; } ndk::ScopedAStatus Module::resetAudioPatch(int32_t in_patchId) { auto& patches = getConfig().patches; auto patchIt = findById<AudioPatch>(patches, in_patchId); Loading audio/aidl/default/Stream.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -855,6 +855,11 @@ ndk::ScopedAStatus StreamCommonImpl::setConnectedDevices( return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus StreamCommonImpl::setGain(float gain) { LOG(DEBUG) << __func__ << ": gain " << gain; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus StreamCommonImpl::bluetoothParametersUpdated() { LOG(DEBUG) << __func__; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); Loading audio/aidl/default/StreamSwitcher.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -260,4 +260,12 @@ ndk::ScopedAStatus StreamSwitcher::bluetoothParametersUpdated() { return mStream->bluetoothParametersUpdated(); } ndk::ScopedAStatus StreamSwitcher::setGain(float gain) { if (mStream == nullptr) { LOG(ERROR) << __func__ << ": stream was closed"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } return mStream->setGain(gain); } } // namespace aidl::android::hardware::audio::core audio/aidl/default/alsa/StreamAlsa.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,7 @@ StreamAlsa::~StreamAlsa() { mReadWriteRetries); maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get()); } else { alsa::applyGain(buffer, mGain, bytesToTransfer, mConfig.value().format, mConfig->channels); for (auto& proxy : mAlsaDeviceProxies) { proxy_write_with_retries(proxy.get(), buffer, bytesToTransfer, mReadWriteRetries); maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get())); Loading Loading @@ -166,4 +167,9 @@ void StreamAlsa::shutdown() { mAlsaDeviceProxies.clear(); } ndk::ScopedAStatus StreamAlsa::setGain(float gain) { mGain = gain; return ndk::ScopedAStatus::ok(); } } // namespace aidl::android::hardware::audio::core audio/aidl/default/alsa/Utils.cpp +66 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include <aidl/android/media/audio/common/AudioFormatType.h> #include <aidl/android/media/audio/common/PcmType.h> #include <android-base/logging.h> #include <audio_utils/primitives.h> #include <cutils/compiler.h> #include "Utils.h" #include "core-impl/utils.h" Loading Loading @@ -343,4 +345,68 @@ pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID); } void applyGain(void* buffer, float gain, size_t bytesToTransfer, enum pcm_format pcmFormat, int channelCount) { if (channelCount != 1 && channelCount != 2) { LOG(WARNING) << __func__ << ": unsupported channel count " << channelCount; return; } if (!getPcmFormatToAudioFormatDescMap().contains(pcmFormat)) { LOG(WARNING) << __func__ << ": unsupported pcm format " << pcmFormat; return; } const float unityGainFloat = 1.0f; if (std::abs(gain - unityGainFloat) < 1e-6) { return; } int numFrames; switch (pcmFormat) { case PCM_FORMAT_S16_LE: { const uint16_t unityGainQ4_12 = u4_12_from_float(unityGainFloat); const uint16_t vl = u4_12_from_float(gain); const uint32_t vrl = (vl << 16) | vl; if (channelCount == 2) { numFrames = bytesToTransfer / sizeof(uint32_t); uint32_t* intBuffer = (uint32_t*)buffer; if (CC_UNLIKELY(vl > unityGainQ4_12)) { // volume is boosted, so we might need to clamp even though // we process only one track. do { int32_t l = mulRL(1, *intBuffer, vrl) >> 12; int32_t r = mulRL(0, *intBuffer, vrl) >> 12; l = clamp16(l); r = clamp16(r); *intBuffer++ = (r << 16) | (l & 0xFFFF); } while (--numFrames); } else { do { int32_t l = mulRL(1, *intBuffer, vrl) >> 12; int32_t r = mulRL(0, *intBuffer, vrl) >> 12; *intBuffer++ = (r << 16) | (l & 0xFFFF); } while (--numFrames); } } else { numFrames = bytesToTransfer / sizeof(uint16_t); int16_t* intBuffer = (int16_t*)buffer; if (CC_UNLIKELY(vl > unityGainQ4_12)) { // volume is boosted, so we might need to clamp even though // we process only one track. do { int32_t mono = mulRL(1, *intBuffer, vrl) >> 12; *intBuffer++ = clamp16(mono); } while (--numFrames); } else { do { int32_t mono = mulRL(1, *intBuffer, vrl) >> 12; *intBuffer++ = static_cast<int16_t>(mono & 0xFFFF); } while (--numFrames); } } } break; default: // TODO(336370745): Implement gain for other supported formats break; } } } // namespace aidl::android::hardware::audio::core::alsa Loading
audio/aidl/default/Module.cpp +50 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ using aidl::android::media::audio::common::AudioDevice; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; using aidl::android::media::audio::common::AudioGainConfig; using aidl::android::media::audio::common::AudioInputFlags; using aidl::android::media::audio::common::AudioIoFlags; using aidl::android::media::audio::common::AudioMMapPolicy; Loading Loading @@ -1200,7 +1201,9 @@ ndk::ScopedAStatus Module::setAudioPortConfigImpl( } if (in_requested.gain.has_value()) { // Let's pretend that gain can always be applied. if (!setAudioPortConfigGain(*portIt, in_requested.gain.value())) { return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); } out_suggested->gain = in_requested.gain.value(); } Loading Loading @@ -1242,6 +1245,52 @@ ndk::ScopedAStatus Module::setAudioPortConfigImpl( return ndk::ScopedAStatus::ok(); } bool Module::setAudioPortConfigGain(const AudioPort& port, const AudioGainConfig& gainRequested) { auto& ports = getConfig().ports; if (gainRequested.index < 0 || gainRequested.index >= (int)port.gains.size()) { LOG(ERROR) << __func__ << ": gains for port " << port.id << " is undefined"; return false; } int stepValue = port.gains[gainRequested.index].stepValue; if (stepValue == 0) { LOG(ERROR) << __func__ << ": port gain step value is 0"; return false; } int minValue = port.gains[gainRequested.index].minValue; int maxValue = port.gains[gainRequested.index].maxValue; if (gainRequested.values[0] > maxValue || gainRequested.values[0] < minValue) { LOG(ERROR) << __func__ << ": gain value " << gainRequested.values[0] << " out of range of min and max gain config"; return false; } int gainIndex = (gainRequested.values[0] - minValue) / stepValue; int totalSteps = (maxValue - minValue) / stepValue; if (totalSteps == 0) { LOG(ERROR) << __func__ << ": difference between port gain min value " << minValue << " and max value " << maxValue << " is less than step value " << stepValue; return false; } // Root-power quantities are used in curve: // 10^((minMb / 100 + (maxMb / 100 - minMb / 100) * gainIndex / totalSteps) / (10 * 2)) // where 100 is the conversion from mB to dB, 10 comes from the log 10 conversion from power // ratios, and 2 means are the square of amplitude. float gain = pow(10, (minValue + (maxValue - minValue) * (gainIndex / (float)totalSteps)) / 2000); if (gain < 0) { LOG(ERROR) << __func__ << ": gain " << gain << " is less than 0"; return false; } for (const auto& route : getConfig().routes) { if (route.sinkPortId != port.id) { continue; } for (const auto sourcePortId : route.sourcePortIds) { mStreams.setGain(sourcePortId, gain); } } return true; } ndk::ScopedAStatus Module::resetAudioPatch(int32_t in_patchId) { auto& patches = getConfig().patches; auto patchIt = findById<AudioPatch>(patches, in_patchId); Loading
audio/aidl/default/Stream.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -855,6 +855,11 @@ ndk::ScopedAStatus StreamCommonImpl::setConnectedDevices( return ndk::ScopedAStatus::ok(); } ndk::ScopedAStatus StreamCommonImpl::setGain(float gain) { LOG(DEBUG) << __func__ << ": gain " << gain; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); } ndk::ScopedAStatus StreamCommonImpl::bluetoothParametersUpdated() { LOG(DEBUG) << __func__; return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); Loading
audio/aidl/default/StreamSwitcher.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -260,4 +260,12 @@ ndk::ScopedAStatus StreamSwitcher::bluetoothParametersUpdated() { return mStream->bluetoothParametersUpdated(); } ndk::ScopedAStatus StreamSwitcher::setGain(float gain) { if (mStream == nullptr) { LOG(ERROR) << __func__ << ": stream was closed"; return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); } return mStream->setGain(gain); } } // namespace aidl::android::hardware::audio::core
audio/aidl/default/alsa/StreamAlsa.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,7 @@ StreamAlsa::~StreamAlsa() { mReadWriteRetries); maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get()); } else { alsa::applyGain(buffer, mGain, bytesToTransfer, mConfig.value().format, mConfig->channels); for (auto& proxy : mAlsaDeviceProxies) { proxy_write_with_retries(proxy.get(), buffer, bytesToTransfer, mReadWriteRetries); maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get())); Loading Loading @@ -166,4 +167,9 @@ void StreamAlsa::shutdown() { mAlsaDeviceProxies.clear(); } ndk::ScopedAStatus StreamAlsa::setGain(float gain) { mGain = gain; return ndk::ScopedAStatus::ok(); } } // namespace aidl::android::hardware::audio::core
audio/aidl/default/alsa/Utils.cpp +66 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ #include <aidl/android/media/audio/common/AudioFormatType.h> #include <aidl/android/media/audio/common/PcmType.h> #include <android-base/logging.h> #include <audio_utils/primitives.h> #include <cutils/compiler.h> #include "Utils.h" #include "core-impl/utils.h" Loading Loading @@ -343,4 +345,68 @@ pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID); } void applyGain(void* buffer, float gain, size_t bytesToTransfer, enum pcm_format pcmFormat, int channelCount) { if (channelCount != 1 && channelCount != 2) { LOG(WARNING) << __func__ << ": unsupported channel count " << channelCount; return; } if (!getPcmFormatToAudioFormatDescMap().contains(pcmFormat)) { LOG(WARNING) << __func__ << ": unsupported pcm format " << pcmFormat; return; } const float unityGainFloat = 1.0f; if (std::abs(gain - unityGainFloat) < 1e-6) { return; } int numFrames; switch (pcmFormat) { case PCM_FORMAT_S16_LE: { const uint16_t unityGainQ4_12 = u4_12_from_float(unityGainFloat); const uint16_t vl = u4_12_from_float(gain); const uint32_t vrl = (vl << 16) | vl; if (channelCount == 2) { numFrames = bytesToTransfer / sizeof(uint32_t); uint32_t* intBuffer = (uint32_t*)buffer; if (CC_UNLIKELY(vl > unityGainQ4_12)) { // volume is boosted, so we might need to clamp even though // we process only one track. do { int32_t l = mulRL(1, *intBuffer, vrl) >> 12; int32_t r = mulRL(0, *intBuffer, vrl) >> 12; l = clamp16(l); r = clamp16(r); *intBuffer++ = (r << 16) | (l & 0xFFFF); } while (--numFrames); } else { do { int32_t l = mulRL(1, *intBuffer, vrl) >> 12; int32_t r = mulRL(0, *intBuffer, vrl) >> 12; *intBuffer++ = (r << 16) | (l & 0xFFFF); } while (--numFrames); } } else { numFrames = bytesToTransfer / sizeof(uint16_t); int16_t* intBuffer = (int16_t*)buffer; if (CC_UNLIKELY(vl > unityGainQ4_12)) { // volume is boosted, so we might need to clamp even though // we process only one track. do { int32_t mono = mulRL(1, *intBuffer, vrl) >> 12; *intBuffer++ = clamp16(mono); } while (--numFrames); } else { do { int32_t mono = mulRL(1, *intBuffer, vrl) >> 12; *intBuffer++ = static_cast<int16_t>(mono & 0xFFFF); } while (--numFrames); } } } break; default: // TODO(336370745): Implement gain for other supported formats break; } } } // namespace aidl::android::hardware::audio::core::alsa