Merge changes from topics "presubmit-am-87e43861d082492cad38dc75a9f31cdb", "presubmit-am-a8669f4a68d94c8d9b842b36e692e795" into tm-dev
* changes:
[BUG] AudioPolicyManager: prevent unecessary force routing on SwOutput
[BUG] AudioPolicyManager: prevent patch leak on SwOutput used for bridges
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 18cf0c1..f57ac64 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -305,6 +305,7 @@
{
return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false;
}
+ bool isRouted() const { return mPatchHandle != AUDIO_PATCH_HANDLE_NONE; }
DeviceVector mDevices; /**< current devices this output is routed to */
wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index dc2403c..6f95012 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -56,7 +56,13 @@
virtual void dump(String8 *dst, int spaces) const;
virtual std::string toShortString() const;
-
+ /**
+ * @brief isInternal
+ * @return true if the client corresponds to an audio patch created from createAudioPatch API or
+ * for call audio routing, or false if the client corresponds to an AudioTrack, AudioRecord or
+ * HW Audio Source.
+ */
+ virtual bool isInternal() const { return false; }
audio_port_handle_t portId() const { return mPortId; }
uid_t uid() const { return mUid; }
audio_session_t session() const { return mSessionId; };
@@ -69,8 +75,16 @@
bool isPreferredDeviceForExclusiveUse() const { return mPreferredDeviceForExclusiveUse; }
virtual void setActive(bool active) { mActive = active; }
bool active() const { return mActive; }
+ /**
+ * @brief hasPreferredDevice Note that as internal clients use preferred device for convenience,
+ * we do hide this internal behavior to prevent from regression (like invalidating track for
+ * clients following same strategies...)
+ * @param activeOnly
+ * @return
+ */
bool hasPreferredDevice(bool activeOnly = false) const {
- return mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
+ return !isInternal() &&
+ mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive);
}
private:
@@ -211,6 +225,11 @@
mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
mSinkDevice = nullptr;
}
+ bool belongsToOutput(const sp<SwAudioOutputDescriptor> &swOutput) const {
+ return swOutput != nullptr && mSwOutput.promote() == swOutput;
+ }
+ void setUseSwBridge() { mUseSwBridge = true; }
+ bool useSwBridge() const { return mUseSwBridge; }
bool isConnected() const { return mPatchHandle != AUDIO_PATCH_HANDLE_NONE; }
audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
@@ -229,6 +248,35 @@
sp<DeviceDescriptor> mSinkDevice;
wp<SwAudioOutputDescriptor> mSwOutput;
wp<HwAudioOutputDescriptor> mHwOutput;
+ bool mUseSwBridge = false;
+};
+
+/**
+ * @brief The InternalSourceClientDescriptor class
+ * Specialized Client Descriptor for either a raw patch created from @see createAudioPatch API
+ * or for internal audio patches managed by APM (e.g. phone call patches).
+ * Whatever the bridge created (software or hardware), we need a client to track the activity
+ * and manage volumes.
+ * The Audio Patch requested sink is expressed as a preferred device which allows to route
+ * the SwOutput. Then APM will performs checks on the UID (against UID of Audioserver) of the
+ * requester to prevent rerouting SwOutput involved in raw patches.
+ */
+class InternalSourceClientDescriptor: public SourceClientDescriptor
+{
+public:
+ InternalSourceClientDescriptor(
+ audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
+ const struct audio_port_config &config, const sp<DeviceDescriptor>& srcDevice,
+ const sp<DeviceDescriptor>& sinkDevice,
+ product_strategy_t strategy, VolumeSource volumeSource) :
+ SourceClientDescriptor(
+ portId, uid, attributes, config, srcDevice, AUDIO_STREAM_PATCH, strategy,
+ volumeSource)
+ {
+ setPreferredDeviceId(sinkDevice->getId());
+ }
+ bool isInternal() const override { return true; }
+ ~InternalSourceClientDescriptor() override = default;
};
class SourceClientCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 1132a29..d1655ef 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -100,7 +100,8 @@
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
{config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
- {} /* Sources do not support secondary outputs*/, nullptr), mSrcDevice(srcDevice)
+ {} /* Sources do not support secondary outputs*/, nullptr),
+ mSrcDevice(srcDevice)
{
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c3c9753..ff4705c 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -664,12 +664,8 @@
ALOGV("%s device rxDevice %s txDevice %s", __func__,
rxDevices.itemAt(0)->toString().c_str(), txSourceDevice->toString().c_str());
- disconnectTelephonyRxAudioSource();
- // release TX patch if any
- if (mCallTxPatch != 0) {
- releaseAudioPatchInternal(mCallTxPatch->getHandle());
- mCallTxPatch.clear();
- }
+ disconnectTelephonyAudioSource(mCallRxSourceClient);
+ disconnectTelephonyAudioSource(mCallTxSourceClient);
auto telephonyRxModule =
mHwModules.getModuleForDeviceType(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
@@ -727,7 +723,7 @@
closeActiveClients(activeDesc);
}
}
- mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
+ connectTelephonyTxAudioSource(txSourceDevice, txSinkDevice, delayMs);
}
if (waitMs != nullptr) {
*waitMs = muteWaitMs;
@@ -735,36 +731,6 @@
return NO_ERROR;
}
-sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
- bool isRx, const sp<DeviceDescriptor> &device, uint32_t delayMs) {
- PatchBuilder patchBuilder;
-
- if (device == nullptr) {
- return nullptr;
- }
-
- // @TODO: still ignoring the address, or not dealing platform with multiple telephony devices
- if (isRx) {
- patchBuilder.addSink(device).
- addSource(mAvailableInputDevices.getDevice(
- AUDIO_DEVICE_IN_TELEPHONY_RX, String8(), AUDIO_FORMAT_DEFAULT));
- } else {
- patchBuilder.addSource(device).
- addSink(mAvailableOutputDevices.getDevice(
- AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT));
- }
-
- audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
- status_t status =
- createAudioPatchInternal(patchBuilder.patch(), &patchHandle, mUidCached, delayMs);
- ssize_t index = mAudioPatches.indexOfKey(patchHandle);
- if (status != NO_ERROR || index < 0) {
- ALOGW("%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
- return nullptr;
- }
- return mAudioPatches.valueAt(index);
-}
-
bool AudioPolicyManager::isDeviceOfModule(
const sp<DeviceDescriptor>& devDesc, const char *moduleId) const {
sp<HwModule> module = mHwModules.getModuleFromName(moduleId);
@@ -779,20 +745,55 @@
void AudioPolicyManager::connectTelephonyRxAudioSource()
{
- disconnectTelephonyRxAudioSource();
+ disconnectTelephonyAudioSource(mCallRxSourceClient);
const struct audio_port_config source = {
.role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE,
.ext.device.type = AUDIO_DEVICE_IN_TELEPHONY_RX, .ext.device.address = ""
};
const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
- status_t status = startAudioSource(&source, &aa, &mCallRxSourceClientPort, 0/*uid*/);
- ALOGE_IF(status != NO_ERROR, "%s failed to start Telephony Rx AudioSource", __func__);
+ mCallRxSourceClient = startAudioSourceInternal(&source, &aa, 0/*uid*/);
+ ALOGE_IF(mCallRxSourceClient == nullptr,
+ "%s failed to start Telephony Rx AudioSource", __func__);
}
-void AudioPolicyManager::disconnectTelephonyRxAudioSource()
+void AudioPolicyManager::disconnectTelephonyAudioSource(sp<SourceClientDescriptor> &clientDesc)
{
- stopAudioSource(mCallRxSourceClientPort);
- mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE;
+ if (clientDesc == nullptr) {
+ return;
+ }
+ ALOGW_IF(stopAudioSource(clientDesc->portId()) != NO_ERROR,
+ "%s error stopping audio source", __func__);
+ clientDesc.clear();
+}
+
+void AudioPolicyManager::connectTelephonyTxAudioSource(
+ const sp<DeviceDescriptor> &srcDevice, const sp<DeviceDescriptor> &sinkDevice,
+ uint32_t delayMs)
+{
+ disconnectTelephonyAudioSource(mCallTxSourceClient);
+ if (srcDevice == nullptr || sinkDevice == nullptr) {
+ ALOGW("%s could not create patch, invalid sink and/or source device(s)", __func__);
+ return;
+ }
+ PatchBuilder patchBuilder;
+ patchBuilder.addSource(srcDevice).addSink(sinkDevice);
+ ALOGV("%s between source %s and sink %s", __func__,
+ srcDevice->toString().c_str(), sinkDevice->toString().c_str());
+ auto callTxSourceClientPortId = PolicyAudioPort::getNextUniqueId();
+ const audio_attributes_t aa = { .source = AUDIO_SOURCE_VOICE_COMMUNICATION };
+ struct audio_port_config source = {};
+ srcDevice->toAudioPortConfig(&source);
+ mCallTxSourceClient = new InternalSourceClientDescriptor(
+ callTxSourceClientPortId, mUidCached, aa, source, srcDevice, sinkDevice,
+ mCommunnicationStrategy, toVolumeSource(aa));
+ audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
+ status_t status = connectAudioSourceToSink(
+ mCallTxSourceClient, sinkDevice, patchBuilder.patch(), patchHandle, mUidCached,
+ delayMs);
+ ALOGE_IF(status != NO_ERROR, "%s() error %d creating TX audio patch", __func__, status);
+ if (status == NO_ERROR) {
+ mAudioSources.add(callTxSourceClientPortId, mCallTxSourceClient);
+ }
}
void AudioPolicyManager::setPhoneState(audio_mode_t state)
@@ -860,11 +861,8 @@
rxDevices = mPrimaryOutput->devices();
}
if (oldState == AUDIO_MODE_IN_CALL) {
- disconnectTelephonyRxAudioSource();
- if (mCallTxPatch != 0) {
- releaseAudioPatchInternal(mCallTxPatch->getHandle());
- mCallTxPatch.clear();
- }
+ disconnectTelephonyAudioSource(mCallRxSourceClient);
+ disconnectTelephonyAudioSource(mCallTxSourceClient);
}
setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
}
@@ -874,8 +872,10 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
DeviceVector newDevices = getNewOutputDevices(desc, true /*fromCache*/);
- if (state != AUDIO_MODE_IN_CALL || desc != mPrimaryOutput) {
- setOutputDevices(desc, newDevices, !newDevices.isEmpty(), 0 /*delayMs*/);
+ if (state != AUDIO_MODE_IN_CALL || (desc != mPrimaryOutput && !isTelephonyRxOrTx(desc))) {
+ bool forceRouting = !newDevices.isEmpty();
+ setOutputDevices(desc, newDevices, forceRouting, 0 /*delayMs*/, nullptr,
+ true /*requiresMuteCheck*/, !forceRouting /*requiresVolumeCheck*/);
}
}
@@ -1510,6 +1510,27 @@
return msdPatches;
}
+bool AudioPolicyManager::isMsdPatch(const audio_patch_handle_t &handle) const {
+ ssize_t index = mAudioPatches.indexOfKey(handle);
+ if (index < 0) {
+ return false;
+ }
+ const sp<AudioPatch> patch = mAudioPatches.valueAt(index);
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule == nullptr) {
+ return false;
+ }
+ const struct audio_port_config *sink = &patch->mPatch.sinks[0];
+ if (getMsdAudioOutDevices().contains(mAvailableOutputDevices.getDeviceFromId(sink->id))) {
+ return true;
+ }
+ index = getMsdOutputPatches().indexOfKey(handle);
+ if (index < 0) {
+ return false;
+ }
+ return true;
+}
+
status_t AudioPolicyManager::getMsdProfiles(bool hwAvSync,
const InputProfileCollection &inputProfiles,
const OutputProfileCollection &outputProfiles,
@@ -1939,8 +1960,7 @@
// force device change if the output is inactive and no audio patch is already present.
// check active before incrementing usage count
- bool force = !outputDesc->isActive() &&
- (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
+ bool force = !outputDesc->isActive() && !outputDesc->isRouted();
DeviceVector devices;
sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
@@ -3511,11 +3531,15 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/);
- if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) {
+ if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) ||
+ (outputDesc != mPrimaryOutput && !isTelephonyRxOrTx(outputDesc))) {
// As done in setDeviceConnectionState, we could also fix default device issue by
// preventing the force re-routing in case of default dev that distinguishes on address.
// Let's give back to engine full device choice decision however.
- waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs);
+ bool forceRouting = !newDevices.isEmpty();
+ waitMs = setOutputDevices(outputDesc, newDevices, forceRouting, delayMs, nullptr,
+ true /*requiresMuteCheck*/,
+ !forceRouting /*requiresVolumeCheck*/);
// Only apply special touch sound delay once
delayMs = 0;
}
@@ -4064,17 +4088,15 @@
return BAD_VALUE;
}
-status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *patch,
- audio_patch_handle_t *handle,
- uid_t uid, uint32_t delayMs,
- const sp<SourceClientDescriptor>& sourceDesc)
+status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ uid_t uid)
{
ALOGV("%s", __func__);
if (handle == NULL || patch == NULL) {
return BAD_VALUE;
}
ALOGV("%s num sources %d num sinks %d", __func__, patch->num_sources, patch->num_sinks);
-
if (!audio_patch_is_valid(patch)) {
return BAD_VALUE;
}
@@ -4082,7 +4104,6 @@
if (patch->num_sources > 1) {
return INVALID_OPERATION;
}
-
if (patch->sources[0].role != AUDIO_PORT_ROLE_SOURCE) {
return INVALID_OPERATION;
}
@@ -4092,6 +4113,86 @@
}
}
+ sp<DeviceDescriptor> srcDevice = mAvailableInputDevices.getDeviceFromId(patch->sources[0].id);
+ sp<DeviceDescriptor> sinkDevice = mAvailableOutputDevices.getDeviceFromId(patch->sinks[0].id);
+ if (srcDevice == nullptr || sinkDevice == nullptr) {
+ ALOGW("%s could not create patch, invalid sink and/or source device(s)", __func__);
+ return BAD_VALUE;
+ }
+ ALOGV("%s between source %s and sink %s", __func__,
+ srcDevice->toString().c_str(), sinkDevice->toString().c_str());
+ audio_port_handle_t portId = PolicyAudioPort::getNextUniqueId();
+ // Default attributes, default volume priority, not to infer with non raw audio patches.
+ audio_attributes_t attributes = attributes_initializer(AUDIO_USAGE_MEDIA);
+ const struct audio_port_config *source = &patch->sources[0];
+ sp<SourceClientDescriptor> sourceDesc =
+ new InternalSourceClientDescriptor(
+ portId, uid, attributes, *source, srcDevice, sinkDevice,
+ mEngine->getProductStrategyForAttributes(attributes), toVolumeSource(attributes));
+
+ status_t status =
+ connectAudioSourceToSink(sourceDesc, sinkDevice, patch, *handle, uid, 0 /* delayMs */);
+
+ if (status != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ mAudioSources.add(portId, sourceDesc);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::connectAudioSourceToSink(
+ const sp<SourceClientDescriptor>& sourceDesc, const sp<DeviceDescriptor> &sinkDevice,
+ const struct audio_patch *patch,
+ audio_patch_handle_t &handle,
+ uid_t uid, uint32_t delayMs)
+{
+ status_t status = createAudioPatchInternal(patch, &handle, uid, delayMs, sourceDesc);
+ if (status != NO_ERROR || mAudioPatches.indexOfKey(handle) < 0) {
+ ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
+ return INVALID_OPERATION;
+ }
+ sourceDesc->connect(handle, sinkDevice);
+ if (isMsdPatch(handle)) {
+ return NO_ERROR;
+ }
+ // SW Bridge? (@todo: HW bridge, keep track of HwOutput for device selection "reconsideration")
+ sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
+ ALOG_ASSERT(swOutput != nullptr, "%s: a swOutput shall always be associated", __func__);
+ if (swOutput->getClient(sourceDesc->portId()) != nullptr) {
+ ALOGW("%s source portId has already been attached to outputDesc", __func__);
+ goto FailurePatchAdded;
+ }
+ status = swOutput->start();
+ if (status != NO_ERROR) {
+ goto FailureSourceAdded;
+ }
+ swOutput->addClient(sourceDesc);
+ status = startSource(swOutput, sourceDesc, &delayMs);
+ if (status != NO_ERROR) {
+ ALOGW("%s failed to start source, error %d", __FUNCTION__, status);
+ goto FailureSourceActive;
+ }
+ if (delayMs != 0) {
+ usleep(delayMs * 1000);
+ }
+ return NO_ERROR;
+
+FailureSourceActive:
+ swOutput->stop();
+ releaseOutput(sourceDesc->portId());
+FailureSourceAdded:
+ sourceDesc->setSwOutput(nullptr);
+FailurePatchAdded:
+ releaseAudioPatchInternal(handle);
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ uid_t uid, uint32_t delayMs,
+ const sp<SourceClientDescriptor>& sourceDesc)
+{
+ ALOGV("%s num sources %d num sinks %d", __func__, patch->num_sources, patch->num_sinks);
sp<AudioPatch> patchDesc;
ssize_t index = mAudioPatches.indexOfKey(*handle);
@@ -4280,7 +4381,7 @@
// in config XML to reach the sink so that is can be declared as available.
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
sp<SwAudioOutputDescriptor> outputDesc = nullptr;
- if (sourceDesc != nullptr) {
+ if (!sourceDesc->isInternal()) {
// take care of dynamic routing for SwOutput selection,
audio_attributes_t attributes = sourceDesc->attributes();
audio_stream_type_t stream = sourceDesc->stream();
@@ -4308,44 +4409,49 @@
return INVALID_OPERATION;
}
sourceDesc->setSwOutput(outputDesc);
+ } else {
+ // Same for "raw patches" aka created from createAudioPatch API
+ SortedVector<audio_io_handle_t> outputs =
+ getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
+ // if the sink device is reachable via an opened output stream, request to
+ // go via this output stream by adding a second source to the patch
+ // description
+ output = selectOutput(outputs);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGE("%s no output available for internal patch sink", __func__);
+ return INVALID_OPERATION;
+ }
+ outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGV("%s output for device %s is duplicated",
+ __func__, sinkDevice->toString().c_str());
+ return INVALID_OPERATION;
+ }
+ sourceDesc->setSwOutput(outputDesc);
}
// create a software bridge in PatchPanel if:
// - source and sink devices are on different HW modules OR
// - audio HAL version is < 3.0
// - audio HAL version is >= 3.0 but no route has been declared between devices
- // - called from startAudioSource (aka sourceDesc != nullptr) and source device does
- // not have a gain controller
+ // - called from startAudioSource (aka sourceDesc is not internal) and source device
+ // does not have a gain controller
if (!srcDevice->hasSameHwModuleAs(sinkDevice) ||
(srcDevice->getModuleVersionMajor() < 3) ||
!srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice) ||
- (sourceDesc != nullptr &&
+ (!sourceDesc->isInternal() &&
srcDevice->getAudioPort()->getGains().size() == 0)) {
// support only one sink device for now to simplify output selection logic
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
}
- if (sourceDesc == nullptr) {
- SortedVector<audio_io_handle_t> outputs =
- getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
- // if the sink device is reachable via an opened output stream, request to
- // go via this output stream by adding a second source to the patch
- // description
- output = selectOutput(outputs);
- if (output != AUDIO_IO_HANDLE_NONE) {
- outputDesc = mOutputs.valueFor(output);
- if (outputDesc->isDuplicated()) {
- ALOGV("%s output for device %s is duplicated",
- __FUNCTION__, sinkDevice->toString().c_str());
- return INVALID_OPERATION;
- }
- }
- }
+ sourceDesc->setUseSwBridge();
if (outputDesc != nullptr) {
audio_port_config srcMixPortConfig = {};
outputDesc->toAudioPortConfig(&srcMixPortConfig, nullptr);
// for volume control, we may need a valid stream
- srcMixPortConfig.ext.mix.usecase.stream = sourceDesc != nullptr ?
- sourceDesc->stream() : AUDIO_STREAM_PATCH;
+ srcMixPortConfig.ext.mix.usecase.stream = !sourceDesc->isInternal() ?
+ mEngine->getStreamTypeForAttributes(sourceDesc->attributes()) :
+ AUDIO_STREAM_PATCH;
patchBuilder.addSource(srcMixPortConfig);
}
}
@@ -4368,11 +4474,9 @@
return NO_ERROR;
}
-status_t AudioPolicyManager::releaseAudioPatch(audio_patch_handle_t handle,
- uid_t uid)
+status_t AudioPolicyManager::releaseAudioPatch(audio_patch_handle_t handle, uid_t uid)
{
- ALOGV("releaseAudioPatch() patch %d", handle);
-
+ ALOGV("%s patch %d", __func__, handle);
ssize_t index = mAudioPatches.indexOfKey(handle);
if (index < 0) {
@@ -4384,11 +4488,21 @@
if (patchDesc->getUid() != mUidCached && uid != patchDesc->getUid()) {
return INVALID_OPERATION;
}
- return releaseAudioPatchInternal(handle);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ for (size_t i = 0; i < mAudioSources.size(); i++) {
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc != nullptr && sourceDesc->getPatchHandle() == handle) {
+ portId = sourceDesc->portId();
+ break;
+ }
+ }
+ return portId != AUDIO_PORT_HANDLE_NONE ?
+ stopAudioSource(portId) : releaseAudioPatchInternal(handle);
}
status_t AudioPolicyManager::releaseAudioPatchInternal(audio_patch_handle_t handle,
- uint32_t delayMs)
+ uint32_t delayMs,
+ const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s patch %d", __func__, handle);
if (mAudioPatches.indexOfKey(handle) < 0) {
@@ -4429,26 +4543,29 @@
removeAudioPatch(patchDesc->getHandle());
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
- // SW Bridge
+ // SW or HW Bridge
+ sp<SwAudioOutputDescriptor> outputDesc = nullptr;
+ audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
if (patch->num_sources > 1 && patch->sources[1].type == AUDIO_PORT_TYPE_MIX) {
- sp<SwAudioOutputDescriptor> outputDesc =
- mOutputs.getOutputFromId(patch->sources[1].id);
- if (outputDesc == NULL) {
- ALOGW("%s output not found for id %d", __func__, patch->sources[0].id);
- // releaseOutput has already called closeOuput in case of direct output
- return NO_ERROR;
- }
- if (patchDesc->getHandle() != outputDesc->getPatchHandle()) {
- // force SwOutput patch removal as AF counter part patch has already gone.
- ALOGV("%s reset patch handle on Output as different from SWBridge", __func__);
- removeAudioPatch(outputDesc->getPatchHandle());
- }
- outputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
+ outputDesc = mOutputs.getOutputFromId(patch->sources[1].id);
+ } else if (patch->num_sources == 1 && sourceDesc != nullptr) {
+ outputDesc = sourceDesc->swOutput().promote();
+ }
+ if (outputDesc == nullptr) {
+ ALOGW("%s no output for id %d", __func__, patch->sources[0].id);
+ // releaseOutput has already called closeOutput in case of direct output
+ return NO_ERROR;
+ }
+ if (!outputDesc->isActive() && !sourceDesc->useSwBridge()) {
+ resetOutputDevice(outputDesc);
+ } else {
+ // Reuse patch handle if still valid / do not force rerouting if still routed
+ patchHandle = outputDesc->getPatchHandle();
setOutputDevices(outputDesc,
getNewOutputDevices(outputDesc, true /*fromCache*/),
- true, /*force*/
+ patchHandle == AUDIO_PATCH_HANDLE_NONE, /*force*/
0,
- NULL);
+ patchHandle == AUDIO_PATCH_HANDLE_NONE ? nullptr : &patchHandle);
}
} else {
return BAD_VALUE;
@@ -4694,6 +4811,18 @@
return status;
}
+sp<SourceClientDescriptor> AudioPolicyManager::startAudioSourceInternal(
+ const struct audio_port_config *source, const audio_attributes_t *attributes, uid_t uid)
+{
+ ALOGV("%s", __FUNCTION__);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+
+ status_t status = startAudioSource(source, attributes, &portId, uid);
+ ALOGE_IF(status != OK, "%s: failed to start audio source (%d)", __func__, status);
+ return mAudioSources.valueFor(portId);
+}
+
+
status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s handle %d", __FUNCTION__, sourceDesc->portId());
@@ -4718,52 +4847,9 @@
PatchBuilder patchBuilder;
patchBuilder.addSink(sinkDevice).addSource(srcDevice);
audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
- status_t status =
- createAudioPatchInternal(patchBuilder.patch(), &handle, mUidCached, 0, sourceDesc);
- if (status != NO_ERROR || mAudioPatches.indexOfKey(handle) < 0) {
- ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
- return INVALID_OPERATION;
- }
- 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) {
- status = swOutput->start();
- if (status != NO_ERROR) {
- goto FailureSourceAdded;
- }
- if (swOutput->getClient(sourceDesc->portId()) != nullptr) {
- ALOGW("%s source portId has already been attached to outputDesc", __func__);
- goto FailureReleasePatch;
- }
- swOutput->addClient(sourceDesc);
- uint32_t delayMs = 0;
- status = startSource(swOutput, sourceDesc, &delayMs);
- if (status != NO_ERROR) {
- ALOGW("%s failed to start source, error %d", __FUNCTION__, status);
- goto FailureSourceActive;
- }
- if (delayMs != 0) {
- usleep(delayMs * 1000);
- }
- } else {
- sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
- if (hwOutputDesc != 0) {
- // create Hwoutput and add to mHwOutputs
- } else {
- ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
- }
- }
- return NO_ERROR;
-FailureSourceActive:
- swOutput->stop();
- releaseOutput(sourceDesc->portId());
-FailureSourceAdded:
- sourceDesc->setSwOutput(nullptr);
-FailureReleasePatch:
- releaseAudioPatchInternal(handle);
- return INVALID_OPERATION;
+ return connectAudioSourceToSink(
+ sourceDesc, sinkDevice, patchBuilder.patch(), handle, mUidCached, 0 /*delayMs*/);
}
status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
@@ -5089,7 +5175,7 @@
ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
}
}
- status_t status = releaseAudioPatchInternal(sourceDesc->getPatchHandle());
+ status_t status = releaseAudioPatchInternal(sourceDesc->getPatchHandle(), 0, sourceDesc);
sourceDesc->disconnect();
return status;
}
@@ -6061,7 +6147,7 @@
sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
if (sourceDesc != nullptr && followsSameRouting(attr, sourceDesc->attributes())
&& sourceDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE
- && !isCallRxAudioSource(sourceDesc)) {
+ && !isCallRxAudioSource(sourceDesc) && !sourceDesc->isInternal()) {
connectAudioSource(sourceDesc);
}
}
@@ -6174,7 +6260,7 @@
newDevices.types());
}
sp<SourceClientDescriptor> source = getSourceForAttributesOnOutput(srcOut, attr);
- if (source != nullptr && !isCallRxAudioSource(source)) {
+ if (source != nullptr && !isCallRxAudioSource(source) && !source->isInternal()) {
connectAudioSource(source);
}
}
@@ -6708,6 +6794,8 @@
muteWaitMs = 0;
}
+ bool outputRouted = outputDesc->isRouted();
+
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
// output profile or if new device is not supported AND previous device(s) is(are) still
// available (otherwise reset device must be done on the output)
@@ -6724,8 +6812,7 @@
// AND force is not specified
// AND the output is connected by a valid audio patch.
// Doing this check here allows the caller to call setOutputDevices() without conditions
- if ((filteredDevices.isEmpty() || filteredDevices == prevDevices) &&
- !force && outputDesc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
+ if ((filteredDevices.isEmpty() || filteredDevices == prevDevices) && !force && outputRouted) {
ALOGV("%s setting same device %s or null device, force=%d, patch handle=%d", __func__,
filteredDevices.toString().c_str(), force, outputDesc->getPatchHandle());
if (requiresVolumeCheck && !filteredDevices.isEmpty()) {
@@ -6765,6 +6852,9 @@
audio_patch_handle_t *patchHandle)
{
ssize_t index;
+ if (patchHandle == nullptr && !outputDesc->isRouted()) {
+ return INVALID_OPERATION;
+ }
if (patchHandle) {
index = mAudioPatches.indexOfKey(*patchHandle);
} else {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 4d307cf..6f8b897 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -263,10 +263,7 @@
virtual status_t getAudioPort(struct audio_port_v7 *port);
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
- uid_t uid) {
- return createAudioPatchInternal(patch, handle, uid);
- }
-
+ uid_t uid);
virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
uid_t uid);
virtual status_t listAudioPatches(unsigned int *num_patches,
@@ -638,13 +635,22 @@
void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0);
bool isCallRxAudioSource(const sp<SourceClientDescriptor> &source) {
- return mCallRxSourceClientPort != AUDIO_PORT_HANDLE_NONE
- && source == mAudioSources.valueFor(mCallRxSourceClientPort);
+ return mCallRxSourceClient != nullptr && source == mCallRxSourceClient;
}
void connectTelephonyRxAudioSource();
- void disconnectTelephonyRxAudioSource();
+ void disconnectTelephonyAudioSource(sp<SourceClientDescriptor> &clientDesc);
+
+ void connectTelephonyTxAudioSource(const sp<DeviceDescriptor> &srcdevice,
+ const sp<DeviceDescriptor> &sinkDevice,
+ uint32_t delayMs);
+
+ bool isTelephonyRxOrTx(const sp<SwAudioOutputDescriptor>& desc) const {
+ return (mCallRxSourceClient != nullptr && mCallRxSourceClient->belongsToOutput(desc))
+ || (mCallTxSourceClient != nullptr
+ && mCallTxSourceClient->belongsToOutput(desc));
+ }
/**
* @brief updates routing for all inputs.
@@ -851,6 +857,12 @@
status_t connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
status_t disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
+ status_t connectAudioSourceToSink(const sp<SourceClientDescriptor>& sourceDesc,
+ const sp<DeviceDescriptor> &sinkDevice,
+ const struct audio_patch *patch,
+ audio_patch_handle_t &handle,
+ uid_t uid, uint32_t delayMs);
+
sp<SourceClientDescriptor> getSourceForAttributesOnOutput(audio_io_handle_t output,
const audio_attributes_t &attr);
void clearAudioSourcesForOutput(audio_io_handle_t output);
@@ -901,8 +913,6 @@
SoundTriggerSessionCollection mSoundTriggerSessions;
- sp<AudioPatch> mCallTxPatch;
-
HwAudioOutputCollection mHwOutputs;
SourceClientCollection mAudioSources;
@@ -943,7 +953,8 @@
// The port handle of the hardware audio source created internally for the Call RX audio
// end point.
- audio_port_handle_t mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE;
+ sp<SourceClientDescriptor> mCallRxSourceClient;
+ sp<SourceClientDescriptor> mCallTxSourceClient;
// Support for Multi-Stream Decoder (MSD) module
sp<DeviceDescriptor> getMsdAudioInDevice() const;
@@ -975,7 +986,13 @@
// Called by setDeviceConnectionState()
status_t deviceToAudioPort(audio_devices_t deviceType, const char* device_address,
const char* device_name, media::AudioPort* aidPort);
+ bool isMsdPatch(const audio_patch_handle_t &handle) const;
+
private:
+ sp<SourceClientDescriptor> startAudioSourceInternal(
+ const struct audio_port_config *source, const audio_attributes_t *attributes,
+ uid_t uid);
+
void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
// Add or remove AC3 DTS encodings based on user preferences.
@@ -1120,21 +1137,25 @@
* @param[out] handle patch handle to be provided if patch installed correctly
* @param[in] uid of the client
* @param[in] delayMs if required
- * @param[in] sourceDesc [optional] in case of external source, source client to be
- * configured by the patch, i.e. assigning an Output (HW or SW)
+ * @param[in] sourceDesc source client to be configured when creating the patch, i.e.
+ * assigning an Output (HW or SW) used for volume control.
* @return NO_ERROR if patch installed correctly, error code otherwise.
*/
status_t createAudioPatchInternal(const struct audio_patch *patch,
audio_patch_handle_t *handle,
- uid_t uid, uint32_t delayMs = 0,
- const sp<SourceClientDescriptor>& sourceDesc = nullptr);
+ uid_t uid, uint32_t delayMs,
+ const sp<SourceClientDescriptor>& sourceDesc);
/**
* @brief releaseAudioPatchInternal internal function to remove an audio patch
* @param[in] handle of the patch to be removed
* @param[in] delayMs if required
+ * @param[in] sourceDesc [optional] in case of external source, source client to be
+ * unrouted from the patch, i.e. assigning an Output (HW or SW)
* @return NO_ERROR if patch removed correctly, error code otherwise.
*/
- status_t releaseAudioPatchInternal(audio_patch_handle_t handle, uint32_t delayMs = 0);
+ status_t releaseAudioPatchInternal(audio_patch_handle_t handle,
+ uint32_t delayMs = 0,
+ const sp<SourceClientDescriptor>& sourceDesc = nullptr);
status_t installPatch(const char *caller,
audio_patch_handle_t *patchHandle,