Add secondary output to audio tracks

The secondary are returned from mixes (from DAP loopback&render),
from getOutputForAttr.
All getOutputForAttr* of the stack are update.
Internal getOutputForAttr use descriptor, external one use handles.

The secondary output are saved in each track and the track is
invalidated if the list of secondary output changes.

In audio flinger, create a pair of recordTrack & patchTrack to pipe
the intercepted audio audio to the secondary output.

Test: adb shell audiorecorder --target /data/file.raw
Bug: 111453086
Change-Id: Id6523d9e383c15a0e39313d5f355df809b7e72fe
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 863dc9e..37c3a2d 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -99,7 +99,7 @@
         mId(android_atomic_inc(&nextTrackId)),
         mTerminated(false),
         mType(type),
-        mThreadIoHandle(thread->id()),
+        mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
         mPortId(portId),
         mIsInvalid(false)
 {
@@ -670,8 +670,7 @@
 }
 
 // AudioBufferProvider interface
-status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
-        AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
 {
     ServerProxy::Buffer buf;
     size_t desiredFrames = buffer->frameCount;
@@ -686,10 +685,39 @@
     } else {
         mAudioTrackServerProxy->tallyUnderrunFrames(0);
     }
-
     return status;
 }
 
+void AudioFlinger::PlaybackThread::Track::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+{
+    interceptBuffer(*buffer);
+    TrackBase::releaseBuffer(buffer);
+}
+
+// TODO: compensate for time shift between HW modules.
+void AudioFlinger::PlaybackThread::Track::interceptBuffer(
+        const AudioBufferProvider::Buffer& buffer) {
+    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;
+        }
+        // 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);
+    }
+}
+
 // releaseBuffer() is not overridden
 
 // ExtendedAudioBufferProvider interface
@@ -1081,6 +1109,10 @@
     };
 }
 
+void AudioFlinger::PlaybackThread::Track::setTeePatches(TeePatches teePatches) {
+    mTeePatches = std::move(teePatches);
+}
+
 status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
 {
     if (!isOffloaded() && !isDirect()) {