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

Commit a134b006 authored by Kevin Rocard's avatar Kevin Rocard
Browse files

Audioflinger intercept track retry on buffer end

Track::interceptBuffer failed to write all the audio if the source BP
could not returned the requested buffer size.
This is actually normal when the source circular buffer wraps around.

Handle it by retrying if the first buffer is too small.

Test: adb shell audiorecorder --target /data/file.raw
Bug: 111453086
Change-Id: I42a7962449a0f075909a29f5f8f5ba82ca1d0085
parent 2ec06741
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -222,6 +222,8 @@ protected:

private:
    void                interceptBuffer(const AudioBufferProvider::Buffer& buffer);
    /** Write the source data in the buffer provider. @return written frame count. */
    size_t              writeFrames(AudioBufferProvider* dest, const void* src, size_t frameCount);
    template <class F>
    void                forEachTeePatchTrack(F f) {
        for (auto& tp : mTeePatches) { f(tp.patchTrack); }
+33 −17
Original line number Diff line number Diff line
@@ -697,26 +697,42 @@ void AudioFlinger::PlaybackThread::Track::releaseBuffer(AudioBufferProvider::Buf

// TODO: compensate for time shift between HW modules.
void AudioFlinger::PlaybackThread::Track::interceptBuffer(
        const AudioBufferProvider::Buffer& buffer) {
        const AudioBufferProvider::Buffer& sourceBuffer) {
    const size_t frameCount = sourceBuffer.frameCount;
    for (auto& sink : mTeePatches) {
        RecordThread::PatchRecord& patchRecord = *sink.patchRecord;
        RecordThread::PatchRecord* patchRecord = sink.patchRecord.get();

        size_t framesWritten = writeFrames(patchRecord, sourceBuffer.i8, frameCount);
        // On buffer wrap, the buffer frame count will be less than requested,
        // when this happens a second buffer needs to be used to write the leftover audio
        size_t framesLeft = frameCount - framesWritten;
        if (framesWritten != 0 && framesLeft != 0) {
            framesWritten +=
                writeFrames(patchRecord, sourceBuffer.i8 + framesWritten * mFrameSize, framesLeft);
            framesLeft = frameCount - framesWritten;
        }
        ALOGW_IF(framesLeft != 0, "%s(%d) PatchRecord %d can not provide big enough "
                 "buffer %zu/%zu, dropping %zu frames", __func__, mId, patchRecord->mId,
                 framesWritten, frameCount, framesLeft);
    }
}

size_t AudioFlinger::PlaybackThread::Track::writeFrames(AudioBufferProvider* dest,
                                                        const void* src,
                                                        size_t frameCount) {
    AudioBufferProvider::Buffer patchBuffer;
        patchBuffer.frameCount = buffer.frameCount;
        auto status = patchRecord.getNextBuffer(&patchBuffer);
    patchBuffer.frameCount = frameCount;
    auto status = dest->getNextBuffer(&patchBuffer);
    if (status != NO_ERROR) {
       ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
             __func__, status, strerror(-status));
           continue;
        }
        // FIXME: On buffer wrap, the frame count will be less then requested,
        //        retry to write the rest. (unlikely due to lcm buffer sizing)
        ALOGW_IF(patchBuffer.frameCount != buffer.frameCount,
                 "%s PatchRecord can not provide big enough buffer %zu/%zu, dropping %zu frames",
                 __func__, patchBuffer.frameCount, buffer.frameCount,
                 buffer.frameCount - patchBuffer.frameCount);
        memcpy(patchBuffer.raw, buffer.raw, patchBuffer.frameCount * mFrameSize);
        patchRecord.releaseBuffer(&patchBuffer);
       return 0;
    }
    ALOG_ASSERT(patchBuffer.frameCount <= frameCount);
    memcpy(patchBuffer.raw, src, patchBuffer.frameCount * mFrameSize);
    auto framesWritten = patchBuffer.frameCount;
    dest->releaseBuffer(&patchBuffer);
    return framesWritten;
}

// releaseBuffer() is not overridden