From 1e693b55d888b9d3e0a2ce770ae2b72b59c1a317 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 9 Jul 2014 15:03:28 -0700 Subject: [PATCH] audio policy: add rules to select audio parameters Added rules to select most appropriate sampling rate, format and channel mask from an input or output profile. Moved mFlags from IOProfile to its base class AudioPort. Removed bogus mChannelMask member in DeviceDescriptor class. Improveed dump of dynamic parameters in AudioPort. Change-Id: Ic09d320386002a8bafee4a28db00b1001a386678 --- services/audiopolicy/AudioPolicyManager.cpp | 182 ++++++++++++++++++++++++---- services/audiopolicy/AudioPolicyManager.h | 21 +++- services/audiopolicy/AudioPolicyService.cpp | 4 +- 3 files changed, 176 insertions(+), 31 deletions(-) diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index e2b34ee3ee..1b4796b142 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -2711,10 +2711,15 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, ALOGW("checkOutputsForDevice() direct output missing param"); mpClientInterface->closeOutput(output); output = 0; - } else if (profile->mSamplingRates[0] == 0) { + } else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 || + profile->mChannelMasks[0] == 0) { mpClientInterface->closeOutput(output); - desc->mSamplingRate = profile->mSamplingRates[1]; + desc->mSamplingRate = profile->pickSamplingRate(); + desc->mFormat = profile->pickFormat(); + desc->mChannelMask = profile->pickChannelMask(); offloadInfo.sample_rate = desc->mSamplingRate; + offloadInfo.format = desc->mFormat; + offloadInfo.channel_mask = desc->mChannelMask; output = mpClientInterface->openOutput( profile->mModule->mHandle, &desc->mDevice, @@ -4500,9 +4505,9 @@ AudioPolicyManager::AudioOutputDescriptor::AudioOutputDescriptor( } if (profile != NULL) { mAudioPort = profile; - mSamplingRate = profile->mSamplingRates[0]; - mFormat = profile->mFormats[0]; - mChannelMask = profile->mChannelMasks[0]; + mSamplingRate = profile->pickSamplingRate(); + mFormat = profile->pickFormat(); + mChannelMask = profile->pickChannelMask(); if (profile->mGains.size() > 0) { profile->mGains[0]->getDefaultConfig(&mGain); } @@ -4681,16 +4686,12 @@ AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const spmSamplingRates[0]; - mFormat = profile->mFormats[0]; - mChannelMask = profile->mChannelMasks[0]; + mSamplingRate = profile->pickSamplingRate(); + mFormat = profile->pickFormat(); + mChannelMask = profile->pickChannelMask(); if (profile->mGains.size() > 0) { profile->mGains[0]->getDefaultConfig(&mGain); } - } else { - mSamplingRate = 0; - mFormat = AUDIO_FORMAT_DEFAULT; - mChannelMask = 0; } } @@ -5006,7 +5007,7 @@ void AudioPolicyManager::HwModule::dump(int fd) AudioPolicyManager::AudioPort::AudioPort(const String8& name, audio_port_type_t type, audio_port_role_t role, const sp& module) : - mName(name), mType(type), mRole(role), mModule(module) + mName(name), mType(type), mRole(role), mModule(module), mFlags((audio_output_flags_t)0) { mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) || ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK)); @@ -5234,6 +5235,127 @@ status_t AudioPolicyManager::AudioPort::checkFormat(audio_format_t format) const return BAD_VALUE; } + +uint32_t AudioPolicyManager::AudioPort::pickSamplingRate() const +{ + // special case for uninitialized dynamic profile + if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) { + return 0; + } + + uint32_t samplingRate = 0; + uint32_t maxRate = MAX_MIXER_SAMPLING_RATE; + + // For mixed output and inputs, use max mixer sampling rates. Do not + // limit sampling rate otherwise + if ((mType != AUDIO_PORT_TYPE_MIX) || + ((mRole == AUDIO_PORT_ROLE_SOURCE) && + (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)))) { + maxRate = UINT_MAX; + } + for (size_t i = 0; i < mSamplingRates.size(); i ++) { + if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) { + samplingRate = mSamplingRates[i]; + } + } + return samplingRate; +} + +audio_channel_mask_t AudioPolicyManager::AudioPort::pickChannelMask() const +{ + // special case for uninitialized dynamic profile + if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) { + return AUDIO_CHANNEL_NONE; + } + + audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE; + uint32_t channelCount = 0; + uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT; + + // For mixed output and inputs, use max mixer channel count. Do not + // limit channel count otherwise + if ((mType != AUDIO_PORT_TYPE_MIX) || + ((mRole == AUDIO_PORT_ROLE_SOURCE) && + (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)))) { + maxCount = UINT_MAX; + } + for (size_t i = 0; i < mChannelMasks.size(); i ++) { + uint32_t cnlCount; + if (mUseInChannelMask) { + cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]); + } else { + cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]); + } + if ((cnlCount > channelCount) && (cnlCount <= maxCount)) { + channelMask = mChannelMasks[i]; + } + } + return channelMask; +} + +const audio_format_t AudioPolicyManager::AudioPort::sPcmFormatCompareTable[] = { + AUDIO_FORMAT_DEFAULT, + AUDIO_FORMAT_PCM_16_BIT, + AUDIO_FORMAT_PCM_24_BIT_PACKED, +}; + +int AudioPolicyManager::AudioPort::compareFormats(audio_format_t format1, + audio_format_t format2) +{ + // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any + // compressed format and better than any PCM format. This is by design of pickFormat() + if (!audio_is_linear_pcm(format1)) { + if (!audio_is_linear_pcm(format2)) { + return 0; + } + return 1; + } + if (!audio_is_linear_pcm(format2)) { + return -1; + } + + int index1 = -1, index2 = -1; + for (size_t i = 0; + (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1)); + i ++) { + if (sPcmFormatCompareTable[i] == format1) { + index1 = i; + } + if (sPcmFormatCompareTable[i] == format2) { + index2 = i; + } + } + // format1 not found => index1 < 0 => format2 > format1 + // format2 not found => index2 < 0 => format2 < format1 + return index1 - index2; +} + +audio_format_t AudioPolicyManager::AudioPort::pickFormat() const +{ + // special case for uninitialized dynamic profile + if (mFormats.size() == 1 && mFormats[0] == 0) { + return AUDIO_FORMAT_DEFAULT; + } + + audio_format_t format = AUDIO_FORMAT_DEFAULT; + audio_format_t bestFormat = BEST_MIXER_FORMAT; + // For mixed output and inputs, use best mixer output format. Do not + // limit format otherwise + if ((mType != AUDIO_PORT_TYPE_MIX) || + ((mRole == AUDIO_PORT_ROLE_SOURCE) && + (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) == 0)))) { + bestFormat = AUDIO_FORMAT_INVALID; + } + + for (size_t i = 0; i < mFormats.size(); i ++) { + if ((compareFormats(mFormats[i], format) > 0) && + (compareFormats(mFormats[i], bestFormat) <= 0)) { + format = mFormats[i]; + } + } + return format; +} + status_t AudioPolicyManager::AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const { @@ -5258,7 +5380,11 @@ void AudioPolicyManager::AudioPort::dump(int fd, int spaces) const snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, ""); result.append(buffer); for (size_t i = 0; i < mSamplingRates.size(); i++) { - snprintf(buffer, SIZE, "%d", mSamplingRates[i]); + if (i == 0 && mSamplingRates[i] == 0) { + snprintf(buffer, SIZE, "Dynamic"); + } else { + snprintf(buffer, SIZE, "%d", mSamplingRates[i]); + } result.append(buffer); result.append(i == (mSamplingRates.size() - 1) ? "" : ", "); } @@ -5269,7 +5395,13 @@ void AudioPolicyManager::AudioPort::dump(int fd, int spaces) const snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, ""); result.append(buffer); for (size_t i = 0; i < mChannelMasks.size(); i++) { - snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]); + ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]); + + if (i == 0 && mChannelMasks[i] == 0) { + snprintf(buffer, SIZE, "Dynamic"); + } else { + snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]); + } result.append(buffer); result.append(i == (mChannelMasks.size() - 1) ? "" : ", "); } @@ -5280,9 +5412,14 @@ void AudioPolicyManager::AudioPort::dump(int fd, int spaces) const snprintf(buffer, SIZE, "%*s- formats: ", spaces, ""); result.append(buffer); for (size_t i = 0; i < mFormats.size(); i++) { - snprintf(buffer, SIZE, "%-48s", enumToString(sFormatNameToEnumTable, - ARRAY_SIZE(sFormatNameToEnumTable), - mFormats[i])); + const char *formatStr = enumToString(sFormatNameToEnumTable, + ARRAY_SIZE(sFormatNameToEnumTable), + mFormats[i]); + if (i == 0 && strcmp(formatStr, "") == 0) { + snprintf(buffer, SIZE, "Dynamic"); + } else { + snprintf(buffer, SIZE, "%-48s", formatStr); + } result.append(buffer); result.append(i == (mFormats.size() - 1) ? "" : ", "); } @@ -5505,7 +5642,7 @@ void AudioPolicyManager::AudioPortConfig::toAudioPortConfig( AudioPolicyManager::IOProfile::IOProfile(const String8& name, audio_port_role_t role, const sp& module) - : AudioPort(name, AUDIO_PORT_TYPE_MIX, role, module), mFlags((audio_output_flags_t)0) + : AudioPort(name, AUDIO_PORT_TYPE_MIX, role, module) { } @@ -5596,8 +5733,7 @@ AudioPolicyManager::DeviceDescriptor::DeviceDescriptor(const String8& name, audi audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE, NULL), - mDeviceType(type), mAddress(""), - mChannelMask(AUDIO_CHANNEL_NONE), mId(0) + mDeviceType(type), mAddress(""), mId(0) { mAudioPort = this; if (mGains.size() > 0) { @@ -5817,10 +5953,6 @@ status_t AudioPolicyManager::DeviceDescriptor::dump(int fd, int spaces, int inde snprintf(buffer, SIZE, "%*s- address: %-32s\n", spaces, "", mAddress.string()); result.append(buffer); } - if (mChannelMask != AUDIO_CHANNEL_NONE) { - snprintf(buffer, SIZE, "%*s- channel mask: %08x\n", spaces, "", mChannelMask); - result.append(buffer); - } write(fd, result.string(), result.size()); AudioPort::dump(fd, spaces); diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index c23d994614..4caeccaadd 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -52,6 +52,12 @@ namespace android { // Can be overridden by the audio.offload.min.duration.secs property #define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60 +#define MAX_MIXER_SAMPLING_RATE 48000 +#define MAX_MIXER_CHANNEL_COUNT 2 +// See AudioPort::compareFormats() +#define WORST_MIXER_FORMAT AUDIO_FORMAT_PCM_16_BIT +#define BEST_MIXER_FORMAT AUDIO_FORMAT_PCM_24_BIT_PACKED + // ---------------------------------------------------------------------------- // AudioPolicyManager implements audio policy manager behavior common to all platforms. // ---------------------------------------------------------------------------- @@ -238,6 +244,13 @@ protected: status_t checkFormat(audio_format_t format) const; status_t checkGain(const struct audio_gain_config *gainConfig, int index) const; + uint32_t pickSamplingRate() const; + audio_channel_mask_t pickChannelMask() const; + audio_format_t pickFormat() const; + + static const audio_format_t sPcmFormatCompareTable[]; + static int compareFormats(audio_format_t format1, audio_format_t format2); + void dump(int fd, int spaces) const; String8 mName; @@ -252,6 +265,8 @@ protected: Vector mFormats; // supported audio formats Vector < sp > mGains; // gain controllers sp mModule; // audio HW module exposing this I/O stream + audio_output_flags_t mFlags; // attribute flags (e.g primary output, + // direct output...). For outputs only. }; class AudioPortConfig: public virtual RefBase @@ -302,7 +317,6 @@ protected: audio_devices_t mDeviceType; String8 mAddress; - audio_channel_mask_t mChannelMask; audio_port_handle_t mId; }; @@ -352,11 +366,10 @@ protected: DeviceVector mSupportedDevices; // supported devices // (devices this output can be routed to) - audio_output_flags_t mFlags; // attribute flags (e.g primary output, - // direct output...). For outputs only. }; - class HwModule : public RefBase{ + class HwModule : public RefBase + { public: HwModule(const char *name); ~HwModule(); diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp index 943579794d..ae9cc3588e 100755 --- a/services/audiopolicy/AudioPolicyService.cpp +++ b/services/audiopolicy/AudioPolicyService.cpp @@ -841,8 +841,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(sp& c } // insert command at the right place according to its time stamp - ALOGV("inserting command: %d at index %d, num commands %d", - command->mCommand, (int)i+1, mAudioCommands.size()); + ALOGV("inserting command: %d at index %zd, num commands %zu", + command->mCommand, i+1, mAudioCommands.size()); mAudioCommands.insertAt(command, i + 1); } -- 2.11.0