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

Commit 2407ce3d authored by Eric Laurent's avatar Eric Laurent
Browse files

audio flinger: fix wraparound issues in AudioRecord shared audi history implementation

Fix issues with the implementation of the shared audio history record start
point in RecordThread input resampling buffer when indexes wrapround.

Bug: 185972521
Test: atest AudioRecordSharedAudioTest
Change-Id: Idcb664f1253b5a488991b39647c13087fc46b0c4
parent ab113ac8
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ public:
                                audio_input_flags_t flags,
                                track_type type,
                                audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
                                int64_t startTimeMs = -1);
                                int32_t startFrames = -1);
    virtual             ~RecordTrack();
    virtual status_t    initCheck() const;

@@ -110,7 +110,7 @@ public:
            status_t    setPreferredMicrophoneFieldDimension(float zoom);
            status_t    shareAudioHistory(const std::string& sharedAudioPackageName,
                                          int64_t sharedAudioStartMs);
            int64_t     startTimeMs() { return mStartTimeMs; }
            int32_t     startFrames() { return mStartFrames; }

    static  bool        checkServerLatencySupported(
                                audio_format_t format, audio_input_flags_t flags) {
@@ -152,7 +152,7 @@ private:
            // used to enforce OP_RECORD_AUDIO
            sp<OpRecordAudioMonitor>           mOpRecordAudioMonitor;
            std::string                        mSharedAudioPackageName = {};
            int64_t                            mStartTimeMs = -1;
            int32_t                            mStartFrames = -1;
};

