From 4765d3bfd83f1868fe84961068c81a1dbc222f03 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Thu, 18 Aug 2022 15:47:36 -0400 Subject: [PATCH] Add initial patch for APM Hopefully this works... --- ...and-Q-behavior-respectively-for-tele.patch | 313 ++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 frameworks/av/0001-APM-Restore-S-R-and-Q-behavior-respectively-for-tele.patch diff --git a/frameworks/av/0001-APM-Restore-S-R-and-Q-behavior-respectively-for-tele.patch b/frameworks/av/0001-APM-Restore-S-R-and-Q-behavior-respectively-for-tele.patch new file mode 100644 index 0000000..25fd781 --- /dev/null +++ b/frameworks/av/0001-APM-Restore-S-R-and-Q-behavior-respectively-for-tele.patch @@ -0,0 +1,313 @@ +From 51deb8e31ca57f19420277cc92b26375233e9050 Mon Sep 17 00:00:00 2001 +From: Peter Cai +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 AudioPolicyManager::createTelephonyPatch( ++ bool isRx, const sp &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& devDesc, const char *moduleId) const { + sp 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 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 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 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 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 mCallTxPatch; ++ sp mCallRxPatch; ++ + HwAudioOutputCollection mHwOutputs; + SourceClientCollection mAudioSources; + +-- +2.37.2 +