Add initial patch for APM

Hopefully this works...
This commit is contained in:
Peter Cai 2022-08-18 15:47:36 -04:00
parent 04694ee655
commit 4765d3bfd8
1 changed files with 313 additions and 0 deletions

View File

@ -0,0 +1,313 @@
From 51deb8e31ca57f19420277cc92b26375233e9050 Mon Sep 17 00:00:00 2001
From: Peter Cai <peter@typeblog.net>
Date: Thu, 18 Aug 2022 15:44:46 -0400
Subject: [PATCH] APM: Restore S, R and Q behavior respectively for telephony
audio
This conditionally reverts part of b2e5cb (T), 51c9cc (S) and afd4ce (R)
when the VNDK version is equal to or before S, R and Q respectively.
On R, commit afd4ce made it so that both HW and SW bridging go through
`createAudioPatch()`, which is broken on some devices such as on MTK Q
vendor, because their HAL do not support HW patching via the newer
`createAudioPatch()` method. Instead, the patching on Q was done through
`setOutputDevices()`.
On S, commit 51c9cc refactored the related code again such that HW
bridging for the Rx direction is essentially removed, replaced with SW
bridging through `startAudioSource()`. This is, again, broken on MTK R
vendor devices.
On T, commit b2e5cb applied the same SW bridging to the Tx direction.
All of these commits rely on assumptions that are not tested through
VTS and just presumed to be true. Although we can blame MTK for not
supporting all the possible cases in their HAL, it will not fix
anything, and really frameworks code should not depend on such untested
assumptions.
To work around said issues, we restore old behavior from S, R and Q
relying on the value of `ro.vndk.version`.
Change-Id: I56d36d2aef4319935cb88a3e4771b23c6d5b2145
---
.../managerdefault/AudioPolicyManager.cpp | 193 +++++++++++++-----
.../managerdefault/AudioPolicyManager.h | 3 +
2 files changed, 141 insertions(+), 55 deletions(-)
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 744609f27b..224dae3820 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -675,6 +675,17 @@ status_t AudioPolicyManager::updateCallRoutingInternal(
disconnectTelephonyAudioSource(mCallRxSourceClient);
disconnectTelephonyAudioSource(mCallTxSourceClient);
+ // release existing RX patch if any
+ if (mCallRxPatch != 0) {
+ releaseAudioPatchInternal(mCallRxPatch->getHandle());
+ mCallRxPatch.clear();
+ }
+ // release TX patch if any
+ if (mCallTxPatch != 0) {
+ releaseAudioPatchInternal(mCallTxPatch->getHandle());
+ mCallTxPatch.clear();
+ }
+
auto telephonyRxModule =
mHwModules.getModuleForDeviceType(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
auto telephonyTxModule =
@@ -697,9 +708,20 @@ status_t AudioPolicyManager::updateCallRoutingInternal(
ALOGE("%s() no telephony Tx and/or RX device", __func__);
return INVALID_OPERATION;
}
- // createAudioPatchInternal now supports both HW / SW bridging
- createRxPatch = true;
- createTxPatch = true;
+ if (property_get_int32("ro.vndk.version", 31) >= 30) {
+ // createAudioPatchInternal now supports both HW / SW bridging
+ createRxPatch = true;
+ createTxPatch = true;
+ } else {
+ // pre-R behavior: some devices before VNDK 30 do not support createAudioPatch correctly
+ // for HW bridging even though they declare support for it
+ // do not create a patch (aka Sw Bridging) if Primary HW module has declared supporting a
+ // route between telephony RX to Sink device and Source device to telephony TX
+ ALOGI("%s() Using pre-R behavior for createRxPatch and createTxPatch", __func__);
+ const auto &primaryModule = telephonyRxModule;
+ createRxPatch = !primaryModule->supportsPatch(rxSourceDevice, rxDevices.itemAt(0));
+ createTxPatch = !primaryModule->supportsPatch(txSourceDevice, txSinkDevice);
+ }
} else {
// If the RX device is on the primary HW module, then use legacy routing method for
// voice calls via setOutputDevice() on primary output.
@@ -716,7 +738,14 @@ status_t AudioPolicyManager::updateCallRoutingInternal(
if (!createRxPatch) {
muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
} else { // create RX path audio patch
- connectTelephonyRxAudioSource();
+ if (property_get_int32("ro.vndk.version", 31) >= 31) {
+ connectTelephonyRxAudioSource();
+ } else {
+ // pre-S behavior: some devices do not support SW bridging correctly when HW bridge is
+ // available through createAudioPatch(); startAudioSource() forces SW bridging.
+ ALOGI("%s() Using pre-S behavior to create HW Rx patch", __func__);
+ mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevices.itemAt(0), delayMs);
+ }
// If the TX device is on the primary HW module but RX device is
// on other HW module, SinkMetaData of telephony input should handle it
// assuming the device uses audio HAL V5.0 and above
@@ -731,7 +760,12 @@ status_t AudioPolicyManager::updateCallRoutingInternal(
closeActiveClients(activeDesc);
}
}
- connectTelephonyTxAudioSource(txSourceDevice, txSinkDevice, delayMs);
+ if (property_get_int32("ro.vndk.version", 33) >= 33) {
+ connectTelephonyTxAudioSource(txSourceDevice, txSinkDevice, delayMs);
+ } else {
+ // pre-T behavior: hw bridging for tx too; skip the SwOutput
+ mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
+ }
}
if (waitMs != nullptr) {
*waitMs = muteWaitMs;
@@ -739,6 +773,36 @@ status_t AudioPolicyManager::updateCallRoutingInternal(
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, nullptr);
+ 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);
@@ -4520,76 +4584,95 @@ status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *
// 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->isInternal()) {
- // take care of dynamic routing for SwOutput selection,
- audio_attributes_t attributes = sourceDesc->attributes();
- audio_stream_type_t stream = sourceDesc->stream();
- audio_attributes_t resultAttr;
- audio_config_t config = AUDIO_CONFIG_INITIALIZER;
- config.sample_rate = sourceDesc->config().sample_rate;
- config.channel_mask = sourceDesc->config().channel_mask;
- config.format = sourceDesc->config().format;
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- bool isRequestedDeviceForExclusiveUse = false;
- output_type_t outputType;
- bool isSpatialized;
- getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
- &stream, sourceDesc->uid(), &config, &flags,
- &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
- nullptr, &outputType, &isSpatialized);
- if (output == AUDIO_IO_HANDLE_NONE) {
- ALOGV("%s no output for device %s",
- __FUNCTION__, sinkDevice->toString().c_str());
- return INVALID_OPERATION;
- }
- outputDesc = mOutputs.valueFor(output);
- if (outputDesc->isDuplicated()) {
- ALOGE("%s output is duplicated", __func__);
- return INVALID_OPERATION;
- }
- sourceDesc->setSwOutput(outputDesc);
- } else {
- // Same for "raw patches" aka created from createAudioPatch API
- SortedVector<audio_io_handle_t> outputs =
+ 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();
+ audio_attributes_t resultAttr;
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.sample_rate = sourceDesc->config().sample_rate;
+ config.channel_mask = sourceDesc->config().channel_mask;
+ config.format = sourceDesc->config().format;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ bool isRequestedDeviceForExclusiveUse = false;
+ output_type_t outputType;
+ bool isSpatialized;
+ getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
+ &stream, sourceDesc->uid(), &config, &flags,
+ &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
+ nullptr, &outputType, &isSpatialized);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGV("%s no output for device %s",
+ __FUNCTION__, sinkDevice->toString().c_str());
+ return INVALID_OPERATION;
+ }
+ outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGE("%s output is duplicated", __func__);
+ 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;
+ // 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);
}
- 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 is not internal) and source device
+ // - called from startAudioSource (aka sourceDesc is neither null nor internal) and source device
// does not have a gain controller
if (!srcDevice->hasSameHwModuleAs(sinkDevice) ||
(srcDevice->getModuleVersionMajor() < 3) ||
!srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice) ||
- (!sourceDesc->isInternal() &&
+ ((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;
}
- sourceDesc->setUseSwBridge();
+ 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;
+ }
+ }
+ } else {
+ 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->isInternal() ?
+ srcMixPortConfig.ext.mix.usecase.stream = (sourceDesc != nullptr && !sourceDesc->isInternal()) ?
mEngine->getStreamTypeForAttributes(sourceDesc->attributes()) :
AUDIO_STREAM_PATCH;
patchBuilder.addSource(srcMixPortConfig);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index db0ee15de8..97fa6f6f81 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -938,6 +938,9 @@ protected:
SoundTriggerSessionCollection mSoundTriggerSessions;
+ sp<AudioPatch> mCallTxPatch;
+ sp<AudioPatch> mCallRxPatch;
+
HwAudioOutputCollection mHwOutputs;
SourceClientCollection mAudioSources;
--
2.37.2