Add support for manually set surround formats.
To make surround sound setting more clear to users, we are changing
surround setting from ALWAYS to MANUAL. With MANUAL, users could enable
surround formats according to their need.
Bug: 67479735
Test: Try creating AudioTrack with enable/disable surround formats.
Change-Id: Ia6c0e1210ff6215f4b80a278a0aa90ca9543f262
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e1467b7..a141f49 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -60,6 +60,26 @@
// media / notification / system volume.
constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+// Array of all surround formats.
+static const audio_format_t SURROUND_FORMATS[] = {
+ AUDIO_FORMAT_AC3,
+ AUDIO_FORMAT_E_AC3,
+ AUDIO_FORMAT_DTS,
+ AUDIO_FORMAT_DTS_HD,
+ AUDIO_FORMAT_AAC_LC,
+ AUDIO_FORMAT_DOLBY_TRUEHD,
+ AUDIO_FORMAT_E_AC3_JOC,
+};
+// Array of all AAC formats. When AAC is enabled by users, all AAC formats should be enabled.
+static const audio_format_t AAC_FORMATS[] = {
+ AUDIO_FORMAT_AAC_LC,
+ AUDIO_FORMAT_AAC_HE_V1,
+ AUDIO_FORMAT_AAC_HE_V2,
+ AUDIO_FORMAT_AAC_ELD,
+ AUDIO_FORMAT_AAC_XHE,
+};
+
// ----------------------------------------------------------------------------
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
@@ -3461,6 +3481,275 @@
return computeVolume(stream, index, device);
}
+status_t AudioPolicyManager::getSupportedFormats(audio_io_handle_t ioHandle,
+ FormatVector& formats) {
+ if (ioHandle == AUDIO_IO_HANDLE_NONE) {
+ return BAD_VALUE;
+ }
+ String8 reply;
+ reply = mpClientInterface->getParameters(
+ ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
+ ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+ AudioParameter repliedParameters(reply);
+ if (repliedParameters.get(
+ String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {
+ ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ for (auto format : formatsFromString(reply.string())) {
+ // Only AUDIO_FORMAT_AAC_LC will be used in Settings UI for all AAC formats.
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ if (format == AAC_FORMATS[i]) {
+ format = AUDIO_FORMAT_AAC_LC;
+ break;
+ }
+ }
+ bool exist = false;
+ for (size_t i = 0; i < formats.size(); i++) {
+ if (format == formats[i]) {
+ exist = true;
+ break;
+ }
+ }
+ bool isSurroundFormat = false;
+ for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+ if (SURROUND_FORMATS[i] == format) {
+ isSurroundFormat = true;
+ break;
+ }
+ }
+ if (!exist && isSurroundFormat) {
+ formats.add(format);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
+ audio_format_t *surroundFormats,
+ bool *surroundFormatsEnabled,
+ bool reported)
+{
+ if (numSurroundFormats == NULL || (*numSurroundFormats != 0 &&
+ (surroundFormats == NULL || surroundFormatsEnabled == NULL))) {
+ return BAD_VALUE;
+ }
+ ALOGV("getSurroundFormats() numSurroundFormats %d surroundFormats %p surroundFormatsEnabled %p",
+ *numSurroundFormats, surroundFormats, surroundFormatsEnabled);
+
+ // Only return value if there is HDMI output.
+ if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
+ return INVALID_OPERATION;
+ }
+
+ size_t formatsWritten = 0;
+ size_t formatsMax = *numSurroundFormats;
+ *numSurroundFormats = 0;
+ FormatVector formats;
+ if (reported) {
+ // Only get surround formats which are reported by device.
+ // First list already open outputs that can be routed to this device
+ audio_devices_t device = AUDIO_DEVICE_OUT_HDMI;
+ SortedVector<audio_io_handle_t> outputs;
+ bool reportedFormatFound = false;
+ status_t status;
+ sp<SwAudioOutputDescriptor> desc;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ desc = mOutputs.valueAt(i);
+ if (!desc->isDuplicated() && (desc->supportedDevices() & device)) {
+ outputs.add(mOutputs.keyAt(i));
+ }
+ }
+ // Open an output to query dynamic parameters.
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_HDMI);
+ for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
+ String8 address = hdmiOutputDevices[i]->mAddress;
+ for (const auto& hwModule : mHwModules) {
+ for (size_t i = 0; i < hwModule->getOutputProfiles().size(); i++) {
+ sp<IOProfile> profile = hwModule->getOutputProfiles()[i];
+ if (profile->supportDevice(AUDIO_DEVICE_OUT_HDMI) &&
+ profile->supportDeviceAddress(address)) {
+ size_t j;
+ for (j = 0; j < outputs.size(); j++) {
+ desc = mOutputs.valueFor(outputs.itemAt(j));
+ if (!desc->isDuplicated() && desc->mProfile == profile) {
+ break;
+ }
+ }
+ if (j != outputs.size()) {
+ status = getSupportedFormats(outputs.itemAt(j), formats);
+ reportedFormatFound |= (status == NO_ERROR);
+ continue;
+ }
+
+ if (!profile->canOpenNewIo()) {
+ ALOGW("Max Output number %u already opened for this profile %s",
+ profile->maxOpenCount, profile->getTagName().c_str());
+ continue;
+ }
+
+ ALOGV("opening output for device %08x with params %s profile %p name %s",
+ device, address.string(), profile.get(), profile->getName().string());
+ desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ status_t status = desc->open(nullptr, device, address,
+ AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE,
+ &output);
+
+ if (status == NO_ERROR) {
+ status = getSupportedFormats(output, formats);
+ reportedFormatFound |= (status == NO_ERROR);
+ desc->close();
+ output = AUDIO_IO_HANDLE_NONE;
+ }
+ }
+ }
+ }
+ }
+
+ if (!reportedFormatFound) {
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+ formats.add(SURROUND_FORMATS[i]);
+ }
+ }
+ for (size_t i = 0; i < formats.size(); i++) {
+ if (formatsWritten < formatsMax) {
+ surroundFormats[formatsWritten] = formats[i];
+ bool formatEnabled = false;
+ if (formats[i] == AUDIO_FORMAT_AAC_LC) {
+ for (size_t j = 0; j < ARRAY_SIZE(AAC_FORMATS); j++) {
+ formatEnabled =
+ mSurroundFormats.find(AAC_FORMATS[i]) != mSurroundFormats.end();
+ break;
+ }
+ } else {
+ formatEnabled = mSurroundFormats.find(formats[i]) != mSurroundFormats.end();
+ }
+ surroundFormatsEnabled[formatsWritten++] = formatEnabled;
+ }
+ (*numSurroundFormats)++;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled)
+{
+ // Check if audio format is a surround formats.
+ bool isSurroundFormat = false;
+ for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
+ if (audioFormat == SURROUND_FORMATS[i]) {
+ isSurroundFormat = true;
+ break;
+ }
+ }
+ if (!isSurroundFormat) {
+ return BAD_VALUE;
+ }
+
+ // Should only be called when MANUAL.
+ audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
+ AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
+ if (forceUse != AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
+ return INVALID_OPERATION;
+ }
+
+ if ((mSurroundFormats.find(audioFormat) != mSurroundFormats.end() && enabled)
+ || (mSurroundFormats.find(audioFormat) == mSurroundFormats.end() && !enabled)) {
+ return NO_ERROR;
+ }
+
+ // The operation is valid only when there is HDMI output available.
+ if ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_HDMI) == 0) {
+ return INVALID_OPERATION;
+ }
+
+ if (enabled) {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.insert(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.insert(audioFormat);
+ }
+ } else {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.erase(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.erase(audioFormat);
+ }
+ }
+
+ sp<SwAudioOutputDescriptor> outputDesc;
+ bool profileUpdated = false;
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+ AUDIO_DEVICE_OUT_HDMI);
+ for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
+ // Simulate reconnection to update enabled surround sound formats.
+ String8 address = hdmiOutputDevices[i]->mAddress;
+ String8 name = hdmiOutputDevices[i]->getName();
+ status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(),
+ name.c_str());
+ if (status != NO_ERROR) {
+ continue;
+ }
+ status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(),
+ name.c_str());
+ profileUpdated |= (status == NO_ERROR);
+ }
+ DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
+ AUDIO_DEVICE_IN_HDMI);
+ for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
+ // Simulate reconnection to update enabled surround sound formats.
+ String8 address = hdmiInputDevices[i]->mAddress;
+ String8 name = hdmiInputDevices[i]->getName();
+ status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.c_str(),
+ name.c_str());
+ if (status != NO_ERROR) {
+ continue;
+ }
+ status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(),
+ name.c_str());
+ profileUpdated |= (status == NO_ERROR);
+ }
+
+ // Undo the surround formats change due to no audio profiles updated.
+ if (!profileUpdated) {
+ if (enabled) {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.erase(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.erase(audioFormat);
+ }
+ } else {
+ if (audioFormat == AUDIO_FORMAT_AAC_LC) {
+ for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
+ mSurroundFormats.insert(AAC_FORMATS[i]);
+ }
+ } else {
+ mSurroundFormats.insert(audioFormat);
+ }
+ }
+ }
+
+ return profileUpdated ? NO_ERROR : INVALID_OPERATION;
+}
+
void AudioPolicyManager::setRecordSilenced(uid_t uid, bool silenced)
{
ALOGV("AudioPolicyManager:setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
@@ -3834,6 +4123,7 @@
mInputs.clear();
mHwModules.clear();
mHwModulesAll.clear();
+ mSurroundFormats.clear();
}
status_t AudioPolicyManager::initCheck()
@@ -5581,81 +5871,110 @@
AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
ALOGD("%s: forced use = %d", __FUNCTION__, forceUse);
- // Analyze original support for various formats.
- bool supportsAC3 = false;
- bool supportsOtherSurround = false;
- bool supportsIEC61937 = false;
- for (ssize_t formatIndex = 0; formatIndex < (ssize_t)formats.size(); formatIndex++) {
- audio_format_t format = formats[formatIndex];
- switch (format) {
- case AUDIO_FORMAT_AC3:
- supportsAC3 = true;
- break;
- case AUDIO_FORMAT_E_AC3:
- case AUDIO_FORMAT_DTS:
- case AUDIO_FORMAT_DTS_HD:
- // If ALWAYS, remove all other surround formats here since we will add them later.
- if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
- formats.removeAt(formatIndex);
- formatIndex--;
- }
- supportsOtherSurround = true;
- break;
- case AUDIO_FORMAT_IEC61937:
- supportsIEC61937 = true;
- break;
- default:
- break;
+ // If MANUAL, keep the supported surround sound formats as current enabled ones.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
+ formats.clear();
+ for (auto it = mSurroundFormats.begin(); it != mSurroundFormats.end(); it++) {
+ formats.add(*it);
}
- }
+ // Always enable IEC61937 when in MANUAL mode.
+ formats.add(AUDIO_FORMAT_IEC61937);
+ } else { // NEVER, AUTO or ALWAYS
+ // Analyze original support for various formats.
+ bool supportsAC3 = false;
+ bool supportsOtherSurround = false;
+ bool supportsIEC61937 = false;
+ mSurroundFormats.clear();
+ for (ssize_t formatIndex = 0; formatIndex < (ssize_t)formats.size(); formatIndex++) {
+ audio_format_t format = formats[formatIndex];
+ switch (format) {
+ case AUDIO_FORMAT_AC3:
+ supportsAC3 = true;
+ break;
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ // If ALWAYS, remove all other surround formats here
+ // since we will add them later.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+ formats.removeAt(formatIndex);
+ formatIndex--;
+ }
+ supportsOtherSurround = true;
+ break;
+ case AUDIO_FORMAT_IEC61937:
+ supportsIEC61937 = true;
+ break;
+ default:
+ break;
+ }
+ }
- // Modify formats based on surround preferences.
- // If NEVER, remove support for surround formats.
- if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
- if (supportsAC3 || supportsOtherSurround || supportsIEC61937) {
- // Remove surround sound related formats.
- for (size_t formatIndex = 0; formatIndex < formats.size(); ) {
+ // Modify formats based on surround preferences.
+ // If NEVER, remove support for surround formats.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
+ if (supportsAC3 || supportsOtherSurround || supportsIEC61937) {
+ // Remove surround sound related formats.
+ for (size_t formatIndex = 0; formatIndex < formats.size(); ) {
+ audio_format_t format = formats[formatIndex];
+ switch(format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ case AUDIO_FORMAT_IEC61937:
+ formats.removeAt(formatIndex);
+ break;
+ default:
+ formatIndex++; // keep it
+ break;
+ }
+ }
+ supportsAC3 = false;
+ supportsOtherSurround = false;
+ supportsIEC61937 = false;
+ }
+ } else { // AUTO or ALWAYS
+ // Most TVs support AC3 even if they do not report it in the EDID.
+ if ((alwaysForceAC3 || (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS))
+ && !supportsAC3) {
+ formats.add(AUDIO_FORMAT_AC3);
+ supportsAC3 = true;
+ }
+
+ // If ALWAYS, add support for raw surround formats if all are missing.
+ // This assumes that if any of these formats are reported by the HAL
+ // then the report is valid and should not be modified.
+ if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+ formats.add(AUDIO_FORMAT_E_AC3);
+ formats.add(AUDIO_FORMAT_DTS);
+ formats.add(AUDIO_FORMAT_DTS_HD);
+ supportsOtherSurround = true;
+ }
+
+ // Add support for IEC61937 if any raw surround supported.
+ // The HAL could do this but add it here, just in case.
+ if ((supportsAC3 || supportsOtherSurround) && !supportsIEC61937) {
+ formats.add(AUDIO_FORMAT_IEC61937);
+ supportsIEC61937 = true;
+ }
+
+ // Add reported surround sound formats to enabled surround formats.
+ for (size_t formatIndex = 0; formatIndex < formats.size(); formatIndex++) {
audio_format_t format = formats[formatIndex];
switch(format) {
case AUDIO_FORMAT_AC3:
case AUDIO_FORMAT_E_AC3:
case AUDIO_FORMAT_DTS:
case AUDIO_FORMAT_DTS_HD:
- case AUDIO_FORMAT_IEC61937:
- formats.removeAt(formatIndex);
- break;
+ case AUDIO_FORMAT_AAC_LC:
+ case AUDIO_FORMAT_DOLBY_TRUEHD:
+ case AUDIO_FORMAT_E_AC3_JOC:
+ mSurroundFormats.insert(format);
default:
- formatIndex++; // keep it
break;
}
}
- supportsAC3 = false;
- supportsOtherSurround = false;
- supportsIEC61937 = false;
- }
- } else { // AUTO or ALWAYS
- // Most TVs support AC3 even if they do not report it in the EDID.
- if ((alwaysForceAC3 || (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS))
- && !supportsAC3) {
- formats.add(AUDIO_FORMAT_AC3);
- supportsAC3 = true;
- }
-
- // If ALWAYS, add support for raw surround formats if all are missing.
- // This assumes that if any of these formats are reported by the HAL
- // then the report is valid and should not be modified.
- if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
- formats.add(AUDIO_FORMAT_E_AC3);
- formats.add(AUDIO_FORMAT_DTS);
- formats.add(AUDIO_FORMAT_DTS_HD);
- supportsOtherSurround = true;
- }
-
- // Add support for IEC61937 if any raw surround supported.
- // The HAL could do this but add it here, just in case.
- if ((supportsAC3 || supportsOtherSurround) && !supportsIEC61937) {
- formats.add(AUDIO_FORMAT_IEC61937);
- supportsIEC61937 = true;
}
}
}
@@ -5677,8 +5996,9 @@
maskIndex++;
}
}
- // If ALWAYS, then make sure we at least support 5.1
- } else if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) {
+ // If ALWAYS or MANUAL, then make sure we at least support 5.1
+ } else if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS
+ || forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) {
bool supports5dot1 = false;
// Are there any channel masks that can be considered "surround"?
for (audio_channel_mask_t channelMask : channelMasks) {
@@ -5705,7 +6025,7 @@
if (profiles.hasDynamicFormat()) {
reply = mpClientInterface->getParameters(
ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
- ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+ ALOGV("%s: supported formats %d, %s", __FUNCTION__, ioHandle, reply.string());
AudioParameter repliedParameters(reply);
if (repliedParameters.get(
String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {