Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 150fcc6f authored by François Gaffie's avatar François Gaffie Committed by Eric Laurent
Browse files

audiopolicy: fix audioflinger patch release while using SwBridge



Test: make

When using a SwBridge, AudioFlinger creates a new patch to reach the
sink device from the SwOutput.
Upon release, the patch is released, hence the associated mixer thread
has released the patch.
Previously, setOutputDevices was forced on the SwOutput to recreate a
patch.
However, it consumes times, hence leading to for example certification
issue of CarPlay (call shall be routed within less than 100ms while in
FM)

Change-Id: I84209b8e69d202e5754946a341f8bb1d89b7d5a6
Signed-off-by: default avatarFrançois Gaffie <francois.gaffie@renault.com>
parent db1755bf
Loading
Loading
Loading
Loading
+50 −9
Original line number Diff line number Diff line
@@ -412,7 +412,23 @@ status_t PatchPanel::createAudioPatch_l(const struct audio_patch* patch,
                mAfPatchPanelCallback->updateOutDevicesForRecordThreads_l(devices);
            }

            // For endpoint patches, we do not need to re-evaluate the device effect state
            // if the same HAL patch is reused (see calls to mAfPatchPanelCallback below)
            if (endpointPatch) {
                for (auto& p : mPatches) {
                    // end point patches are skipped so we do not compare against this patch
                    if (!p.second.mIsEndpointPatch && patchesHaveSameRoute(
                            newPatch.mAudioPatch, p.second.mAudioPatch)) {
                        ALOGV("%s() Sw Bridge endpoint reusing halHandle=%d", __func__,
                              p.second.mHalHandle);
                        halHandle = p.second.mHalHandle;
                        reuseExistingHalPatch = true;
                        break;
                    }
                }
            }
            mAfPatchPanelCallback->mutex().unlock();

            status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
            mAfPatchPanelCallback->mutex().lock();
            if (status == NO_ERROR) {
@@ -442,11 +458,18 @@ exit:
        *handle = static_cast<audio_patch_handle_t>(
                mAfPatchPanelCallback->nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH));
        newPatch.mHalHandle = halHandle;
        // Skip device effect:
        //  -for sw bridge as effect are likely held by endpoint patches
        //  -for endpoint reusing a HalPatch handle
        if (!(newPatch.isSoftware()
                || (endpointPatch && reuseExistingHalPatch))) {
            if (reuseExistingHalPatch) {
                mAfPatchPanelCallback->getPatchCommandThread()->updateAudioPatch(
                        oldhandle, *handle, newPatch);
            } else {
            mAfPatchPanelCallback->getPatchCommandThread()->createAudioPatch(*handle, newPatch);
                 mAfPatchPanelCallback->getPatchCommandThread()->createAudioPatch(
                        *handle, newPatch);
            }
        }
        if (insertedModule != AUDIO_MODULE_HANDLE_NONE) {
            addSoftwarePatchToInsertedModules_l(insertedModule, *handle, &newPatch.mAudioPatch);
@@ -734,12 +757,14 @@ status_t PatchPanel::releaseAudioPatch_l(audio_patch_handle_t handle)
 {
    ALOGV("%s handle %d", __func__, handle);
    status_t status = NO_ERROR;
    bool doReleasePatch = true;

    auto iter = mPatches.find(handle);
    if (iter == mPatches.end()) {
        return BAD_VALUE;
    }
    Patch &removedPatch = iter->second;
    const bool isSwBridge = removedPatch.isSoftware();
    const struct audio_patch &patch = removedPatch.mAudioPatch;

    const struct audio_port_config &src = patch.sources[0];
@@ -791,15 +816,31 @@ status_t PatchPanel::releaseAudioPatch_l(audio_patch_handle_t handle)
                    break;
                }
            }
            // Check whether the removed patch Hal Handle is used in another non-Endpoint patch.
            // Since this is a non-Endpoint patch, the removed patch is not considered (it is
            // removed later from mPatches).
            if (removedPatch.mIsEndpointPatch) {
                for (auto& p: mPatches) {
                    if (!p.second.mIsEndpointPatch
                            && p.second.mHalHandle == removedPatch.mHalHandle) {
                        ALOGV("%s() Sw Bridge endpoint used existing halHandle=%d, do not release",
                              __func__,  p.second.mHalHandle);
                        doReleasePatch = false;
                        break;
                    }
                }
            }
            if (doReleasePatch) {
                mAfPatchPanelCallback->mutex().unlock();
                status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
                mAfPatchPanelCallback->mutex().lock();
            }
        } break;
        default:
            status = BAD_VALUE;
    }

    erasePatch(handle);
    erasePatch(handle, /* reuseExistingHalPatch= */ !doReleasePatch || isSwBridge);
    return status;
}

+1 −6
Original line number Diff line number Diff line
@@ -5258,14 +5258,9 @@ status_t AudioPolicyManager::releaseAudioPatchInternal(audio_patch_handle_t hand
                return NO_ERROR;
            }
            patchHandle = outputDesc->getPatchHandle();
            // When a Sw bridge is released, the mixer used by this bridge will release its
            // patch at AudioFlinger side. Hence, the mixer audio patch must be recreated
            // Reuse patch handle to force audio flinger removing initial mixer patch removal
            // updating hal patch handle (prevent leaks).
            // While using a HwBridge, force reconsidering device only if not reusing an existing
            // output and no more activity on output (will force to close).
            bool force = sourceDesc->useSwBridge() ||
                    (sourceDesc->canCloseOutput() && !outputDesc->isActive());
            const bool force = sourceDesc->canCloseOutput() && !outputDesc->isActive();
            // APM pattern is to have always outputs opened / patch realized for reachable devices.
            // Update device may result to NONE (empty), coupled with force, it releases the patch.
            // Reconsider device only for cases: