From f129b03fa583d4cc26fd9c9171b8fb3b0ed8d4f4 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 7 Apr 2015 13:45:50 -0700 Subject: Enable 8 bit and float pcm record formats for AudioPolicyManager Add capability for handling different record channel masks. Change-Id: I63f6b029aca5cefff7adf26198a3b594a7ea2d71 --- .../common/managerdefinitions/include/AudioPort.h | 13 +++- .../common/managerdefinitions/include/IOProfile.h | 2 + .../common/managerdefinitions/src/AudioPort.cpp | 61 +++++++++++++---- .../common/managerdefinitions/src/IOProfile.cpp | 20 +++++- .../managerdefault/AudioPolicyManager.cpp | 76 ++++++++++++++-------- .../managerdefault/AudioPolicyManager.h | 6 +- 6 files changed, 130 insertions(+), 48 deletions(-) (limited to 'services') diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h index dea1b8a..1c2c27e 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h @@ -62,8 +62,12 @@ public: // searches for an exact match status_t checkExactChannelMask(audio_channel_mask_t channelMask) const; // searches for a compatible match, currently implemented for input channel masks only - status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask) const; - status_t checkFormat(audio_format_t format) const; + status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask, + audio_channel_mask_t *updatedChannelMask) const; + + status_t checkExactFormat(audio_format_t format) const; + // searches for a compatible match, currently implemented for input formats only + status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const; status_t checkGain(const struct audio_gain_config *gainConfig, int index) const; uint32_t pickSamplingRate() const; @@ -71,6 +75,11 @@ public: audio_format_t pickFormat() const; static const audio_format_t sPcmFormatCompareTable[]; + static int compareFormatsGoodToBad( + const audio_format_t *format1, const audio_format_t *format2) { + // compareFormats sorts from bad to good, we reverse it here + return compareFormats(*format2, *format1); + } static int compareFormats(audio_format_t format1, audio_format_t format2); audio_module_handle_t getModuleHandle() const; diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h index 022257e..ab6fcc1 100644 --- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h +++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h @@ -45,7 +45,9 @@ public: uint32_t samplingRate, uint32_t *updatedSamplingRate, audio_format_t format, + audio_format_t *updatedFormat, audio_channel_mask_t channelMask, + audio_channel_mask_t *updatedChannelMask, uint32_t flags) const; void dump(int fd); diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp index e8191dd..f3978ec 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "APM::AudioPort" //#define LOG_NDEBUG 0 - +#include #include "AudioPort.h" #include "HwModule.h" #include "AudioGain.h" @@ -216,6 +216,7 @@ void AudioPort::loadFormats(char *name) } str = strtok(NULL, "|"); } + mFormats.sort(compareFormatsGoodToBad); } void AudioPort::loadInChannels(char *name) @@ -358,6 +359,9 @@ status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate, uint32_t *updatedSamplingRate) const { if (mSamplingRates.isEmpty()) { + if (updatedSamplingRate != NULL) { + *updatedSamplingRate = samplingRate; + } return NO_ERROR; } @@ -387,16 +391,11 @@ status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate, } } } - // This uses hard-coded knowledge about AudioFlinger resampling ratios. - // TODO Move these assumptions out. - static const uint32_t kMaxDownSampleRatio = 6; // beyond this aliasing occurs - static const uint32_t kMaxUpSampleRatio = 256; // beyond this sample rate inaccuracies occur - // due to approximation by an int32_t of the - // phase increments + // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum. if (minAbove >= 0) { candidate = mSamplingRates[minAbove]; - if (candidate / kMaxDownSampleRatio <= samplingRate) { + if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) { if (updatedSamplingRate != NULL) { *updatedSamplingRate = candidate; } @@ -406,7 +405,7 @@ status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate, // But if we have to up-sample from a lower sampling rate, that's OK. if (maxBelow >= 0) { candidate = mSamplingRates[maxBelow]; - if (candidate * kMaxUpSampleRatio >= samplingRate) { + if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) { if (updatedSamplingRate != NULL) { *updatedSamplingRate = candidate; } @@ -431,10 +430,13 @@ status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) cons return BAD_VALUE; } -status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask) - const +status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask, + audio_channel_mask_t *updatedChannelMask) const { if (mChannelMasks.isEmpty()) { + if (updatedChannelMask != NULL) { + *updatedChannelMask = channelMask; + } return NO_ERROR; } @@ -443,6 +445,9 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask) // FIXME Does not handle multi-channel automatic conversions yet audio_channel_mask_t supported = mChannelMasks[i]; if (supported == channelMask) { + if (updatedChannelMask != NULL) { + *updatedChannelMask = channelMask; + } return NO_ERROR; } if (isRecordThread) { @@ -452,6 +457,9 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask) && channelMask == AUDIO_CHANNEL_IN_MONO) || (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK || channelMask == AUDIO_CHANNEL_IN_STEREO))) { + if (updatedChannelMask != NULL) { + *updatedChannelMask = supported; + } return NO_ERROR; } } @@ -459,7 +467,7 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask) return BAD_VALUE; } -status_t AudioPort::checkFormat(audio_format_t format) const +status_t AudioPort::checkExactFormat(audio_format_t format) const { if (mFormats.isEmpty()) { return NO_ERROR; @@ -473,6 +481,33 @@ status_t AudioPort::checkFormat(audio_format_t format) const return BAD_VALUE; } +status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) + const +{ + if (mFormats.isEmpty()) { + if (updatedFormat != NULL) { + *updatedFormat = format; + } + return NO_ERROR; + } + + const bool checkInexact = // when port is input and format is linear pcm + mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK + && audio_is_linear_pcm(format); + + for (size_t i = 0; i < mFormats.size(); ++i) { + if (mFormats[i] == format || + (checkInexact && audio_is_linear_pcm(mFormats[i]))) { + // for inexact checks we take the first linear pcm format since + // mFormats is sorted from best PCM format to worst PCM format. + if (updatedFormat != NULL) { + *updatedFormat = mFormats[i]; + } + return NO_ERROR; + } + } + return BAD_VALUE; +} uint32_t AudioPort::pickSamplingRate() const { @@ -756,7 +791,7 @@ status_t AudioPortConfig::applyAudioPortConfig( mChannelMask = config->channel_mask; } if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) { - status = audioport->checkFormat(config->format); + status = audioport->checkExactFormat(config->format); if (status != NO_ERROR) { goto exit; } diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp index de6539c..7b6d51d 100644 --- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp @@ -40,7 +40,9 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device, uint32_t samplingRate, uint32_t *updatedSamplingRate, audio_format_t format, + audio_format_t *updatedFormat, audio_channel_mask_t channelMask, + audio_channel_mask_t *updatedChannelMask, uint32_t flags) const { const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE; @@ -71,7 +73,14 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device, return false; } - if (!audio_is_valid_format(format) || checkFormat(format) != NO_ERROR) { + if (!audio_is_valid_format(format)) { + return false; + } + if (isPlaybackThread && checkExactFormat(format) != NO_ERROR) { + return false; + } + audio_format_t myUpdatedFormat = format; + if (isRecordThread && checkCompatibleFormat(format, &myUpdatedFormat) != NO_ERROR) { return false; } @@ -79,8 +88,9 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device, checkExactChannelMask(channelMask) != NO_ERROR)) { return false; } + audio_channel_mask_t myUpdatedChannelMask = channelMask; if (isRecordThread && (!audio_is_input_channel(channelMask) || - checkCompatibleChannelMask(channelMask) != NO_ERROR)) { + checkCompatibleChannelMask(channelMask, &myUpdatedChannelMask) != NO_ERROR)) { return false; } @@ -99,6 +109,12 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device, if (updatedSamplingRate != NULL) { *updatedSamplingRate = myUpdatedSamplingRate; } + if (updatedFormat != NULL) { + *updatedFormat = myUpdatedFormat; + } + if (updatedChannelMask != NULL) { + *updatedChannelMask = myUpdatedChannelMask; + } return true; } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 35e80f7..ba9f996 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -585,8 +585,10 @@ sp AudioPolicyManager::getProfileForDirectOutput( } for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { sp profile = mHwModules[i]->mOutputProfiles[j]; - bool found = profile->isCompatibleProfile(device, String8(""), samplingRate, - NULL /*updatedSamplingRate*/, format, channelMask, + bool found = profile->isCompatibleProfile(device, String8(""), + samplingRate, NULL /*updatedSamplingRate*/, + format, NULL /*updatedFormat*/, + channelMask, NULL /*updatedChannelMask*/, flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT); if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) { @@ -1303,20 +1305,25 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, } } - sp profile = getInputProfile(device, address, - samplingRate, format, channelMask, - flags); - if (profile == 0) { - //retry without flags - audio_input_flags_t log_flags = flags; - flags = AUDIO_INPUT_FLAG_NONE; + // find a compatible input profile (not necessarily identical in parameters) + sp profile; + // samplingRate and flags may be updated by getInputProfile + uint32_t profileSamplingRate = samplingRate; + audio_format_t profileFormat = format; + audio_channel_mask_t profileChannelMask = channelMask; + audio_input_flags_t profileFlags = flags; + for (;;) { profile = getInputProfile(device, address, - samplingRate, format, channelMask, - flags); - if (profile == 0) { + profileSamplingRate, profileFormat, profileChannelMask, + profileFlags); + if (profile != 0) { + break; // success + } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) { + profileFlags = AUDIO_INPUT_FLAG_NONE; // retry + } else { // fail ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u," "format %#x, channelMask 0x%X, flags %#x", - device, samplingRate, format, channelMask, log_flags); + device, samplingRate, format, channelMask, flags); return BAD_VALUE; } } @@ -1327,9 +1334,9 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, } audio_config_t config = AUDIO_CONFIG_INITIALIZER; - config.sample_rate = samplingRate; - config.channel_mask = channelMask; - config.format = format; + config.sample_rate = profileSamplingRate; + config.channel_mask = profileChannelMask; + config.format = profileFormat; status_t status = mpClientInterface->openInput(profile->getModuleHandle(), input, @@ -1337,14 +1344,15 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, &device, address, halInputSource, - flags); + profileFlags); // only accept input with the exact requested set of parameters if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE || - (samplingRate != config.sample_rate) || - (format != config.format) || - (channelMask != config.channel_mask)) { - ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d, channelMask %x", + (profileSamplingRate != config.sample_rate) || + (profileFormat != config.format) || + (profileChannelMask != config.channel_mask)) { + ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d," + " channelMask %x", samplingRate, format, channelMask); if (*input != AUDIO_IO_HANDLE_NONE) { mpClientInterface->closeInput(*input); @@ -1356,9 +1364,9 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, inputDesc->mInputSource = inputSource; inputDesc->mRefCount = 0; inputDesc->mOpenRefCount = 1; - inputDesc->mSamplingRate = samplingRate; - inputDesc->mFormat = format; - inputDesc->mChannelMask = channelMask; + inputDesc->mSamplingRate = profileSamplingRate; + inputDesc->mFormat = profileFormat; + inputDesc->mChannelMask = profileChannelMask; inputDesc->mDevice = device; inputDesc->mSessions.add(session); inputDesc->mIsSoundTrigger = isSoundTrigger; @@ -2122,9 +2130,12 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, patch->sources[0].sample_rate, NULL, // updatedSamplingRate patch->sources[0].format, + NULL, // updatedFormat patch->sources[0].channel_mask, + NULL, // updatedChannelMask AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) { - ALOGV("createAudioPatch() profile not supported for device %08x", devDesc->type()); + ALOGV("createAudioPatch() profile not supported for device %08x", + devDesc->type()); return INVALID_OPERATION; } devices.add(devDesc); @@ -2176,7 +2187,9 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch, patch->sinks[0].sample_rate, NULL, /*updatedSampleRate*/ patch->sinks[0].format, + NULL, /*updatedFormat*/ patch->sinks[0].channel_mask, + NULL, /*updatedChannelMask*/ // FIXME for the parameter type, // and the NONE (audio_output_flags_t) @@ -4201,12 +4214,15 @@ status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input, sp AudioPolicyManager::getInputProfile(audio_devices_t device, String8 address, uint32_t& samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, + audio_format_t& format, + audio_channel_mask_t& channelMask, audio_input_flags_t flags) { // Choose an input profile based on the requested capture parameters: select the first available // profile supporting all requested parameters. + // + // TODO: perhaps isCompatibleProfile should return a "matching" score so we can return + // the best matching profile, not the first one. for (size_t i = 0; i < mHwModules.size(); i++) { @@ -4219,7 +4235,11 @@ sp AudioPolicyManager::getInputProfile(audio_devices_t device, // profile->log(); if (profile->isCompatibleProfile(device, address, samplingRate, &samplingRate /*updatedSamplingRate*/, - format, channelMask, (audio_output_flags_t) flags)) { + format, + &format /*updatedFormat*/, + channelMask, + &channelMask /*updatedChannelMask*/, + (audio_output_flags_t) flags)) { return profile; } diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index 11fd5ff..fe6b986 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -470,12 +470,12 @@ protected: audio_io_handle_t selectOutput(const SortedVector& outputs, audio_output_flags_t flags, audio_format_t format); - // samplingRate parameter is an in/out and so may be modified + // samplingRate, format, channelMask are in/out and so may be modified sp getInputProfile(audio_devices_t device, String8 address, uint32_t& samplingRate, - audio_format_t format, - audio_channel_mask_t channelMask, + audio_format_t& format, + audio_channel_mask_t& channelMask, audio_input_flags_t flags); sp getProfileForDirectOutput(audio_devices_t device, uint32_t samplingRate, -- cgit v1.1