forked from PeterGSI/patches
parent
04694ee655
commit
4765d3bfd8
|
@ -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
|
||||
|
Loading…
Reference in New Issue