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

Commit 7e39df23 authored by François Gaffie's avatar François Gaffie Committed by Eric Laurent
Browse files

[BUG] AudioPolicy: fix AudioDeviceCallback



This CL fixes the AudioDeviceCallback that may report null device.
When an output is reused by a SwBridge, upon release of SW bridge patch,
releasing the patch of the Playback PatchTrack associated with the mixer thread
will clear its patch and output devices.
As the patch created for this output may not be recreated by AudioPolicyManager
if routing does not change (same device or none if no activity on output),
the device will not be updated, hence the AudioDeviceCallback will report null
device.
AudioPolicy will now force to recreate the output patch with same
handle and valid when the SwBridge is released.
 AudioFlinger will erase previous mixer output patch and reuse
hal patch handle to recreate/update the hal audio patch.

Test: run a SwBridge audio use case on primary output (e.g. FM Radio),
stop it, then play a stream on primary output.
Ensure AudioDeviceCallback is called with non null device.

Signed-off-by: default avatarFrancois Gaffie <francois.gaffie@renault.com>
Change-Id: I0b4f852280046cc596da9194cab4655316a026a4
parent 0e4ee16a
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -239,12 +239,13 @@ public:
    }
    void setUseSwBridge() { mUseSwBridge = true; }
    bool useSwBridge() const { return mUseSwBridge; }
    bool canCloseOutput() const { return mCloseOutput; }
    bool isConnected() const { return mPatchHandle != AUDIO_PATCH_HANDLE_NONE; }
    audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
    sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
    sp<DeviceDescriptor> sinkDevice() const { return mSinkDevice; }
    wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
    void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
    void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput, bool closeOutput = false);
    wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
    void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);

@@ -258,6 +259,15 @@ public:
    wp<SwAudioOutputDescriptor> mSwOutput;
    wp<HwAudioOutputDescriptor> mHwOutput;
    bool mUseSwBridge = false;
    /**
     * For either HW bridge associated to a SwOutput for activity / volume or SwBridge for also
     * sample rendering / activity & volume, an existing playback thread may be reused (e.g.
     * not already opened at APM startup or Direct Output).
     * If reusing an already opened output, when this output is not used anymore, the AudioFlinger
     * patch must be updated to refine the output device(s) information and ensure the right
     * behavior of AudioDeviceCallback.
     */
    bool mCloseOutput = false;
};

/**
+3 −1
Original line number Diff line number Diff line
@@ -105,9 +105,11 @@ SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t
{
}

void SourceClientDescriptor::setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput)
void SourceClientDescriptor::setSwOutput(
        const sp<SwAudioOutputDescriptor>& swOutput, bool closeOutput)
{
    mSwOutput = swOutput;
    mCloseOutput = closeOutput;
}

void SourceClientDescriptor::setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput)
+26 −13
Original line number Diff line number Diff line
@@ -4539,7 +4539,8 @@ status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *
                        ALOGE("%s output is duplicated", __func__);
                        return INVALID_OPERATION;
                    }
                    sourceDesc->setSwOutput(outputDesc);
                    bool closeOutput = outputDesc->mDirectOpenCount != 0;
                    sourceDesc->setSwOutput(outputDesc, closeOutput);
                } else {
                    // Same for "raw patches" aka created from createAudioPatch API
                    SortedVector<audio_io_handle_t> outputs =
@@ -4558,7 +4559,7 @@ status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *
                              __func__, sinkDevice->toString().c_str());
                        return INVALID_OPERATION;
                    }
                    sourceDesc->setSwOutput(outputDesc);
                    sourceDesc->setSwOutput(outputDesc, /* closeOutput= */ false);
                }
                // create a software bridge in PatchPanel if:
                // - source and sink devices are on different HW modules OR
@@ -4687,17 +4688,29 @@ status_t AudioPolicyManager::releaseAudioPatchInternal(audio_patch_handle_t hand
                // releaseOutput has already called closeOutput in case of direct output
                return NO_ERROR;
            }
            if (!outputDesc->isActive() && !sourceDesc->useSwBridge()) {
                resetOutputDevice(outputDesc);
            } else {
                // Reuse patch handle if still valid / do not force rerouting if still routed
            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());
            // 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:
            //      1 / Active Output
            //      2 / Inactive Output previously hosting HwBridge
            //      3 / Inactive Output previously hosting SwBridge that can be closed.
            bool updateDevice = outputDesc->isActive() || !sourceDesc->useSwBridge() ||
                    sourceDesc->canCloseOutput();
            setOutputDevices(outputDesc,
                                 getNewOutputDevices(outputDesc, true /*fromCache*/),
                                 patchHandle == AUDIO_PATCH_HANDLE_NONE, /*force*/
                             updateDevice ? getNewOutputDevices(outputDesc, true /*fromCache*/) :
                                            outputDesc->devices(),
                             force,
                             0,
                             patchHandle == AUDIO_PATCH_HANDLE_NONE ? nullptr : &patchHandle);
            }
        } else {
            return BAD_VALUE;
        }