summaryrefslogtreecommitdiffstats
path: root/services/audiopolicy
diff options
context:
space:
mode:
Diffstat (limited to 'services/audiopolicy')
-rw-r--r--services/audiopolicy/AudioPolicyInterface.h5
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/AudioPort.h6
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h14
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp113
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp3
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.cpp34
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.h21
-rw-r--r--services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp31
-rw-r--r--services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp12
-rw-r--r--services/audiopolicy/service/AudioPolicyService.h5
10 files changed, 204 insertions, 40 deletions
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 4fa472e..58c65fa 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -218,6 +218,11 @@ public:
virtual status_t registerPolicyMixes(Vector<AudioMix> mixes) = 0;
virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes) = 0;
+
+ virtual status_t startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle) = 0;
+ virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 1c2c27e..82e2c43 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -75,10 +75,8 @@ 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(const audio_format_t *format1, const audio_format_t *format2) {
+ return compareFormats(*format1, *format2);
}
static int compareFormats(audio_format_t format1, audio_format_t format2);
diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index f8c4d08..0b08430 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -38,7 +38,8 @@ struct StringToEnum {
uint32_t value;
};
-#define STRING_TO_ENUM(string) { #string, string }
+// TODO: move to a separate file. Should be in sync with audio.h.
+#define STRING_TO_ENUM(string) { #string, (uint32_t)string } // uint32_t cast removes warning
#define NAME_TO_ENUM(name, value) { name, value }
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -204,6 +205,17 @@ const StringToEnum sInChannelsNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
};
+const StringToEnum sIndexChannelsNameToEnumTable[] = {
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
+ STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
+};
+
const StringToEnum sGainModeNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_GAIN_MODE_JOINT),
STRING_TO_ENUM(AUDIO_GAIN_MODE_CHANNELS),
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index f3978ec..64f883a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -146,7 +146,7 @@ void AudioPort::importAudioPort(const sp<AudioPort> port) {
break;
}
}
- if (!hasFormat) { // never import a channel mask twice
+ if (!hasFormat) { // never import a format twice
mFormats.add(format);
}
}
@@ -216,7 +216,12 @@ void AudioPort::loadFormats(char *name)
}
str = strtok(NULL, "|");
}
- mFormats.sort(compareFormatsGoodToBad);
+ // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+ // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
+ // [](const audio_format_t *format1, const audio_format_t *format2) {
+ // return compareFormats(*format1, *format2);
+ // }
+ mFormats.sort(compareFormats);
}
void AudioPort::loadInChannels(char *name)
@@ -235,8 +240,14 @@ void AudioPort::loadInChannels(char *name)
(audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
ARRAY_SIZE(sInChannelsNameToEnumTable),
str);
+ if (channelMask == 0) { // if not found, check the channel index table
+ channelMask = (audio_channel_mask_t)
+ ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable,
+ ARRAY_SIZE(sIndexChannelsNameToEnumTable),
+ str);
+ }
if (channelMask != 0) {
- ALOGV("loadInChannels() adding channelMask %04x", channelMask);
+ ALOGV("loadInChannels() adding channelMask %#x", channelMask);
mChannelMasks.add(channelMask);
}
str = strtok(NULL, "|");
@@ -441,30 +452,87 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
}
const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+ const bool isIndex = audio_channel_mask_get_representation(channelMask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+ int bestMatch = 0;
for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- // FIXME Does not handle multi-channel automatic conversions yet
audio_channel_mask_t supported = mChannelMasks[i];
if (supported == channelMask) {
+ // Exact matches always taken.
if (updatedChannelMask != NULL) {
*updatedChannelMask = channelMask;
}
return NO_ERROR;
}
- if (isRecordThread) {
- // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix.
- // FIXME Abstract this out to a table.
- if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO)
- && channelMask == AUDIO_CHANNEL_IN_MONO) ||
- (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
- || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
+
+ // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+ if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+ // Approximate (best) match:
+ // The match score measures how well the supported channel mask matches the
+ // desired mask, where increasing-is-better.
+ //
+ // TODO: Some tweaks may be needed.
+ // Should be a static function of the data processing library.
+ //
+ // In priority:
+ // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+ // OR
+ // match score += 100 if the channel mask representations match
+ // match score += number of channels matched.
+ //
+ // If there are no matched channels, the mask may still be accepted
+ // but the playback or record will be silent.
+ const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+ int match;
+ if (isIndex && isSupportedIndex) {
+ // index equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ } else if (isIndex && !isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
+ match = __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask) & equivalentBits);
+ } else if (!isIndex && isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
+ match = __builtin_popcount(
+ equivalentBits & audio_channel_mask_get_bits(supported));
+ } else {
+ // positional equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ switch (supported) {
+ case AUDIO_CHANNEL_IN_FRONT_BACK:
+ case AUDIO_CHANNEL_IN_STEREO:
+ if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+ match = 1000;
+ }
+ break;
+ case AUDIO_CHANNEL_IN_MONO:
+ if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+ || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+ match = 1000;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (match > bestMatch) {
+ bestMatch = match;
if (updatedChannelMask != NULL) {
*updatedChannelMask = supported;
+ } else {
+ return NO_ERROR; // any match will do in this case.
}
- return NO_ERROR;
}
}
}
- return BAD_VALUE;
+ return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
}
status_t AudioPort::checkExactFormat(audio_format_t format) const
@@ -495,11 +563,13 @@ status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t
mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK
&& audio_is_linear_pcm(format);
- for (size_t i = 0; i < mFormats.size(); ++i) {
+ // iterate from best format to worst format (reverse order)
+ for (ssize_t i = mFormats.size() - 1; i >= 0 ; --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.
+ (checkInexact
+ && mFormats[i] != AUDIO_FORMAT_DEFAULT
+ && audio_is_linear_pcm(mFormats[i]))) {
+ // for inexact checks we take the first linear pcm format due to sorting.
if (updatedFormat != NULL) {
*updatedFormat = mFormats[i];
}
@@ -726,10 +796,15 @@ void AudioPort::dump(int fd, int spaces) const
const char *formatStr = ConfigParsingUtils::enumToString(sFormatNameToEnumTable,
ARRAY_SIZE(sFormatNameToEnumTable),
mFormats[i]);
- if (i == 0 && strcmp(formatStr, "") == 0) {
+ const bool isEmptyStr = formatStr[0] == 0;
+ if (i == 0 && isEmptyStr) {
snprintf(buffer, SIZE, "Dynamic");
} else {
- snprintf(buffer, SIZE, "%s", formatStr);
+ if (isEmptyStr) {
+ snprintf(buffer, SIZE, "%#x", mFormats[i]);
+ } else {
+ snprintf(buffer, SIZE, "%s", formatStr);
+ }
}
result.append(buffer);
result.append(i == (mFormats.size() - 1) ? "" : ", ");
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 9573583..0715eea 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -52,6 +52,9 @@ bool DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const
// - are of the same type (a device type cannot be AUDIO_DEVICE_NONE)
// - have the same address or one device does not specify the address
// - have the same channel mask or one device does not specify the channel mask
+ if (other == 0) {
+ return false;
+ }
return (mDeviceType == other->mDeviceType) &&
(mAddress == "" || other->mAddress == "" || mAddress == other->mAddress) &&
(mChannelMask == 0 || other->mChannelMask == 0 ||
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 266eeda..ba3fcaf 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -969,6 +969,8 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
audio_devices_t newDevice;
if (outputDesc->mPolicyMix != NULL) {
newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ } else if (mOutputRoutes.hasRouteChanged(session)) {
+ newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
} else {
newDevice = AUDIO_DEVICE_NONE;
}
@@ -1026,7 +1028,7 @@ status_t AudioPolicyManager::startSource(sp<AudioOutputDescriptor> outputDesc,
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
outputDesc->changeRefCount(stream, 1);
- if (outputDesc->mRefCount[stream] == 1) {
+ if (outputDesc->mRefCount[stream] == 1 || device != AUDIO_DEVICE_NONE) {
// starting an output being rerouted?
if (device == AUDIO_DEVICE_NONE) {
device = getNewOutputDevice(outputDesc, false /*fromCache*/);
@@ -2475,6 +2477,18 @@ status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session
return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
}
+status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source __unused,
+ const audio_attributes_t *attributes __unused,
+ audio_io_handle_t *handle __unused)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused)
+{
+ return INVALID_OPERATION;
+}
+
// ----------------------------------------------------------------------------
// AudioPolicyManager
// ----------------------------------------------------------------------------
@@ -4512,18 +4526,36 @@ bool AudioPolicyManager::SessionRouteMap::hasRoute(audio_session_t session)
return indexOfKey(session) >= 0 && valueFor(session)->mDeviceDescriptor != 0;
}
+bool AudioPolicyManager::SessionRouteMap::hasRouteChanged(audio_session_t session)
+{
+ if (indexOfKey(session) >= 0) {
+ if (valueFor(session)->mChanged) {
+ valueFor(session)->mChanged = false;
+ return true;
+ }
+ }
+ return false;
+}
+
void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session,
audio_stream_type_t streamType,
sp<DeviceDescriptor> deviceDescriptor)
{
sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
if (route != NULL) {
+ if ((route->mDeviceDescriptor == 0 && deviceDescriptor != 0) ||
+ (!route->mDeviceDescriptor->equals(deviceDescriptor))) {
+ route->mChanged = true;
+ }
route->mRefCount++;
route->mDeviceDescriptor = deviceDescriptor;
} else {
route = new AudioPolicyManager::SessionRoute(session, streamType, deviceDescriptor);
route->mRefCount++;
add(session, route);
+ if (deviceDescriptor != 0) {
+ route->mChanged = true;
+ }
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index fe6b986..521f6c4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -220,6 +220,11 @@ public:
virtual status_t registerPolicyMixes(Vector<AudioMix> mixes);
virtual status_t unregisterPolicyMixes(Vector<AudioMix> mixes);
+ virtual status_t startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle);
+ virtual status_t stopAudioSource(audio_io_handle_t handle);
+
// Audio policy configuration file parsing (audio_policy.conf)
// TODO candidates to be moved to ConfigParsingUtils
void defaultAudioPolicyConfig(void);
@@ -239,7 +244,10 @@ protected:
mStreamType(streamType),
mDeviceDescriptor(deviceDescriptor),
mRefCount(0),
- mActivityCount(0) {}
+ mActivityCount(0),
+ mChanged(false) {}
+
+ void log(const char* prefix);
audio_session_t mSession;
audio_stream_type_t mStreamType;
@@ -247,10 +255,9 @@ protected:
sp<DeviceDescriptor> mDeviceDescriptor;
// "reference" counting
- int mRefCount; // +/- on references
- int mActivityCount; // +/- on start/stop
-
- void log(const char* prefix);
+ int mRefCount; // +/- on references
+ int mActivityCount; // +/- on start/stop
+ bool mChanged;
};
class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>>
@@ -263,7 +270,7 @@ protected:
int incRouteActivity(audio_session_t session);
int decRouteActivity(audio_session_t session);
-
+ bool hasRouteChanged(audio_session_t session); // also clears the changed flag
void log(const char* caption);
};
@@ -505,6 +512,8 @@ protected:
void updateCallRouting(audio_devices_t rxDevice, int delayMs = 0);
+ // if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force
+ // the re-evaluation of the output device.
status_t startSource(sp<AudioOutputDescriptor> outputDesc,
audio_stream_type_t stream,
audio_devices_t device,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 9510727..e764eda 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -546,9 +546,6 @@ status_t AudioPolicyService::listAudioPorts(audio_port_role_t role,
unsigned int *generation)
{
Mutex::Autolock _l(mLock);
- if(!modifyAudioRoutingAllowed()) {
- return PERMISSION_DENIED;
- }
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
@@ -559,9 +556,6 @@ status_t AudioPolicyService::listAudioPorts(audio_port_role_t role,
status_t AudioPolicyService::getAudioPort(struct audio_port *port)
{
Mutex::Autolock _l(mLock);
- if(!modifyAudioRoutingAllowed()) {
- return PERMISSION_DENIED;
- }
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
@@ -602,9 +596,6 @@ status_t AudioPolicyService::listAudioPatches(unsigned int *num_patches,
unsigned int *generation)
{
Mutex::Autolock _l(mLock);
- if(!modifyAudioRoutingAllowed()) {
- return PERMISSION_DENIED;
- }
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
@@ -661,4 +652,26 @@ status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes, bool re
}
}
+status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle)
+{
+ Mutex::Autolock _l(mLock);
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+
+ return mAudioPolicyManager->startAudioSource(source, attributes, handle);
+}
+
+status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
+{
+ Mutex::Autolock _l(mLock);
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+
+ return mAudioPolicyManager->stopAudioSource(handle);
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index e4ca5dc..f783437 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -604,4 +604,16 @@ status_t AudioPolicyService::registerPolicyMixes(Vector<AudioMix> mixes __unused
return INVALID_OPERATION;
}
+status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
+{
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index fbd8f0e..4e25d33 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -192,6 +192,11 @@ public:
virtual status_t registerPolicyMixes(Vector<AudioMix> mixes, bool registration);
+ virtual status_t startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle);
+ virtual status_t stopAudioSource(audio_io_handle_t handle);
+
status_t doStopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
audio_session_t session);