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

Commit 64265b2f authored by Eric Laurent's avatar Eric Laurent
Browse files

audio policy: fix preemtible capture race

Because a preemtible capture session can preempt another one,
we end up in an endless loop situation were each session is allowed to restart
after being preempted, thus preempting the other one which restarts and so on.

To avoid this situation, we store which audio session was preempted when
a particular input started and prevent preemption of this active input by this session.
We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...

Bug: 24007220.
Change-Id: I0eab5299440ef3ab9e987635dc9a300cf42f2c79
parent 6fe78a87
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -56,9 +56,21 @@ public:
            const struct audio_port_config *srcConfig = NULL) const;
    virtual sp<AudioPort> getAudioPort() const { return mProfile; }
    void toAudioPort(struct audio_port *port) const;
    void setPreemptedSessions(const SortedVector<audio_session_t>& sessions);
    SortedVector<audio_session_t> getPreemptedSessions() const;
    bool hasPreemptedSession(audio_session_t session) const;
    void clearPreemptedSessions();

private:
    audio_port_handle_t           mId;
    // Because a preemtible capture session can preempt another one, we end up in an endless loop
    // situation were each session is allowed to restart after being preempted,
    // thus preempting the other one which restarts and so on.
    // To avoid this situation, we store which audio session was preempted when
    // a particular input started and prevent preemption of this active input by this session.
    // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
    SortedVector<audio_session_t> mPreemptedSessions;

};

class AudioInputCollection :
+20 −0
Original line number Diff line number Diff line
@@ -93,6 +93,26 @@ void AudioInputDescriptor::toAudioPort(struct audio_port *port) const
    port->ext.mix.latency_class = AUDIO_LATENCY_NORMAL;
}

void AudioInputDescriptor::setPreemptedSessions(const SortedVector<audio_session_t>& sessions)
{
    mPreemptedSessions = sessions;
}

SortedVector<audio_session_t> AudioInputDescriptor::getPreemptedSessions() const
{
    return mPreemptedSessions;
}

bool AudioInputDescriptor::hasPreemptedSession(audio_session_t session) const
{
    return (mPreemptedSessions.indexOf(session) >= 0);
}

void AudioInputDescriptor::clearPreemptedSessions()
{
    mPreemptedSessions.clear();
}

status_t AudioInputDescriptor::dump(int fd)
{
    const size_t SIZE = 256;
+9 −3
Original line number Diff line number Diff line
@@ -1485,10 +1485,15 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
            // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
            // otherwise the active input continues and the new input cannot be started.
            sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
            if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
            if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) &&
                    !activeDesc->hasPreemptedSession(session)) {
                ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
                stopInput(activeInput, activeDesc->mSessions.itemAt(0));
                releaseInput(activeInput, activeDesc->mSessions.itemAt(0));
                audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
                SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
                sessions.add(activeSession);
                inputDesc->setPreemptedSessions(sessions);
                stopInput(activeInput, activeSession);
                releaseInput(activeInput, activeSession);
            } else {
                ALOGE("startInput(%d) failed: other input %d already started", input, activeInput);
                return INVALID_OPERATION;
@@ -1592,6 +1597,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
        if (mInputs.activeInputsCount() == 0) {
            SoundTrigger::setCaptureState(false);
        }
        inputDesc->clearPreemptedSessions();
    }
    return NO_ERROR;
}