summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2014-07-09 15:03:28 -0700
committerEric Laurent <elaurent@google.com>2014-07-11 15:06:09 -0700
commit1e693b55d888b9d3e0a2ce770ae2b72b59c1a317 (patch)
tree1f5cf885a43a9f79a6c698cbd286ce4dbf27ee8b /services
parent2db91ae0e6aa33b50cc924ad65d6dc01876d220f (diff)
downloadframeworks_av-1e693b55d888b9d3e0a2ce770ae2b72b59c1a317.zip
frameworks_av-1e693b55d888b9d3e0a2ce770ae2b72b59c1a317.tar.gz
frameworks_av-1e693b55d888b9d3e0a2ce770ae2b72b59c1a317.tar.bz2
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
Diffstat (limited to 'services')
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp182
-rw-r--r--services/audiopolicy/AudioPolicyManager.h21
-rwxr-xr-xservices/audiopolicy/AudioPolicyService.cpp4
3 files changed, 176 insertions, 31 deletions
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index e2b34ee..1b4796b 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 sp<IOProfil
{
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);
}
- } 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<HwModule>& 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<HwModule>& 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 c23d994..4caecca 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 <audio_format_t> mFormats; // supported audio formats
Vector < sp<AudioGain> > mGains; // gain controllers
sp<HwModule> 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 9435797..ae9cc35 100755
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -841,8 +841,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& 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);
}