Merge "Audioflinger intercept track retry on buffer end"
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 3f62bc3..94ea042 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -222,6 +222,8 @@
 
 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); }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 57dd568..922547d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -697,28 +697,44 @@
 
 // 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;
-        AudioBufferProvider::Buffer patchBuffer;
-        patchBuffer.frameCount = buffer.frameCount;
-        auto status = patchRecord.getNextBuffer(&patchBuffer);
-        if (status != NO_ERROR) {
-           ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
-                 __func__, status, strerror(-status));
-           continue;
+        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;
         }
-        // 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);
+        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 = frameCount;
+    auto status = dest->getNextBuffer(&patchBuffer);
+    if (status != NO_ERROR) {
+       ALOGW("%s PathRecord getNextBuffer failed with error %d: %s",
+             __func__, status, strerror(-status));
+       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
 
 // ExtendedAudioBufferProvider interface