summaryrefslogtreecommitdiffstats
path: root/services/audiopolicy
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2014-07-22 16:19:14 -0700
committerJean-Michel Trivi <jmtrivi@google.com>2014-07-27 11:28:39 -0700
commit0fb47759256ecdaedbc34c880238bc9d102ef160 (patch)
tree5db1d019fb672abc86ebf1d3a331b429e423eaea /services/audiopolicy
parent03c556ae1eb409ad088c49037e185946c54e1d25 (diff)
downloadframeworks_av-0fb47759256ecdaedbc34c880238bc9d102ef160.zip
frameworks_av-0fb47759256ecdaedbc34c880238bc9d102ef160.tar.gz
frameworks_av-0fb47759256ecdaedbc34c880238bc9d102ef160.tar.bz2
AudioPolicyManager: handle outputs for different addresses
Add the notion of device types that cause the device address to be taken into account, i.e. multiple devices of the same type but with a different address can be connected/ disconnected. AUDIO_DEVICE_OUT_REMOTE_SUBMIX is such a device type. When making those devices available / unavailable, look for all outputs with a matching address. Bug 16009464 Change-Id: I260f8248b7794c4932094e876afdf29fdea007a3
Diffstat (limited to 'services/audiopolicy')
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp135
-rw-r--r--services/audiopolicy/AudioPolicyManager.h14
2 files changed, 120 insertions, 29 deletions
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 737cacd..aa6a389 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -30,6 +30,10 @@
// A device mask for all audio output devices that are considered "remote" when evaluating
// active output devices in isStreamActiveRemotely()
#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+// 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_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
#include <inttypes.h>
#include <math.h>
@@ -228,14 +232,6 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
}
ALOGV("setDeviceConnectionState() connecting device %x", device);
- if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) {
- return INVALID_OPERATION;
- }
- // outputs should never be empty here
- ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
- "checkOutputsForDevice() returned no outputs but status OK");
- ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
- outputs.size());
// register new device as available
index = mAvailableOutputDevices.add(devDesc);
if (index >= 0) {
@@ -248,6 +244,15 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
return NO_MEMORY;
}
+ if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) {
+ mAvailableOutputDevices.remove(devDesc);
+ return INVALID_OPERATION;
+ }
+ // outputs should never be empty here
+ ALOG_ASSERT(outputs.size() != 0, "setDeviceConnectionState():"
+ "checkOutputsForDevice() returned no outputs but status OK");
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs",
+ outputs.size());
break;
// handle output device disconnection
case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
@@ -261,8 +266,6 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
mAvailableOutputDevices.remove(devDesc);
checkOutputsForDevice(device, state, outputs, address);
- // not currently handling multiple simultaneous submixes: ignoring remote submix
- // case and address
} break;
default:
@@ -295,10 +298,13 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
// do not force device change on duplicated output because if device is 0, it will
// also force a device 0 for the two outputs it is duplicated to which may override
// a valid device selection on those outputs.
+ bool force = !mOutputs.valueAt(i)->isDuplicated()
+ && (!deviceDistinguishesOnAddress(device)
+ // always force when disconnecting (a non-duplicated device)
+ || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
setOutputDevice(mOutputs.keyAt(i),
getNewOutputDevice(mOutputs.keyAt(i), true /*fromCache*/),
- !mOutputs.valueAt(i)->isDuplicated(),
- 0);
+ force, 0);
}
mpClientInterface->onAudioPortListUpdate();
@@ -2643,10 +2649,39 @@ String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const Str
{
if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
return String8("a2dp_sink_address=")+address;
+ } else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+ return String8("mix=")+address;
}
return address;
}
+void AudioPolicyManager::findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
+ const String8 address /*in*/,
+ SortedVector<audio_io_handle_t>& outputs /*out*/) {
+ // look for a match on the given address on the addresses of the outputs:
+ // find the address by finding the patch that maps to this output
+ ssize_t patchIdx = mAudioPatches.indexOfKey(desc->mPatchHandle);
+ //ALOGV(" inspecting output %d (patch %d) for supported device=0x%x",
+ // outputIdx, patchIdx, desc->mProfile->mSupportedDevices.types());
+ if (patchIdx >= 0) {
+ const sp<AudioPatch> patchDesc = mAudioPatches.valueAt(patchIdx);
+ const int numSinks = patchDesc->mPatch.num_sinks;
+ for (ssize_t j=0; j < numSinks; j++) {
+ if (patchDesc->mPatch.sinks[j].type == AUDIO_PORT_TYPE_DEVICE) {
+ const char* patchAddr =
+ patchDesc->mPatch.sinks[j].ext.device.address;
+ if (strncmp(patchAddr,
+ address.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
+ ALOGV("checkOutputsForDevice(): adding opened output %d on same address %s",
+ desc->mIoHandle, patchDesc->mPatch.sinks[j].ext.device.address);
+ outputs.add(desc->mIoHandle);
+ break;
+ }
+ }
+ }
+ }
+}
+
status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
audio_policy_dev_state_t state,
SortedVector<audio_io_handle_t>& outputs,
@@ -2659,8 +2694,13 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
if (!desc->isDuplicated() && (desc->mProfile->mSupportedDevices.types() & device)) {
- ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
- outputs.add(mOutputs.keyAt(i));
+ if (!deviceDistinguishesOnAddress(device)) {
+ ALOGV("checkOutputsForDevice(): adding opened output %d", mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ } else {
+ ALOGV(" checking address match due to device 0x%x", device);
+ findIoHandlesByAddress(desc, address, outputs);
+ }
}
}
// then look for output profiles that can be routed to this device
@@ -2679,6 +2719,8 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
}
}
+ ALOGV(" found %d profiles, %d outputs", profiles.size(), outputs.size());
+
if (profiles.isEmpty() && outputs.isEmpty()) {
ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
return BAD_VALUE;
@@ -2691,13 +2733,13 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
// nothing to do if one output is already opened for this profile
size_t j;
- for (j = 0; j < mOutputs.size(); j++) {
- desc = mOutputs.valueAt(j);
+ for (j = 0; j < outputs.size(); j++) {
+ desc = mOutputs.valueFor(outputs.itemAt(j));
if (!desc->isDuplicated() && desc->mProfile == profile) {
break;
}
}
- if (j != mOutputs.size()) {
+ if (j != outputs.size()) {
continue;
}
@@ -2730,7 +2772,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
if (profile->mSamplingRates[0] == 0) {
reply = mpClientInterface->getParameters(output,
String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkOutputsForDevice() direct output sup sampling rates %s",
+ ALOGV("checkOutputsForDevice() supported sampling rates %s",
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
@@ -2740,7 +2782,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
reply = mpClientInterface->getParameters(output,
String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkOutputsForDevice() direct output sup formats %s",
+ ALOGV("checkOutputsForDevice() supported formats %s",
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
@@ -2750,7 +2792,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
if (profile->mChannelMasks[0] == 0) {
reply = mpClientInterface->getParameters(output,
String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkOutputsForDevice() direct output sup channel masks %s",
+ ALOGV("checkOutputsForDevice() supported channel masks %s",
reply.string());
value = strpbrk((char *)reply.string(), "=");
if (value != NULL) {
@@ -2763,7 +2805,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
(profile->mFormats.size() < 2)) ||
((profile->mChannelMasks[0] == 0) &&
(profile->mChannelMasks.size() < 2))) {
- ALOGW("checkOutputsForDevice() direct output missing param");
+ ALOGW("checkOutputsForDevice() missing param");
mpClientInterface->closeOutput(output);
output = 0;
} else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
@@ -2827,6 +2869,12 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
profile_index--;
} else {
outputs.add(output);
+ if (deviceDistinguishesOnAddress(device)) {
+ ALOGV("checkOutputsForDevice(): setOutputDevice(dev=0x%x, addr=%s)",
+ device, address.string());
+ setOutputDevice(output, device, true/*force*/, 0/*delay*/,
+ NULL/*patch handle*/, address.string());
+ }
ALOGV("checkOutputsForDevice(): adding output %d", output);
}
}
@@ -2839,11 +2887,17 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device,
// check if one opened output is not needed any more after disconnecting one device
for (size_t i = 0; i < mOutputs.size(); i++) {
desc = mOutputs.valueAt(i);
- if (!desc->isDuplicated() &&
- !(desc->mProfile->mSupportedDevices.types() &
- mAvailableOutputDevices.types())) {
- ALOGV("checkOutputsForDevice(): disconnecting adding output %d", mOutputs.keyAt(i));
- outputs.add(mOutputs.keyAt(i));
+ if (!desc->isDuplicated()) {
+ if (!(desc->mProfile->mSupportedDevices.types()
+ & mAvailableOutputDevices.types())) {
+ ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
+ mOutputs.keyAt(i));
+ outputs.add(mOutputs.keyAt(i));
+ } else if (deviceDistinguishesOnAddress(device) &&
+ // exact match on device
+ (desc->mProfile->mSupportedDevices.types() == device)) {
+ findIoHandlesByAddress(desc, address, outputs);
+ }
}
}
// Clear any profiles associated with the disconnected device.
@@ -3736,7 +3790,8 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
audio_devices_t device,
bool force,
int delayMs,
- audio_patch_handle_t *patchHandle)
+ audio_patch_handle_t *patchHandle,
+ const char* address)
{
ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
@@ -3782,7 +3837,9 @@ uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
if (device == AUDIO_DEVICE_NONE) {
resetOutputDevice(output, delayMs, NULL);
} else {
- DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
+ DeviceVector deviceList = (address == NULL) ?
+ mAvailableOutputDevices.getDevicesFromType(device)
+ : mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
if (!deviceList.isEmpty()) {
struct audio_patch patch;
outputDesc->toAudioPortConfig(&patch.sources[0]);
@@ -4046,6 +4103,10 @@ bool AudioPolicyManager::isVirtualInputDevice(audio_devices_t device)
return false;
}
+bool AudioPolicyManager::deviceDistinguishesOnAddress(audio_devices_t device) {
+ return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL) != 0);
+}
+
audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs)
{
for (size_t i = 0; i < mInputs.size(); i++) {
@@ -5954,6 +6015,24 @@ AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFro
return devices;
}
+AudioPolicyManager::DeviceVector AudioPolicyManager::DeviceVector::getDevicesFromTypeAddr(
+ audio_devices_t type, String8 address) const
+{
+ DeviceVector devices;
+ //ALOGV(" looking for device=%x, addr=%s", type, address.string());
+ for (size_t i = 0; i < size(); i++) {
+ //ALOGV(" at i=%d: device=%x, addr=%s",
+ // i, itemAt(i)->mDeviceType, itemAt(i)->mAddress.string());
+ if (itemAt(i)->mDeviceType == type) {
+ if (itemAt(i)->mAddress == address) {
+ //ALOGV(" found matching address %s", address.string());
+ devices.add(itemAt(i));
+ }
+ }
+ }
+ return devices;
+}
+
sp<AudioPolicyManager::DeviceDescriptor> AudioPolicyManager::DeviceVector::getDeviceFromName(
const String8& name) const
{
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index e9ec78e..a420192 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -339,6 +339,8 @@ protected:
DeviceVector getDevicesFromType(audio_devices_t types) const;
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
sp<DeviceDescriptor> getDeviceFromName(const String8& name) const;
+ DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address)
+ const;
private:
void refreshTypes();
@@ -534,7 +536,8 @@ protected:
audio_devices_t device,
bool force = false,
int delayMs = 0,
- audio_patch_handle_t *patchHandle = NULL);
+ audio_patch_handle_t *patchHandle = NULL,
+ const char* address = NULL);
status_t resetOutputDevice(audio_io_handle_t output,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL);
@@ -774,6 +777,15 @@ private:
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
static bool isVirtualInputDevice(audio_devices_t device);
+ static bool deviceDistinguishesOnAddress(audio_devices_t device);
+ // find the outputs on a given output descriptor that have the given address.
+ // to be called on an AudioOutputDescriptor whose supported devices (as defined
+ // in mProfile->mSupportedDevices) matches the device whose address is to be matched.
+ // see deviceDistinguishesOnAddress(audio_devices_t) for whether the device type is one
+ // where addresses are used to distinguish between one connected device and another.
+ void findIoHandlesByAddress(sp<AudioOutputDescriptor> desc /*in*/,
+ const String8 address /*in*/,
+ SortedVector<audio_io_handle_t>& outputs /*out*/);
uint32_t nextUniqueId();
uint32_t nextAudioPortGeneration();
uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }