audio policy: audio source automatic re-connection
When an audio source is started, if either the sink or the source
becomes unavailable, the audio source is stopped.
It implies that the client must listen to patch/ports to become
aware that the source has been stopped.
In order to prevent this, it is possible to allow automatic re-connection
of audio source as APM already keeps track of AudioSource.
In case of unavailability, source is only disconnected, not stopped to prevent
from removing from tracking list.
Test: adb shell /data/nativetest64/AudioPolicyEmulatorTests/AudioPolicyEmulatorTests --gtest_filter=*AudioSourceBridgingTest*
Signed-off-by: Francois Gaffie <francois.gaffie@renault.com>
Change-Id: I414195a85a06c9212420e3b51bf2863f3e08c755
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0c3541a..5b6e066 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -385,7 +385,11 @@
DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevices);
}
-
+ // Reconnect Audio Source
+ for (const auto &strategy : mEngine->getOrderedProductStrategies()) {
+ auto attributes = mEngine->getAllAttributesForProductStrategy(strategy).front();
+ checkAudioSourceForAttributes(attributes);
+ }
if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
cleanUpForDevice(device);
}
@@ -4273,18 +4277,21 @@
// make sure we only have one patch per source.
disconnectAudioSource(sourceDesc);
- sourceDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
audio_attributes_t attributes = sourceDesc->attributes();
- sp<DeviceDescriptor> srcDevice = sourceDesc->srcDevice();
-
+ // May the device (dynamic) have been disconnected/reconnected, id has changed.
+ sp<DeviceDescriptor> srcDevice = mAvailableInputDevices.getDevice(
+ sourceDesc->srcDevice()->type(),
+ String8(sourceDesc->srcDevice()->address().c_str()),
+ AUDIO_FORMAT_DEFAULT);
DeviceVector sinkDevices =
mEngine->getOutputDevicesForAttributes(attributes, nullptr, false /*fromCache*/);
ALOG_ASSERT(!sinkDevices.isEmpty(), "connectAudioSource(): no device found for attributes");
sp<DeviceDescriptor> sinkDevice = sinkDevices.itemAt(0);
- ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available",
- __FUNCTION__, sinkDevice->toString().c_str());
-
+ if (!mAvailableOutputDevices.contains(sinkDevice)) {
+ ALOGE("%s Device %s not available", __func__, sinkDevice->toString().c_str());
+ return INVALID_OPERATION;
+ }
PatchBuilder patchBuilder;
patchBuilder.addSink(sinkDevice).addSource(srcDevice);
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
@@ -4294,7 +4301,7 @@
ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
return INVALID_OPERATION;
}
- sourceDesc->setPatchHandle(handle);
+ sourceDesc->connect(handle, sinkDevice);
// SW Bridge? (@todo: HW bridge, keep track of HwOutput for device selection "reconsideration")
sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
if (swOutput != 0) {
@@ -4591,6 +4598,10 @@
status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
+ if (!sourceDesc->isConnected()) {
+ ALOGV("%s port Id %d already disconnected", __FUNCTION__, sourceDesc->portId());
+ return NO_ERROR;
+ }
sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
if (swOutput != 0) {
status_t status = stopSource(swOutput, sourceDesc);
@@ -4610,7 +4621,9 @@
ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
}
}
- return releaseAudioPatchInternal(sourceDesc->getPatchHandle());
+ status_t status = releaseAudioPatchInternal(sourceDesc->getPatchHandle());
+ sourceDesc->disconnect();
+ return status;
}
sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput(
@@ -6476,9 +6489,9 @@
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
- if (sourceDesc->srcDevice()->equals(deviceDesc)) {
- ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->portId());
- stopAudioSource(sourceDesc->portId());
+ if (sourceDesc->isConnected() && (sourceDesc->srcDevice()->equals(deviceDesc) ||
+ sourceDesc->sinkDevice()->equals(deviceDesc))) {
+ disconnectAudioSource(sourceDesc);
}
}
@@ -6492,10 +6505,14 @@
release = true;
}
}
+ const char *address = deviceDesc->address().c_str();
for (size_t j = 0; j < patchDesc->mPatch.num_sinks && !release; j++) {
const struct audio_port_config *sink = &patchDesc->mPatch.sinks[j];
if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
- sink->ext.device.type == deviceDesc->type()) {
+ sink->ext.device.type == deviceDesc->type() &&
+ (strnlen(address, AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0
+ || strncmp(sink->ext.device.address, address,
+ AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
release = true;
}
}