diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 39ee437044..c072901a40 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -1286,6 +1286,24 @@ status_t AudioSystem::getMicrophones(std::vector *microph return af->getMicrophones(microphones); } +status_t AudioSystem::getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->getSurroundFormats( + numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported); +} + +status_t AudioSystem::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->setSurroundFormatEnabled(audioFormat, enabled); +} + // --------------------------------------------------------------------------- int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback( diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index eca6fee728..a1236e7389 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -80,7 +80,9 @@ enum { SET_AUDIO_PORT_CALLBACK_ENABLED, SET_MASTER_MONO, GET_MASTER_MONO, - GET_STREAM_VOLUME_DB + GET_STREAM_VOLUME_DB, + GET_SURROUND_FORMATS, + SET_SURROUND_FORMAT_ENABLED }; #define MAX_ITEMS_PER_LIST 1024 @@ -829,6 +831,54 @@ public: } return reply.readFloat(); } + + virtual status_t getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported) + { + if (numSurroundFormats == NULL || (*numSurroundFormats != 0 && + (surroundFormats == NULL || surroundFormatsEnabled == NULL))) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + unsigned int numSurroundFormatsReq = *numSurroundFormats; + data.writeUint32(numSurroundFormatsReq); + data.writeBool(reported); + status_t status = remote()->transact(GET_SURROUND_FORMATS, data, &reply); + if (status == NO_ERROR && (status = (status_t)reply.readInt32()) == NO_ERROR) { + *numSurroundFormats = reply.readUint32(); + } + if (status == NO_ERROR) { + if (numSurroundFormatsReq > *numSurroundFormats) { + numSurroundFormatsReq = *numSurroundFormats; + } + if (numSurroundFormatsReq > 0) { + status = reply.read(surroundFormats, + numSurroundFormatsReq * sizeof(audio_format_t)); + if (status != NO_ERROR) { + return status; + } + status = reply.read(surroundFormatsEnabled, + numSurroundFormatsReq * sizeof(bool)); + } + } + return status; + } + + virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(audioFormat); + data.writeBool(enabled); + status_t status = remote()->transact(SET_SURROUND_FORMAT_ENABLED, data, &reply); + if (status != NO_ERROR) { + return status; + } + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -883,7 +933,9 @@ status_t BnAudioPolicyService::onTransact( case REGISTER_POLICY_MIXES: case SET_MASTER_MONO: case START_AUDIO_SOURCE: - case STOP_AUDIO_SOURCE: { + case STOP_AUDIO_SOURCE: + case GET_SURROUND_FORMATS: + case SET_SURROUND_FORMAT_ENABLED: { if (multiuser_get_app_id(IPCThreadState::self()->getCallingUid()) >= AID_APP_START) { ALOGW("%s: transaction %d received from PID %d unauthorized UID %d", __func__, code, IPCThreadState::self()->getCallingPid(), @@ -1489,6 +1541,50 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } + case GET_SURROUND_FORMATS: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + unsigned int numSurroundFormatsReq = data.readUint32(); + if (numSurroundFormatsReq > MAX_ITEMS_PER_LIST) { + numSurroundFormatsReq = MAX_ITEMS_PER_LIST; + } + bool reported = data.readBool(); + unsigned int numSurroundFormats = numSurroundFormatsReq; + audio_format_t *surroundFormats = (audio_format_t *)calloc( + numSurroundFormats, sizeof(audio_format_t)); + bool *surroundFormatsEnabled = (bool *)calloc(numSurroundFormats, sizeof(bool)); + if (numSurroundFormatsReq > 0 && + (surroundFormats == NULL || surroundFormatsEnabled == NULL)) { + free(surroundFormats); + free(surroundFormatsEnabled); + reply->writeInt32(NO_MEMORY); + return NO_ERROR; + } + status_t status = getSurroundFormats( + &numSurroundFormats, surroundFormats, surroundFormatsEnabled, reported); + reply->writeInt32(status); + + if (status == NO_ERROR) { + reply->writeUint32(numSurroundFormats); + if (numSurroundFormatsReq > numSurroundFormats) { + numSurroundFormatsReq = numSurroundFormats; + } + reply->write(surroundFormats, numSurroundFormatsReq * sizeof(audio_format_t)); + reply->write(surroundFormatsEnabled, numSurroundFormatsReq * sizeof(bool)); + } + free(surroundFormats); + free(surroundFormatsEnabled); + return NO_ERROR; + } + + case SET_SURROUND_FORMAT_ENABLED: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + audio_format_t audioFormat = (audio_format_t) data.readInt32(); + bool enabled = data.readBool(); + status_t status = setSurroundFormatEnabled(audioFormat, enabled); + reply->writeInt32(status); + return NO_ERROR; + } + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index 0c4d6ee9a8..4c0f796f5e 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -340,6 +340,15 @@ public: static status_t getMicrophones(std::vector *microphones); + // numSurroundFormats holds the maximum number of formats and bool value allowed in the array. + // When numSurroundFormats is 0, surroundFormats and surroundFormatsEnabled will not be + // populated. The actual number of surround formats should be returned at numSurroundFormats. + static status_t getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported); + static status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled); + // ---------------------------------------------------------------------------- class AudioPortCallback : public RefBase diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h index 1114eeb785..c3876afc40 100644 --- a/media/libaudioclient/include/media/IAudioPolicyService.h +++ b/media/libaudioclient/include/media/IAudioPolicyService.h @@ -166,6 +166,12 @@ public: virtual status_t getMasterMono(bool *mono) = 0; virtual float getStreamVolumeDB( audio_stream_type_t stream, int index, audio_devices_t device) = 0; + + virtual status_t getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported) = 0; + virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) = 0; }; diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 923c0914ac..4812b1fe7d 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -245,6 +245,12 @@ public: virtual float getStreamVolumeDB( audio_stream_type_t stream, int index, audio_devices_t device) = 0; + virtual status_t getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported) = 0; + virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) = 0; + virtual void setRecordSilenced(uid_t uid, bool silenced); }; diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index 83aec3bacf..23c020d796 100644 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -148,7 +148,8 @@ status_t Engine::setForceUse(audio_policy_force_use_t usage, audio_policy_forced case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND: if (config != AUDIO_POLICY_FORCE_NONE && config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER && - config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS) { + config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS && + config != AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL) { ALOGW("setForceUse() invalid config %d for ENCODED_SURROUND", config); return BAD_VALUE; } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 7931176f46..ee16e07126 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -60,6 +60,26 @@ namespace android { // 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 @@ float AudioPolicyManager::getStreamVolumeDB( 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 outputs; + bool reportedFormatFound = false; + status_t status; + sp 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 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 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 @@ AudioPolicyManager::~AudioPolicyManager() mInputs.clear(); mHwModules.clear(); mHwModulesAll.clear(); + mSurroundFormats.clear(); } status_t AudioPolicyManager::initCheck() @@ -5590,81 +5880,110 @@ void AudioPolicyManager::filterSurroundFormats(FormatVector *formatsPtr) { 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--; + // 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(); ) { + 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; - break; - case AUDIO_FORMAT_IEC61937: + } + + // 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; - 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(); ) { + // 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; } } } @@ -5686,8 +6005,9 @@ void AudioPolicyManager::filterSurroundChannelMasks(ChannelsVector *channelMasks 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) { @@ -5714,7 +6034,7 @@ void AudioPolicyManager::updateAudioProfiles(audio_devices_t device, 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) { diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 0df52dac9e..b954714fad 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -237,6 +238,12 @@ public: virtual float getStreamVolumeDB( audio_stream_type_t stream, int index, audio_devices_t device); + virtual status_t getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported); + virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled); + // return the strategy corresponding to a given stream type routing_strategy getStrategy(audio_stream_type_t stream) const; @@ -596,11 +603,16 @@ protected: // Audio Policy Engine Interface. AudioPolicyManagerInterface *mEngine; + + // Surround formats that are enabled. + std::unordered_set mSurroundFormats; private: // Add or remove AC3 DTS encodings based on user preferences. void filterSurroundFormats(FormatVector *formatsPtr); void filterSurroundChannelMasks(ChannelsVector *channelMasksPtr); + status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats); + // If any, resolve any "dynamic" fields of an Audio Profiles collection void updateAudioProfiles(audio_devices_t device, audio_io_handle_t ioHandle, AudioProfileVector &profiles); diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index f6d407fd07..9592b6acdc 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -986,5 +986,28 @@ float AudioPolicyService::getStreamVolumeDB( return mAudioPolicyManager->getStreamVolumeDB(stream, index, device); } +status_t AudioPolicyService::getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + Mutex::Autolock _l(mLock); + AutoCallerClear acc; + return mAudioPolicyManager->getSurroundFormats(numSurroundFormats, surroundFormats, + surroundFormatsEnabled, reported); +} + +status_t AudioPolicyService::setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + Mutex::Autolock _l(mLock); + AutoCallerClear acc; + return mAudioPolicyManager->setSurroundFormatEnabled(audioFormat, enabled); +} } // namespace android diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index d8dd797277..3e179c088d 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -203,6 +203,12 @@ public: virtual float getStreamVolumeDB( audio_stream_type_t stream, int index, audio_devices_t device); + virtual status_t getSurroundFormats(unsigned int *numSurroundFormats, + audio_format_t *surroundFormats, + bool *surroundFormatsEnabled, + bool reported); + virtual status_t setSurroundFormatEnabled(audio_format_t audioFormat, bool enabled); + status_t doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, audio_session_t session);