diff --git a/frameworks/av/0001-APM-Optionally-force-load-audio-policy-for-system-si.patch b/frameworks/av/0001-APM-Optionally-force-load-audio-policy-for-system-si.patch index a0a77cf..25c41ad 100644 --- a/frameworks/av/0001-APM-Optionally-force-load-audio-policy-for-system-si.patch +++ b/frameworks/av/0001-APM-Optionally-force-load-audio-policy-for-system-si.patch @@ -1,7 +1,7 @@ From f8b9cb1d3cdf0274414bb7d100844d2707999558 Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Wed, 24 Aug 2022 15:42:39 -0400 -Subject: [PATCH 1/3] APM: Optionally force-load audio policy for system-side +Subject: [PATCH 1/5] APM: Optionally force-load audio policy for system-side bt audio HAL Required to support our system-side bt audio implementation, i.e. diff --git a/frameworks/av/0002-APM-Remove-A2DP-audio-ports-from-the-primary-HAL.patch b/frameworks/av/0002-APM-Remove-A2DP-audio-ports-from-the-primary-HAL.patch index a20824d..3da3764 100644 --- a/frameworks/av/0002-APM-Remove-A2DP-audio-ports-from-the-primary-HAL.patch +++ b/frameworks/av/0002-APM-Remove-A2DP-audio-ports-from-the-primary-HAL.patch @@ -1,7 +1,7 @@ From d60a1b5fc58a7cc84b48c554cb2cffaeff14d86e Mon Sep 17 00:00:00 2001 From: Peter Cai Date: Thu, 25 Aug 2022 13:30:29 -0400 -Subject: [PATCH 2/3] APM: Remove A2DP audio ports from the primary HAL +Subject: [PATCH 2/5] APM: Remove A2DP audio ports from the primary HAL These ports defined in the primary HAL are intended for A2DP offloading, however they do not work in general on GSIs, and will interfere with diff --git a/frameworks/av/0003-voip-Fix-high-pitched-voice-on-Qualcomm-devices.patch b/frameworks/av/0003-voip-Fix-high-pitched-voice-on-Qualcomm-devices.patch index 2021695..ac07cfd 100644 --- a/frameworks/av/0003-voip-Fix-high-pitched-voice-on-Qualcomm-devices.patch +++ b/frameworks/av/0003-voip-Fix-high-pitched-voice-on-Qualcomm-devices.patch @@ -1,7 +1,7 @@ From aa1f3595b06e6d3d7027a5dd40ae183d71d032f0 Mon Sep 17 00:00:00 2001 From: ponces Date: Mon, 24 Oct 2022 09:38:34 +0100 -Subject: [PATCH 3/3] voip: Fix high pitched voice on Qualcomm devices +Subject: [PATCH 3/5] voip: Fix high pitched voice on Qualcomm devices Change-Id: I6d314912169776b76d07d8c0301ec5249c1870a2 --- diff --git a/frameworks/av/0004-APM-Restore-S-R-and-Q-behavior-respectively-for-tele.patch b/frameworks/av/0004-APM-Restore-S-R-and-Q-behavior-respectively-for-tele.patch new file mode 100644 index 0000000..ad766d2 --- /dev/null +++ b/frameworks/av/0004-APM-Restore-S-R-and-Q-behavior-respectively-for-tele.patch @@ -0,0 +1,326 @@ +From 1a9a9faca4d5c28747a3b7d9843b67c641ed91c9 Mon Sep 17 00:00:00 2001 +From: Peter Cai +Date: Thu, 18 Aug 2022 15:44:46 -0400 +Subject: [PATCH 4/5] 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 | 206 ++++++++++++------ + .../managerdefault/AudioPolicyManager.h | 3 + + 2 files changed, 147 insertions(+), 62 deletions(-) + +diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +index f093e685ba..9a90009f9e 100644 +--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp ++++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +@@ -689,6 +689,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 = +@@ -711,9 +722,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. +@@ -730,7 +752,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 +@@ -745,7 +774,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; +@@ -753,6 +787,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); +@@ -4958,83 +5022,101 @@ 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; +- 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; +- audio_channel_mask_t sourceMask = sourceDesc->config().channel_mask; +- config.channel_mask = +- (audio_channel_mask_get_representation(sourceMask) +- == AUDIO_CHANNEL_REPRESENTATION_INDEX) ? sourceMask +- : audio_channel_mask_in_to_out(sourceMask); +- 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; +- bool isBitPerfect; +- getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes, +- &stream, sourceDesc->uid(), &config, &flags, +- &selectedDeviceId, &isRequestedDeviceForExclusiveUse, +- nullptr, &outputType, &isSpatialized, &isBitPerfect); +- 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; +- } +- bool closeOutput = outputDesc->mDirectOpenCount != 0; +- sourceDesc->setSwOutput(outputDesc, closeOutput); +- } 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 (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; ++ audio_channel_mask_t sourceMask = sourceDesc->config().channel_mask; ++ config.channel_mask = ++ (audio_channel_mask_get_representation(sourceMask) ++ == AUDIO_CHANNEL_REPRESENTATION_INDEX) ? sourceMask ++ : audio_channel_mask_in_to_out(sourceMask); ++ 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; ++ bool isBitPerfect; ++ getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes, ++ &stream, sourceDesc->uid(), &config, &flags, ++ &selectedDeviceId, &isRequestedDeviceForExclusiveUse, ++ nullptr, &outputType, &isSpatialized, &isBitPerfect); ++ 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; ++ } ++ bool closeOutput = outputDesc->mDirectOpenCount != 0; ++ sourceDesc->setSwOutput(outputDesc, closeOutput); ++ } 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; ++ } + } +- sourceDesc->setSwOutput(outputDesc, /* closeOutput= */ false); + } + // 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() || isCallTxAudioSource(sourceDesc)) ? ++ (sourceDesc != nullptr && (!sourceDesc->isInternal() || isCallTxAudioSource(sourceDesc))) ? + 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 88bafefdb1..188b5732b3 100644 +--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h ++++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h +@@ -953,6 +953,9 @@ protected: + + SoundTriggerSessionCollection mSoundTriggerSessions; + ++ sp mCallTxPatch; ++ sp mCallRxPatch; ++ + HwAudioOutputCollection mHwOutputs; + SourceClientCollection mAudioSources; + +-- +2.41.0 + diff --git a/frameworks/av/0005-Fix-BT-in-call-on-CAF-devices.patch b/frameworks/av/0005-Fix-BT-in-call-on-CAF-devices.patch new file mode 100644 index 0000000..04a2722 --- /dev/null +++ b/frameworks/av/0005-Fix-BT-in-call-on-CAF-devices.patch @@ -0,0 +1,131 @@ +From 97421e35dd716c9b07ec44ec05265944efc96294 Mon Sep 17 00:00:00 2001 +From: Pierre-Hugues Husson +Date: Mon, 5 Aug 2019 18:09:50 +0200 +Subject: [PATCH 5/5] Fix BT in-call on CAF devices + +See https://github.com/phhusson/treble_experimentations/issues/374 + +In Qualcomm's BSP audio_policy_configuration.xml, one route is missing, +from primary output and telephony to BT SCO. + +Add it if we detect telephony and bt sco, but no such route. + +Change-Id: Ifea0f88276ec9a0811f3cb1973c4b06f2c82077b +--- + .../managerdefinitions/src/Serializer.cpp | 93 +++++++++++++++++++ + 1 file changed, 93 insertions(+) + +diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp +index d23d55677d..4f896111cb 100644 +--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp ++++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp +@@ -672,6 +672,98 @@ std::variant PolicySerializer::deserialize primary input mix ++ // But Telephony Rx => BT SCO Headset route is missing ++ // When we detect such case, add the missing route ++ ++ // If we have: ++ // ++ // ++ // ++ // And no ++ ++ // Add: ++ // ++ bool foundBtScoHeadsetDevice = false; ++ for(const auto& device: devicePorts) { ++ if(device->getTagName() == "BT SCO Headset") { ++ foundBtScoHeadsetDevice = true; ++ break; ++ } ++ } ++ if(!foundBtScoHeadsetDevice) { ++ ALOGE("No BT SCO Headset device found, don't patch policy"); ++ return; ++ } ++ ++ bool foundTelephony = false; ++ bool foundBtScoInput = false; ++ bool foundScoHeadsetRoute = false; ++ for(const auto& route: routes) { ++ ALOGE("Looking at route %d\n", route->getType()); ++ if(route->getType() != AUDIO_ROUTE_MIX) ++ continue; ++ auto sink = route->getSink(); ++ ALOGE("... With sink %s\n", sink->getTagName().c_str()); ++ if(sink->getTagName() == "Telephony Tx") { ++ foundTelephony = true; ++ continue; ++ } ++ if(sink->getTagName() == "BT SCO Headset") { ++ foundScoHeadsetRoute = true; ++ break; ++ } ++ for(const auto& source: route->getSources()) { ++ ALOGE("... With source %s\n", source->getTagName().c_str()); ++ if(source->getTagName() == "BT SCO Headset Mic") { ++ foundBtScoInput = true; ++ break; ++ } ++ } ++ } ++ //The route we want to add is already there ++ ALOGE("Done looking for existing routes"); ++ if(foundScoHeadsetRoute) ++ return; ++ ++ ALOGE("No existing route found... %d %d", foundTelephony ? 1 : 0, foundBtScoInput ? 1 : 0); ++ //We couldn't find the routes we assume are required for the function we want to add ++ if(!foundTelephony || !foundBtScoInput) ++ return; ++ ALOGE("Adding our own."); ++ ++ // Add: ++ // ++ AudioRoute *newRoute = new AudioRoute(AUDIO_ROUTE_MIX); ++ ++ auto sink = ctx->findPortByTagName("BT SCO Headset"); ++ ALOGE("Got sink %p\n", sink.get()); ++ newRoute->setSink(sink); ++ ++ Vector> sources; ++ for(const auto& sourceName: { ++ "primary output", ++ "deep_buffer", ++ "compressed_offload", ++ "Telephony Rx" ++ }) { ++ auto source = ctx->findPortByTagName(sourceName); ++ ALOGE("Got source %p\n", source.get()); ++ if (source.get() != nullptr) { ++ sources.add(source); ++ source->addRoute(newRoute); ++ } ++ } ++ ++ newRoute->setSources(sources); ++ ++ sink->addRoute(newRoute); ++ ++ auto ret = routes.add(newRoute); ++ ALOGE("route add returned %zd", ret); ++} ++ + template<> + std::variant PolicySerializer::deserialize( + const xmlNode *cur, ModuleTraits::PtrSerializingCtx ctx) +@@ -739,6 +831,7 @@ std::variant PolicySerializer::deserializesetRoutes(routes); + + for (const xmlNode *children = cur->xmlChildrenNode; children != NULL; +-- +2.41.0 +