libaudiohal@aidl: Implement gain change via 'setPortConfig'
The path of updating gain of a port config was not implemented
properly resulting in the update not being sent to the HAL.
Bug: 345852128
Test: atest CoreAudioHalAidlTest
Change-Id: I4ed81a57178fd6f37085c86a0dc98c0c32302f46
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index cbade70..052522f 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -37,6 +37,7 @@
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::AudioOutputFlags;
@@ -325,8 +326,8 @@
}
status_t Hal2AidlMapper::findOrCreateDevicePortConfig(
- const AudioDevice& device, const AudioConfig* config, AudioPortConfig* portConfig,
- bool* created) {
+ const AudioDevice& device, const AudioConfig* config, const AudioGainConfig* gainConfig,
+ AudioPortConfig* portConfig, bool* created) {
if (auto portConfigIt = findPortConfig(device); portConfigIt == mPortConfigs.end()) {
auto portsIt = findPort(device);
if (portsIt == mPorts.end()) {
@@ -339,12 +340,18 @@
if (config != nullptr) {
setPortConfigFromConfig(&requestedPortConfig, *config);
}
+ if (gainConfig != nullptr) {
+ requestedPortConfig.gain = *gainConfig;
+ }
return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
} else {
AudioPortConfig requestedPortConfig = portConfigIt->second;
if (config != nullptr) {
setPortConfigFromConfig(&requestedPortConfig, *config);
}
+ if (gainConfig != nullptr) {
+ requestedPortConfig.gain = *gainConfig;
+ }
if (requestedPortConfig != portConfigIt->second) {
return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
@@ -447,18 +454,26 @@
requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
portConfig, created);
} else if (requestedPortConfig.ext.getTag() == Tag::device) {
- if (const auto& p = requestedPortConfig;
- p.sampleRate.has_value() && p.channelMask.has_value() &&
- p.format.has_value()) {
- AudioConfig config;
- setConfigFromPortConfig(&config, requestedPortConfig);
+ const auto& p = requestedPortConfig;
+ const bool hasAudioConfig =
+ p.sampleRate.has_value() && p.channelMask.has_value() && p.format.has_value();
+ const bool hasGainConfig = p.gain.has_value();
+ if (hasAudioConfig || hasGainConfig) {
+ AudioConfig config, *configPtr = nullptr;
+ if (hasAudioConfig) {
+ setConfigFromPortConfig(&config, requestedPortConfig);
+ configPtr = &config;
+ }
+ const AudioGainConfig* gainConfigPtr = nullptr;
+ if (hasGainConfig) gainConfigPtr = &(*(p.gain));
return findOrCreateDevicePortConfig(
- requestedPortConfig.ext.get<Tag::device>().device, &config,
+ requestedPortConfig.ext.get<Tag::device>().device, configPtr, gainConfigPtr,
portConfig, created);
} else {
+ ALOGD("%s: device port config does not have audio or gain config specified", __func__);
return findOrCreateDevicePortConfig(
requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
- portConfig, created);
+ nullptr /*gainConfig*/, portConfig, created);
}
}
ALOGW("%s: unsupported audio port config: %s",
@@ -769,7 +784,7 @@
// then find / create a patch between them, and open a stream on the mix port.
AudioPortConfig devicePortConfig;
bool created = false;
- RETURN_STATUS_IF_ERROR(findOrCreateDevicePortConfig(device, config,
+ RETURN_STATUS_IF_ERROR(findOrCreateDevicePortConfig(device, config, nullptr /*gainConfig*/,
&devicePortConfig, &created));
LOG_ALWAYS_FATAL_IF(devicePortConfig.id == 0);
if (created) {
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
index c70c8af..710b43e 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.h
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -163,6 +163,7 @@
status_t findOrCreateDevicePortConfig(
const ::aidl::android::media::audio::common::AudioDevice& device,
const ::aidl::android::media::audio::common::AudioConfig* config,
+ const ::aidl::android::media::audio::common::AudioGainConfig* gainConfig,
::aidl::android::media::audio::common::AudioPortConfig* portConfig,
bool* created);
// If the resulting 'portConfig->id' is 0, that means the config was not created,
diff --git a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
index 0bd6fb0..50b748e 100644
--- a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
+++ b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
@@ -29,6 +29,7 @@
#include <aidl/android/hardware/audio/core/BnModule.h>
#include <aidl/android/hardware/audio/core/BnStreamCommon.h>
#include <aidl/android/media/audio/BnHalAdapterVendorExtension.h>
+#include <aidl/android/media/audio/common/AudioGainMode.h>
#include <aidl/android/media/audio/common/Int.h>
#include <utils/Log.h>
@@ -44,6 +45,8 @@
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::AudioGainMode;
using ::aidl::android::media::audio::common::AudioIoFlags;
using ::aidl::android::media::audio::common::AudioPort;
using ::aidl::android::media::audio::common::AudioPortConfig;
@@ -179,6 +182,11 @@
primaryInMix.profiles = standardPcmAudioProfiles;
c.ports.push_back(primaryInMix);
+ AudioPort speakerOutDevice = createPort(c.nextPortId++, "Speaker", 0, false,
+ createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0));
+ speakerOutDevice.profiles = standardPcmAudioProfiles;
+ c.ports.push_back(speakerOutDevice);
+
AudioPort btOutDevice =
createPort(c.nextPortId++, "BT A2DP Out", 0, false,
createPortDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
@@ -209,6 +217,13 @@
getAudioPatches(&result);
return result;
}
+ std::optional<AudioPortConfig> getPortConfig(int32_t id) {
+ auto iter = findById<AudioPortConfig>(mConfig.portConfigs, id);
+ if (iter != mConfig.portConfigs.end()) {
+ return *iter;
+ }
+ return std::nullopt;
+ }
private:
ndk::ScopedAStatus setModuleDebug(
@@ -646,6 +661,19 @@
}
} // namespace aidl::android::hardware::audio::core
+namespace aidl::android::media::audio::common {
+template <typename P>
+std::enable_if_t<std::is_function_v<typename mf_traits<decltype(&P::toString)>::member_type>,
+ std::ostream&>
+operator<<(std::ostream& os, const P& p) {
+ return os << p.toString();
+}
+template <typename E>
+std::enable_if_t<std::is_enum_v<E>, std::ostream&> operator<<(std::ostream& os, const E& e) {
+ return os << toString(e);
+}
+} // namespace aidl::android::media::audio::common
+
using namespace android;
namespace {
@@ -1214,3 +1242,55 @@
EXPECT_EQ(std::vector<int32_t>{backMicPortConfig.id}, patchIt->sourcePortConfigIds);
EXPECT_EQ(std::vector<int32_t>{mixPortConfig.id}, patchIt->sinkPortConfigIds);
}
+
+TEST_F(Hal2AidlMapperTest, SetAudioPortConfigGainChangeExistingPortConfig) {
+ // First set config, then update gain.
+ AudioPortConfig speakerPortConfig;
+ speakerPortConfig.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
+ speakerPortConfig.channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO);
+ speakerPortConfig.format =
+ AudioFormatDescription{.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT};
+ speakerPortConfig.sampleRate = ::aidl::android::media::audio::common::Int(48000);
+ AudioPortConfig resultingPortConfig;
+ ASSERT_EQ(OK,
+ mMapper->setPortConfig(speakerPortConfig, std::set<int32_t>(), &resultingPortConfig));
+ EXPECT_NE(0, resultingPortConfig.id);
+ EXPECT_NE(0, resultingPortConfig.portId);
+
+ AudioPortConfig gainUpdate;
+ gainUpdate.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
+ AudioGainConfig gainConfig{.index = -1,
+ .mode = 1 << static_cast<int>(AudioGainMode::JOINT),
+ .channelMask = AudioChannelLayout{},
+ .values = std::vector<int32_t>{-3200},
+ .rampDurationMs = 0};
+ gainUpdate.gain = gainConfig;
+ AudioPortConfig resultingGainUpdate;
+ ASSERT_EQ(OK, mMapper->setPortConfig(gainUpdate, std::set<int32_t>(), &resultingGainUpdate));
+ EXPECT_EQ(resultingPortConfig.id, resultingGainUpdate.id);
+ auto updatedPortConfig = mModule->getPortConfig(resultingGainUpdate.id);
+ ASSERT_TRUE(updatedPortConfig.has_value());
+ ASSERT_TRUE(updatedPortConfig->gain.has_value());
+ EXPECT_EQ(gainConfig, updatedPortConfig->gain);
+}
+
+TEST_F(Hal2AidlMapperTest, SetAudioPortConfigGainChangeFromScratch) {
+ // Set gain as the first operation, the HAL should suggest the rest of the configuration.
+ AudioPortConfig gainSet;
+ gainSet.ext = createPortDeviceExt(AudioDeviceType::OUT_SPEAKER, 0);
+ AudioGainConfig gainConfig{.index = -1,
+ .mode = 1 << static_cast<int>(AudioGainMode::JOINT),
+ .channelMask = AudioChannelLayout{},
+ .values = std::vector<int32_t>{-3200},
+ .rampDurationMs = 0};
+ gainSet.gain = gainConfig;
+ AudioPortConfig resultingPortConfig;
+ ASSERT_EQ(OK, mMapper->setPortConfig(gainSet, std::set<int32_t>(), &resultingPortConfig));
+ EXPECT_NE(0, resultingPortConfig.id);
+ EXPECT_NE(0, resultingPortConfig.portId);
+ auto portConfig = mModule->getPortConfig(resultingPortConfig.id);
+ ASSERT_TRUE(portConfig.has_value());
+ ASSERT_TRUE(portConfig->gain.has_value());
+ EXPECT_EQ(gainConfig, portConfig->gain);
+}