// playback track, used by PatchPanel
+43 −23
Original line number Diff line number Diff line
@@ -7932,18 +7932,18 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe

    { // scope for mLock
        Mutex::Autolock _l(mLock);
        long startTimeMs = -1;
        int32_t startFrames = -1;
        if (!mSharedAudioPackageName.empty()
                && mSharedAudioPackageName == checkedIdentity.packageName
                && mSharedAudioSessionId == sessionId
                && captureHotwordAllowed(checkedIdentity)) {
            startTimeMs = mSharedAudioStartMs;
            startFrames = mSharedAudioStartFrames;
        }

        track = new RecordTrack(this, client, attr, sampleRate,
                      format, channelMask, frameCount,
                      nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid,
                      checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startTimeMs);
                      checkedIdentity, *flags, TrackBase::TYPE_DEFAULT, portId, startFrames);

        lStatus = track->initCheck();
        if (lStatus != NO_ERROR) {
@@ -8200,17 +8200,32 @@ status_t AudioFlinger::RecordThread::shareAudioHistory_l(
    if ((hasAudioSession_l(sharedSessionId) & ThreadBase::TRACK_SESSION) == 0) {
        return BAD_VALUE;
    }
    if (sharedAudioStartMs < 0 || sharedAudioStartMs * mSampleRate / 1000 > mRsmpInRear) {

    if (sharedAudioStartMs < 0
        || sharedAudioStartMs > INT64_MAX / mSampleRate) {
        return BAD_VALUE;
    }

    // Current implementation of the input resampling buffer wraps around indexes at 32 bit.
    // As we cannot detect more than one wraparound, only accept values up current write position
    // after one wraparound
    // We assume recent wraparounds on mRsmpInRear only given it is unlikely that the requesting
    // app waits several hours after the start time was computed.
    const int64_t sharedAudioStartFrames = sharedAudioStartMs * mSampleRate / 1000;
    const int32_t sharedOffset = audio_utils::safe_sub_overflow(mRsmpInRear,
          (int32_t)sharedAudioStartFrames);
    if (sharedOffset < 0
          || sharedOffset > mRsmpInFrames) {
      return BAD_VALUE;
    }

    mSharedAudioPackageName = sharedAudioPackageName;
    if (mSharedAudioPackageName.empty()) {
        mSharedAudioSessionId = AUDIO_SESSION_NONE;
        mSharedAudioStartMs = -1;
        mSharedAudioStartFrames = -1;
    } else {
        mSharedAudioSessionId = sharedSessionId;
        mSharedAudioStartMs = sharedAudioStartMs;
        mSharedAudioStartFrames = (int32_t)sharedAudioStartFrames;
    }
    return NO_ERROR;
}
@@ -8357,14 +8372,14 @@ void AudioFlinger::RecordThread::ResamplerBufferProvider::reset()
    mRsmpInUnrel = 0;
    const int32_t rear = recordThread->mRsmpInRear;
    ssize_t deltaFrames = 0;
    if (mRecordTrack->startTimeMs() >= 0) {
        int32_t startFrames = mRecordTrack->startTimeMs() * recordThread->sampleRate()  / 1000;
        // start frame has to be in the past
        //TODO: b/185972521 fix in case rear or startFrames wrap around
        if (startFrames > rear) {
            startFrames = rear;
        }
    if (mRecordTrack->startFrames() >= 0) {
        int32_t startFrames = mRecordTrack->startFrames();
        // Accept a recent wraparound of mRsmpInRear
        if (startFrames <= rear) {
            deltaFrames = rear - startFrames;
        } else {
            deltaFrames = (int32_t)((int64_t)rear + UINT32_MAX + 1 - startFrames);
        }
        // start frame cannot be further in the past than start of resampling buffer
        if ((size_t) deltaFrames > recordThread->mRsmpInFrames) {
            deltaFrames = recordThread->mRsmpInFrames;
@@ -8826,17 +8841,22 @@ int32_t AudioFlinger::RecordThread::getOldestFront_l()
    if (mTracks.size() == 0) {
        return 0;
    }
    //TODO: b/185972521 fix in case of wrap around on one track:
    //  want the max(rear - front) for all tracks.
    int32_t front = INT_MAX;
    int32_t oldestFront = mRsmpInRear;
    int32_t maxFilled = 0;
    for (size_t i = 0; i < mTracks.size(); i++) {
        front = std::min(front, mTracks[i]->mResamplerBufferProvider->getFront());
        int32_t front = mTracks[i]->mResamplerBufferProvider->getFront();
        int32_t filled;
        if (front <= mRsmpInRear) {
            filled = mRsmpInRear - front;
        } else {
            filled = (int32_t)((int64_t)mRsmpInRear + UINT32_MAX + 1 - front);
        }
        if (filled > maxFilled) {
            oldestFront = front;
            maxFilled = filled;
        }
    // discard any audio past the buffer size
    if (audio_utils::safe_add_overflow(front, (int32_t)mRsmpInFrames) < mRsmpInRear) {
        front = audio_utils::safe_sub_overflow(mRsmpInRear, (int32_t)mRsmpInFrames);
    }
    return front;
    return oldestFront;
}

void AudioFlinger::RecordThread::updateFronts_l(int32_t offset)
+1 −1
Original line number Diff line number Diff line
@@ -1863,7 +1863,7 @@ private:
            DeviceDescriptorBaseVector          mOutDevices;

            std::string                         mSharedAudioPackageName = {};
            long                                mSharedAudioStartMs = 0;
            int32_t                             mSharedAudioStartFrames = -1;
            audio_session_t                     mSharedAudioSessionId = AUDIO_SESSION_NONE;
};

+2 −2
Original line number Diff line number Diff line
@@ -2378,7 +2378,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
            audio_input_flags_t flags,
            track_type type,
            audio_port_handle_t portId,
            int64_t startTimeMs)
            int32_t startFrames)
    :   TrackBase(thread, client, attr, sampleRate, format,
                  channelMask, frameCount, buffer, bufferSize, sessionId,
                  creatorPid,
@@ -2396,7 +2396,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(
        mFlags(flags),
        mSilenced(false),
        mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(identity, attr)),
        mStartTimeMs(startTimeMs)
        mStartFrames(startFrames)
{
    if (mCblk == NULL) {
        return;