Dynamic policies: support for device selection
Dynamic policy mix: rename "registration" field to device address
as this reflects the true use of the field.
AudioPolicyManager: dynamic policy registration differs depending
on policy routing flags.
When register a mix with the RENDER flag, iterate over all outputs'
patches to find a matching device and address.
Bug 25448664
Change-Id: I71584081e7f1b2b5252fb6c4659fdeb464f7d282
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
index c769a62..8528c7a 100644
--- a/include/media/AudioPolicy.h
+++ b/include/media/AudioPolicy.h
@@ -51,6 +51,7 @@
#define MIX_ROUTE_FLAG_RENDER 0x1
#define MIX_ROUTE_FLAG_LOOP_BACK (0x1 << 1)
+#define MIX_ROUTE_FLAG_ALL (MIX_ROUTE_FLAG_RENDER | MIX_ROUTE_FLAG_LOOP_BACK)
#define MAX_MIXES_PER_POLICY 10
#define MAX_CRITERIA_PER_MIX 20
@@ -81,7 +82,7 @@
AudioMix(Vector<AudioMixMatchCriterion> criteria, uint32_t mixType, audio_config_t format,
uint32_t routeFlags, String8 registrationId, uint32_t flags) :
mCriteria(criteria), mMixType(mixType), mFormat(format),
- mRouteFlags(routeFlags), mRegistrationId(registrationId), mCbFlags(flags){}
+ mRouteFlags(routeFlags), mDeviceAddress(registrationId), mCbFlags(flags){}
status_t readFromParcel(Parcel *parcel);
status_t writeToParcel(Parcel *parcel) const;
@@ -90,7 +91,8 @@
uint32_t mMixType;
audio_config_t mFormat;
uint32_t mRouteFlags;
- String8 mRegistrationId;
+ audio_devices_t mDeviceType;
+ String8 mDeviceAddress;
uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
};
diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp
index ea22b6c..d1f7525 100644
--- a/media/libmedia/AudioPolicy.cpp
+++ b/media/libmedia/AudioPolicy.cpp
@@ -67,7 +67,8 @@
mFormat.channel_mask = (audio_channel_mask_t)parcel->readInt32();
mFormat.format = (audio_format_t)parcel->readInt32();
mRouteFlags = parcel->readInt32();
- mRegistrationId = parcel->readString8();
+ mDeviceType = (audio_devices_t) parcel->readInt32();
+ mDeviceAddress = parcel->readString8();
mCbFlags = (uint32_t)parcel->readInt32();
size_t size = (size_t)parcel->readInt32();
if (size > MAX_CRITERIA_PER_MIX) {
@@ -89,7 +90,8 @@
parcel->writeInt32(mFormat.channel_mask);
parcel->writeInt32(mFormat.format);
parcel->writeInt32(mRouteFlags);
- parcel->writeString8(mRegistrationId);
+ parcel->writeInt32(mDeviceType);
+ parcel->writeString8(mDeviceAddress);
parcel->writeInt32(mCbFlags);
size_t size = mCriteria.size();
if (size > MAX_CRITERIA_PER_MIX) {
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 6968a74..f73548d 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -42,9 +42,9 @@
* A device mask for all audio input and output devices where matching inputs/outputs on device
* type alone is not enough: the address must match too
*/
-#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX|AUDIO_DEVICE_OUT_BUS)
-#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX)
+#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_BUS)
/**
* Check if the state given correspond to an in call state.
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index c952831..8f5ebef 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -54,7 +54,7 @@
public:
status_t getAudioPolicyMix(String8 address, sp<AudioPolicyMix> &policyMix) const;
- status_t registerMix(String8 address, AudioMix mix);
+ status_t registerMix(String8 address, AudioMix mix, sp<SwAudioOutputDescriptor> desc);
status_t unregisterMix(String8 address);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 0fe1a84..c5fee50 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -315,14 +315,14 @@
if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
{
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
MIX_STATE_MIXING);
}
} else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
{
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
MIX_STATE_IDLE);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 3735c05..4af3d54 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -51,7 +51,8 @@
return &mMix;
}
-status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix)
+status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix,
+ sp<SwAudioOutputDescriptor> desc)
{
ssize_t index = indexOfKey(address);
if (index >= 0) {
@@ -61,6 +62,11 @@
sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
policyMix->setMix(mix);
add(address, policyMix);
+
+ if (desc != 0) {
+ desc->mPolicyMix = policyMix->getMix();
+ policyMix->setOutput(desc);
+ }
return NO_ERROR;
}
@@ -128,7 +134,7 @@
// if there is an address match, prioritize that match
if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
strncmp(attributes.tags + strlen("addr="),
- mix->mRegistrationId.string(),
+ mix->mDeviceAddress.string(),
AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
hasAddrMatch = true;
break;
@@ -207,7 +213,7 @@
if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
strncmp(attributes.tags + strlen("addr="),
- mix->mRegistrationId.string(),
+ mix->mDeviceAddress.string(),
AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
desc = policyMix->getOutput();
}
@@ -260,7 +266,7 @@
for (size_t i = 0; i < size(); i++) {
sp<AudioPolicyMix> policyMix = valueAt(i);
AudioMix *mix = policyMix->getMix();
- ALOGV("\tmix %zu address=%s", i, mix->mRegistrationId.string());
+ ALOGV("\tmix %zu address=%s", i, mix->mDeviceAddress.string());
}
#endif
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
index ce9c170..da983c5 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -79,7 +79,7 @@
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
{
- mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mDeviceAddress,
(event == RECORD_CONFIG_EVENT_START) ? MIX_STATE_MIXING : MIX_STATE_IDLE);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c3b1529..1d7849c 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1096,7 +1096,7 @@
outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- outputDesc->mPolicyMix->mRegistrationId,
+ outputDesc->mPolicyMix->mDeviceAddress,
"remote-submix");
}
@@ -1213,7 +1213,7 @@
outputDesc->mPolicyMix->mMixType == MIX_TYPE_RECORDERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- outputDesc->mPolicyMix->mRegistrationId,
+ outputDesc->mPolicyMix->mDeviceAddress,
"remote-submix");
}
}
@@ -1388,7 +1388,7 @@
return BAD_VALUE;
}
if (policyMix != NULL) {
- address = policyMix->mRegistrationId;
+ address = policyMix->mDeviceAddress;
if (policyMix->mMixType == MIX_TYPE_RECORDERS) {
// there is an external policy, but this input is attached to a mix of recorders,
// meaning it receives audio injected into the framework, so the recorder doesn't
@@ -1622,7 +1622,7 @@
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
- mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
+ mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
MIX_STATE_MIXING);
}
@@ -1639,7 +1639,7 @@
if (inputDesc->mPolicyMix == NULL) {
address = String8("0");
} else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
- address = inputDesc->mPolicyMix->mRegistrationId;
+ address = inputDesc->mPolicyMix->mDeviceAddress;
}
if (address != "") {
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
@@ -1686,7 +1686,7 @@
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
- mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
+ mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mDeviceAddress,
MIX_STATE_IDLE);
}
@@ -1697,7 +1697,7 @@
if (inputDesc->mPolicyMix == NULL) {
address = String8("0");
} else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
- address = inputDesc->mPolicyMix->mRegistrationId;
+ address = inputDesc->mPolicyMix->mDeviceAddress;
}
if (address != "") {
setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
@@ -2010,94 +2010,152 @@
status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)
{
- sp<HwModule> module;
- for (size_t i = 0; i < mHwModules.size(); i++) {
- if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 &&
- mHwModules[i]->mHandle != 0) {
- module = mHwModules[i];
+ ALOGV("registerPolicyMixes() %zu mix(es)", mixes.size());
+ status_t res = NO_ERROR;
+
+ sp<HwModule> rSubmixModule;
+ // examine each mix's route type
+ for (size_t i = 0; i < mixes.size(); i++) {
+ // we only support MIX_ROUTE_FLAG_LOOP_BACK or MIX_ROUTE_FLAG_RENDER, not the combination
+ if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_ALL) == MIX_ROUTE_FLAG_ALL) {
+ res = INVALID_OPERATION;
break;
}
- }
+ if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
+ // Loop back through "remote submix"
+ if (rSubmixModule == 0) {
+ for (size_t j = 0; i < mHwModules.size(); j++) {
+ if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[j]->mName) == 0
+ && mHwModules[j]->mHandle != 0) {
+ rSubmixModule = mHwModules[j];
+ break;
+ }
+ }
+ }
- if (module == 0) {
- return INVALID_OPERATION;
- }
+ ALOGV("registerPolicyMixes() mix %zu of %zu is LOOP_BACK", i, mixes.size());
- ALOGV("registerPolicyMixes() num mixes %zu", mixes.size());
+ if (rSubmixModule == 0) {
+ ALOGE(" Unable to find audio module for submix, aborting mix %zu registration", i);
+ res = INVALID_OPERATION;
+ break;
+ }
- for (size_t i = 0; i < mixes.size(); i++) {
- String8 address = mixes[i].mRegistrationId;
+ String8 address = mixes[i].mDeviceAddress;
- if (mPolicyMixes.registerMix(address, mixes[i]) != NO_ERROR) {
- continue;
- }
- audio_config_t outputConfig = mixes[i].mFormat;
- audio_config_t inputConfig = mixes[i].mFormat;
- // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
- // stereo and let audio flinger do the channel conversion if needed.
- outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
- inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
- module->addOutputProfile(address, &outputConfig,
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
- module->addInputProfile(address, &inputConfig,
- AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
+ if (mPolicyMixes.registerMix(address, mixes[i], 0 /*output desc*/) != NO_ERROR) {
+ ALOGE(" Error regisering mix %zu for address %s", i, address.string());
+ res = INVALID_OPERATION;
+ break;
+ }
+ audio_config_t outputConfig = mixes[i].mFormat;
+ audio_config_t inputConfig = mixes[i].mFormat;
+ // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
+ // stereo and let audio flinger do the channel conversion if needed.
+ outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+ rSubmixModule->addOutputProfile(address, &outputConfig,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
+ rSubmixModule->addInputProfile(address, &inputConfig,
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
- if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
- setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- address.string(), "remote-submix");
- } else {
- setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- address.string(), "remote-submix");
+ if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
+ setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.string(), "remote-submix");
+ } else {
+ setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.string(), "remote-submix");
+ }
+ } else if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
+ ALOGV("registerPolicyMixes() mix %zu of %zu is RENDER", i, mixes.size());
+ String8 address = mixes[i].mDeviceAddress;
+
+ audio_devices_t device = mixes[i].mDeviceType;
+
+ for (size_t j = 0 ; j < mOutputs.size() ; j++) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(j);
+ sp<AudioPatch> patch = mAudioPatches.valueFor(desc->getPatchHandle());
+ if ((patch != 0) && (patch->mPatch.num_sinks != 0)
+ && (patch->mPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE)
+ && (patch->mPatch.sinks[0].ext.device.type == device)
+ && (patch->mPatch.sinks[0].ext.device.address == address)) {
+
+ if (mPolicyMixes.registerMix(address, mixes[i], desc) != NO_ERROR) {
+ res = INVALID_OPERATION;
+ }
+ break;
+ }
+ }
+
+ if (res != NO_ERROR) {
+ ALOGE(" Error registering mix %zu for device 0x%X addr %s",
+ i,device, address.string());
+ res = INVALID_OPERATION;
+ break;
+ }
}
}
- return NO_ERROR;
+ if (res != NO_ERROR) {
+ unregisterPolicyMixes(mixes);
+ }
+ return res;
}
status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
{
- sp<HwModule> module;
- for (size_t i = 0; i < mHwModules.size(); i++) {
- if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[i]->mName) == 0 &&
- mHwModules[i]->mHandle != 0) {
- module = mHwModules[i];
- break;
- }
- }
-
- if (module == 0) {
- return INVALID_OPERATION;
- }
-
ALOGV("unregisterPolicyMixes() num mixes %zu", mixes.size());
-
+ status_t res = NO_ERROR;
+ sp<HwModule> rSubmixModule;
+ // examine each mix's route type
for (size_t i = 0; i < mixes.size(); i++) {
- String8 address = mixes[i].mRegistrationId;
+ if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_LOOP_BACK) == MIX_ROUTE_FLAG_LOOP_BACK) {
- if (mPolicyMixes.unregisterMix(address) != NO_ERROR) {
- continue;
- }
+ if (rSubmixModule == 0) {
+ for (size_t j = 0; i < mHwModules.size(); j++) {
+ if (strcmp(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, mHwModules[j]->mName) == 0
+ && mHwModules[j]->mHandle != 0) {
+ rSubmixModule = mHwModules[j];
+ break;
+ }
+ }
+ }
+ if (rSubmixModule == 0) {
+ res = INVALID_OPERATION;
+ continue;
+ }
- if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) ==
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
- {
- setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- address.string(), "remote-submix");
- }
+ String8 address = mixes[i].mDeviceAddress;
- if (getDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address.string()) ==
- AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
- {
- setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- address.string(), "remote-submix");
+ if (mPolicyMixes.unregisterMix(address) != NO_ERROR) {
+ res = INVALID_OPERATION;
+ continue;
+ }
+
+ if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) ==
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+ setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.string(), "remote-submix");
+ }
+ if (getDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address.string()) ==
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
+ setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ address.string(), "remote-submix");
+ }
+ rSubmixModule->removeOutputProfile(address);
+ rSubmixModule->removeInputProfile(address);
+
+ } if ((mixes[i].mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
+ if (mPolicyMixes.unregisterMix(mixes[i].mDeviceAddress) != NO_ERROR) {
+ res = INVALID_OPERATION;
+ continue;
+ }
}
- module->removeOutputProfile(address);
- module->removeInputProfile(address);
}
- return NO_ERROR;
+ return res;
}