APM: update logic of populating profiles for dynamic mix port.
For AIDL HAL, use getAudioPort API to query the profiles for the dynamic
mix ports.
For HIDL HAL, if the HAL supports getAudioPort API, add the profiles of
the device port that contain attributes also reported by getParameters
API. The attributes reported by getParameters API but not in device port
will also be added to mix port.
The reason of using getAudioPort API instead of getParameters is that
getAudioPort API can return well structed audio profiles, which show the
correct relationship between audio format and sample rates, channel
masks.
Test: repo steps from the bug
Test: atest audiofoundation_containers_test
Test: atest audiopolicy_tests
Bug: 284033428
Change-Id: I6d3faf49470514c05fe57be755bb868d74d74dbb
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0d539c0..a277ad1 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -189,6 +189,7 @@
BINDER_METHOD_ENTRY(supportsBluetoothVariableLatency) \
BINDER_METHOD_ENTRY(getSoundDoseInterface) \
BINDER_METHOD_ENTRY(getAudioPolicyConfig) \
+BINDER_METHOD_ENTRY(getAudioMixPort) \
// singleton for Binder Method Statistics for IAudioFlinger
static auto& getIAudioFlingerStatistics() {
@@ -4607,6 +4608,24 @@
return mPatchPanel->listAudioPatches_l(num_patches, patches);
}
+/**
+ * Get the attributes of the mix port when connecting to the given device port.
+ */
+status_t AudioFlinger::getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const {
+ if (status_t status = AudioValidator::validateAudioPort(*devicePort); status != NO_ERROR) {
+ ALOGE("%s, invalid device port, status=%d", __func__, status);
+ return status;
+ }
+ if (status_t status = AudioValidator::validateAudioPort(*mixPort); status != NO_ERROR) {
+ ALOGE("%s, invalid mix port, status=%d", __func__, status);
+ return status;
+ }
+
+ audio_utils::lock_guard _l(mutex());
+ return mPatchPanel->getAudioMixPort_l(devicePort, mixPort);
+}
+
// ----------------------------------------------------------------------------
status_t AudioFlinger::onTransactWrapper(TransactionCode code,
@@ -4640,6 +4659,7 @@
case TransactionCode::GET_SUPPORTED_LATENCY_MODES:
case TransactionCode::INVALIDATE_TRACKS:
case TransactionCode::GET_AUDIO_POLICY_CONFIG:
+ case TransactionCode::GET_AUDIO_MIX_PORT:
ALOGW("%s: transaction %d received from PID %d",
__func__, code, IPCThreadState::self()->getCallingPid());
// return status only for non void methods
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2c34144..e7f9255 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -255,6 +255,10 @@
status_t getAudioPolicyConfig(media::AudioPolicyConfig* config) final
EXCLUDES_AudioFlinger_Mutex;
+ // Get the attributes of the mix port when connecting to the given device port.
+ status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+ struct audio_port_v7* mixPort) const final EXCLUDES_AudioFlinger_Mutex;
+
status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
const std::function<status_t()>& delegate) final EXCLUDES_AudioFlinger_Mutex;
diff --git a/services/audioflinger/IAfPatchPanel.h b/services/audioflinger/IAfPatchPanel.h
index 5a6621e..6110e4c 100644
--- a/services/audioflinger/IAfPatchPanel.h
+++ b/services/audioflinger/IAfPatchPanel.h
@@ -302,6 +302,13 @@
virtual void closeThreadInternal_l(const sp<IAfThreadBase>& thread) const
REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
+
+ /**
+ * Get the attributes of the mix port when connecting to the given device port.
+ */
+ virtual status_t getAudioMixPort_l(
+ const struct audio_port_v7* devicePort,
+ struct audio_port_v7* mixPort) REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
};
} // namespace android
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 7d3900b..17591dd 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -447,6 +447,24 @@
return status;
}
+status_t PatchPanel::getAudioMixPort_l(const audio_port_v7 *devicePort,
+ audio_port_v7 *mixPort) {
+ if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
+ ALOGE("%s the type of given device port is not DEVICE", __func__);
+ return INVALID_OPERATION;
+ }
+ if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
+ ALOGE("%s the type of given mix port is not MIX", __func__);
+ return INVALID_OPERATION;
+ }
+ AudioHwDevice* hwDevice = findAudioHwDeviceByModule_l(devicePort->ext.device.hw_module);
+ if (hwDevice == nullptr) {
+ ALOGW("%s cannot find hw module %d", __func__, devicePort->ext.device.hw_module);
+ return BAD_VALUE;
+ }
+ return hwDevice->getAudioMixPort(devicePort, mixPort);
+}
+
PatchPanel::Patch::~Patch()
{
ALOGE_IF(isSoftware(), "Software patch connections leaked %d %d",
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 1ff8fff..b107eb0 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -73,6 +73,12 @@
void closeThreadInternal_l(const sp<IAfThreadBase>& thread) const final
REQUIRES(audio_utils::AudioFlinger_Mutex);
+ /**
+ * Get the attributes of the mix port when connecting to the given device port
+ */
+ status_t getAudioMixPort_l(const audio_port_v7* devicePort, audio_port_v7* mixPort) final
+ REQUIRES(audio_utils::AudioFlinger_Mutex);
+
private:
AudioHwDevice* findAudioHwDeviceByModule_l(audio_module_handle_t module)
REQUIRES(audio_utils::AudioFlinger_Mutex);
diff --git a/services/audioflinger/datapath/AudioHwDevice.cpp b/services/audioflinger/datapath/AudioHwDevice.cpp
index 9ff316c..67e9991 100644
--- a/services/audioflinger/datapath/AudioHwDevice.cpp
+++ b/services/audioflinger/datapath/AudioHwDevice.cpp
@@ -118,5 +118,10 @@
return mHwDevice->getAAudioHardwareBurstMinUsec();
}
+status_t AudioHwDevice::getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const {
+ return mHwDevice->getAudioMixPort(devicePort, mixPort);
+}
+
}; // namespace android
diff --git a/services/audioflinger/datapath/AudioHwDevice.h b/services/audioflinger/datapath/AudioHwDevice.h
index f9cb80e..cfb6fbd 100644
--- a/services/audioflinger/datapath/AudioHwDevice.h
+++ b/services/audioflinger/datapath/AudioHwDevice.h
@@ -101,6 +101,9 @@
[[nodiscard]] int32_t getAAudioHardwareBurstMinUsec() const;
+ [[nodiscard]] status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) const;
+
private:
const audio_module_handle_t mHandle;
const char * const mModuleName;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index da0df5f..d49a002 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -574,6 +574,10 @@
media::DeviceConnectedState state) = 0;
virtual status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) = 0;
+
+ // Get the attributes of the mix port when connecting to the given device port.
+ virtual status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *mixPort) = 0;
};
// These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index a2cacd2..f3a9518 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -218,6 +218,8 @@
status_t readFromParcelable(const media::AudioPortFw& parcelable);
+ void importAudioPort(const audio_port_v7& port) override;
+
// Number of streams currently opened for this profile.
uint32_t curOpenCount;
// Number of streams currently active for this profile. This is not the number of active clients
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 25b1c5c..dd222de 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -189,6 +189,31 @@
return status;
}
+void IOProfile::importAudioPort(const audio_port_v7 &port) {
+ if (mProfiles.hasDynamicFormat()) {
+ std::set<audio_format_t> formats;
+ for (size_t i = 0; i < port.num_audio_profiles; ++i) {
+ formats.insert(port.audio_profiles[i].format);
+ }
+ addProfilesForFormats(mProfiles, FormatVector(formats.begin(), formats.end()));
+ }
+ for (audio_format_t format : mProfiles.getSupportedFormats()) {
+ for (size_t i = 0; i < port.num_audio_profiles; ++i) {
+ if (port.audio_profiles[i].format == format) {
+ ChannelMaskSet channelMasks(port.audio_profiles[i].channel_masks,
+ port.audio_profiles[i].channel_masks +
+ port.audio_profiles[i].num_channel_masks);
+ SampleRateSet sampleRates(port.audio_profiles[i].sample_rates,
+ port.audio_profiles[i].sample_rates +
+ port.audio_profiles[i].num_sample_rates);
+ addDynamicAudioProfileAndSort(
+ mProfiles, sp<AudioProfile>::make(
+ format, channelMasks, sampleRates));
+ }
+ }
+ }
+}
+
void IOProfile::dump(String8 *dst, int spaces) const
{
String8 extraInfo;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index cc32aec..2d17596 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -6519,7 +6519,7 @@
mpClientInterface->setParameters(input, String8(param));
free(param);
}
- updateAudioProfiles(device, input, profile->getAudioProfiles());
+ updateAudioProfiles(device, input, profile);
if (!profile->hasValidAudioProfile()) {
ALOGW("checkInputsForDevice() direct input missing param");
desc->close();
@@ -8049,77 +8049,54 @@
void AudioPolicyManager::updateAudioProfiles(const sp<DeviceDescriptor>& devDesc,
audio_io_handle_t ioHandle,
- AudioProfileVector &profiles)
-{
- String8 reply;
- audio_devices_t device = devDesc->type();
-
- // Format MUST be checked first to update the list of AudioProfile
- if (profiles.hasDynamicFormat()) {
- reply = mpClientInterface->getParameters(
- ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
- ALOGV("%s: supported formats %d, %s", __FUNCTION__, ioHandle, reply.c_str());
- AudioParameter repliedParameters(reply);
- FormatVector formats;
- if (repliedParameters.get(
- String8(AudioParameter::keyStreamSupportedFormats), reply) == NO_ERROR) {
- formats = formatsFromString(reply.c_str());
- } else if (devDesc->hasValidAudioProfile()) {
- ALOGD("%s: using the device profiles", __func__);
- formats = devDesc->getAudioProfiles().getSupportedFormats();
- } else {
- ALOGE("%s: failed to retrieve format, bailing out", __func__);
- return;
- }
- mReportedFormatsMap[devDesc] = formats;
- if (device == AUDIO_DEVICE_OUT_HDMI
- || isDeviceOfModule(devDesc, AUDIO_HARDWARE_MODULE_ID_MSD)) {
- modifySurroundFormats(devDesc, &formats);
- }
- addProfilesForFormats(profiles, formats);
+ const sp<IOProfile>& profile) {
+ if (!profile->hasDynamicAudioProfile()) {
+ return;
}
- for (audio_format_t format : profiles.getSupportedFormats()) {
- std::optional<ChannelMaskSet> channelMasks;
- SampleRateSet samplingRates;
- AudioParameter requestedParameters;
- requestedParameters.addInt(String8(AudioParameter::keyFormat), format);
+ audio_port_v7 devicePort;
+ devDesc->toAudioPort(&devicePort);
- if (profiles.hasDynamicRateFor(format)) {
- reply = mpClientInterface->getParameters(
- ioHandle,
- requestedParameters.toString() + ";" +
- AudioParameter::keyStreamSupportedSamplingRates);
- ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.c_str());
- AudioParameter repliedParameters(reply);
- if (repliedParameters.get(
- String8(AudioParameter::keyStreamSupportedSamplingRates), reply) == NO_ERROR) {
- samplingRates = samplingRatesFromString(reply.c_str());
- } else {
- samplingRates = devDesc->getAudioProfiles().getSampleRatesFor(format);
- }
- }
- if (profiles.hasDynamicChannelsFor(format)) {
- reply = mpClientInterface->getParameters(ioHandle,
- requestedParameters.toString() + ";" +
- AudioParameter::keyStreamSupportedChannels);
- ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.c_str());
- AudioParameter repliedParameters(reply);
- if (repliedParameters.get(
- String8(AudioParameter::keyStreamSupportedChannels), reply) == NO_ERROR) {
- channelMasks = channelMasksFromString(reply.c_str());
- } else {
- channelMasks = devDesc->getAudioProfiles().getChannelMasksFor(format);
- }
- if (channelMasks.has_value() && (device == AUDIO_DEVICE_OUT_HDMI
- || isDeviceOfModule(devDesc, AUDIO_HARDWARE_MODULE_ID_MSD))) {
- modifySurroundChannelMasks(&channelMasks.value());
- }
- }
- addDynamicAudioProfileAndSort(
- profiles, new AudioProfile(
- format, channelMasks.value_or(ChannelMaskSet()), samplingRates));
+ audio_port_v7 mixPort;
+ profile->toAudioPort(&mixPort);
+ mixPort.ext.mix.handle = ioHandle;
+
+ status_t status = mpClientInterface->getAudioMixPort(&devicePort, &mixPort);
+ if (status != NO_ERROR) {
+ ALOGE("%s failed to query the attributes of the mix port", __func__);
+ return;
}
+
+ std::set<audio_format_t> supportedFormats;
+ for (size_t i = 0; i < mixPort.num_audio_profiles; ++i) {
+ supportedFormats.insert(mixPort.audio_profiles[i].format);
+ }
+ FormatVector formats(supportedFormats.begin(), supportedFormats.end());
+ mReportedFormatsMap[devDesc] = formats;
+
+ if (devDesc->type() == AUDIO_DEVICE_OUT_HDMI ||
+ isDeviceOfModule(devDesc,AUDIO_HARDWARE_MODULE_ID_MSD)) {
+ modifySurroundFormats(devDesc, &formats);
+ size_t modifiedNumProfiles = 0;
+ for (size_t i = 0; i < mixPort.num_audio_profiles; ++i) {
+ if (std::find(formats.begin(), formats.end(), mixPort.audio_profiles[i].format) ==
+ formats.end()) {
+ // Skip the format that is not present after modifying surround formats.
+ continue;
+ }
+ memcpy(&mixPort.audio_profiles[modifiedNumProfiles], &mixPort.audio_profiles[i],
+ sizeof(struct audio_profile));
+ ChannelMaskSet channels(mixPort.audio_profiles[modifiedNumProfiles].channel_masks,
+ mixPort.audio_profiles[modifiedNumProfiles].channel_masks +
+ mixPort.audio_profiles[modifiedNumProfiles].num_channel_masks);
+ modifySurroundChannelMasks(&channels);
+ std::copy(channels.begin(), channels.end(),
+ std::begin(mixPort.audio_profiles[modifiedNumProfiles].channel_masks));
+ mixPort.audio_profiles[modifiedNumProfiles++].num_channel_masks = channels.size();
+ }
+ mixPort.num_audio_profiles = modifiedNumProfiles;
+ }
+ profile->importAudioPort(mixPort);
}
status_t AudioPolicyManager::installPatch(const char *caller,
@@ -8246,7 +8223,7 @@
mpClientInterface->setParameters(output, String8(param));
free(param);
}
- updateAudioProfiles(device, output, profile->getAudioProfiles());
+ updateAudioProfiles(device, output, profile);
if (!profile->hasValidAudioProfile()) {
ALOGW("%s() missing param", __func__);
desc->close();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 88bafef..440fd01 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -1040,9 +1040,9 @@
void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr);
- // If any, resolve any "dynamic" fields of an Audio Profiles collection
+ // If any, resolve any "dynamic" fields of the Audio Profiles collection of and IOProfile
void updateAudioProfiles(const sp<DeviceDescriptor>& devDesc, audio_io_handle_t ioHandle,
- AudioProfileVector &profiles);
+ const sp<IOProfile> &profiles);
// Notify the policy client to prepare for disconnecting external device.
void prepareToDisconnectExternalDevice(const sp<DeviceDescriptor> &device);
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 2874824..7584632 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -340,4 +340,14 @@
return af->invalidateTracks(portIds);
}
+status_t AudioPolicyService::AudioPolicyClient::getAudioMixPort(
+ const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *port) {
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ return PERMISSION_DENIED;
+ }
+ return af->getAudioMixPort(devicePort, port);
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d0cde64..8d5628f 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -856,6 +856,9 @@
status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) override;
+ status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+ struct audio_port_v7 *port) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 3629c16..7ef0266 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -201,6 +201,26 @@
return mAudioParameters.toString();
}
+ status_t getAudioMixPort(const struct audio_port_v7 *devicePort __unused,
+ struct audio_port_v7 *mixPort) override {
+ mixPort->num_audio_profiles = 0;
+ for (auto format : mSupportedFormats) {
+ const int i = mixPort->num_audio_profiles;
+ mixPort->audio_profiles[i].format = format;
+ mixPort->audio_profiles[i].num_sample_rates = 1;
+ mixPort->audio_profiles[i].sample_rates[0] = 48000;
+ mixPort->audio_profiles[i].num_channel_masks = 0;
+ for (const auto& cm : mSupportedChannelMasks) {
+ if (audio_channel_mask_is_valid(cm)) {
+ mixPort->audio_profiles[i].channel_masks[
+ mixPort->audio_profiles[i].num_channel_masks++] = cm;
+ }
+ }
+ mixPort->num_audio_profiles++;
+ }
+ return NO_ERROR;
+ }
+
void addSupportedFormat(audio_format_t format) {
mSupportedFormats.insert(format);
}
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 2ae0e97..e55e935 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -106,6 +106,10 @@
status_t invalidateTracks(const std::vector<audio_port_handle_t>& /*portIds*/) override {
return NO_INIT;
}
+ status_t getAudioMixPort(const struct audio_port_v7 *devicePort __unused,
+ struct audio_port_v7 *mixPort __unused) override {
+ return INVALID_OPERATION;
+ }
};
} // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 5e58dbb..378255d 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -1423,6 +1423,7 @@
ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTest::SetUp());
mClient->addSupportedFormat(AUDIO_FORMAT_AC3);
mClient->addSupportedFormat(AUDIO_FORMAT_E_AC3);
+ mClient->addSupportedChannelMask(AUDIO_CHANNEL_OUT_STEREO);
mManager->setDeviceConnectionState(
AUDIO_DEVICE_OUT_HDMI, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
"" /*address*/, "" /*name*/, AUDIO_FORMAT_DEFAULT);
@@ -1548,13 +1549,13 @@
mManager->setForceUse(
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL);
- ASSERT_EQ(NO_ERROR, mManager->setSurroundFormatEnabled(GetParam(), false /*enabled*/));
- auto formats = getFormatsFromPorts();
- ASSERT_EQ(0, formats.count(GetParam()));
-
ASSERT_EQ(NO_ERROR, mManager->setSurroundFormatEnabled(GetParam(), true /*enabled*/));
- formats = getFormatsFromPorts();
+ auto formats = getFormatsFromPorts();
ASSERT_EQ(1, formats.count(GetParam()));
+
+ ASSERT_EQ(NO_ERROR, mManager->setSurroundFormatEnabled(GetParam(), false /*enabled*/));
+ formats = getFormatsFromPorts();
+ ASSERT_EQ(0, formats.count(GetParam()));
}
TEST_P(AudioPolicyManagerTestForHdmi,