Add tee sink to SpdifStreamOut

Test: enable per https://source.android.com/docs/core/audio/debugging
      play ac3 track via SpdifStreamOut using
      AudioTrackSurroundTest#testPlayAC3Bytes
      dumpsys media.audio_flinger and see .raw iec61937 wrapped
      file in /data/misc/audioserver.
Change-Id: I65ccd9d8a5b92ef7ffc87e081095d8f7332d8acb
diff --git a/services/audioflinger/afutils/NBAIO_Tee.cpp b/services/audioflinger/afutils/NBAIO_Tee.cpp
index 49057ce..86fb128 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.cpp
+++ b/services/audioflinger/afutils/NBAIO_Tee.cpp
@@ -43,6 +43,7 @@
  "aftee_Date_ThreadId_C_reason.wav" RecordThread
  "aftee_Date_ThreadId_M_reason.wav" MixerThread (Normal)
  "aftee_Date_ThreadId_F_reason.wav" MixerThread (Fast)
+ "aftee_Date_ThreadId_D_reason.raw" DirectOutputThread (SpdifStreamOut)
  "aftee_Date_ThreadId_TrackId_R_reason.wav" RecordTrack
  "aftee_Date_ThreadId_TrackId_TrackName_T_reason.wav" PlaybackTrack
 
@@ -120,7 +121,7 @@
         return directory.size() > 0 && directory[0] == '/';
     }
 
-    std::string generateFilename(const std::string &suffix) const {
+    std::string generateFilename(const std::string &suffix, audio_format_t format) const {
         char fileTime[sizeof("YYYYmmdd_HHMMSS_\0")];
         struct timeval tv;
         gettimeofday(&tv, nullptr /* struct timezone */);
@@ -130,7 +131,7 @@
             "incorrect fileTime buffer");
         char msec[4];
         (void)snprintf(msec, sizeof(msec), "%03d", (int)(tv.tv_usec / 1000));
-        return mPrefix + fileTime + msec + suffix + ".wav";
+        return mPrefix + fileTime + msec + suffix + (audio_is_linear_pcm(format) ? ".wav" : ".raw");
     }
 
     bool isManagedFilename(const char *name) {
@@ -225,7 +226,7 @@
 NBAIO_Tee::NBAIO_TeeImpl::NBAIO_SinkSource NBAIO_Tee::NBAIO_TeeImpl::makeSinkSource(
         const NBAIO_Format &format, size_t frames, bool *enabled)
 {
-    if (Format_isValid(format) && audio_is_linear_pcm(format.mFormat)) {
+    if (Format_isValid(format) && audio_has_proportional_frames(format.mFormat)) {
         Pipe *pipe = new Pipe(frames, format);
         size_t numCounterOffers = 0;
         const NBAIO_Format offers[1] = {format};
@@ -259,7 +260,7 @@
         audio_format_t format,
         const std::string &suffix)
 {
-    std::string filename = generateFilename(suffix);
+    std::string filename = generateFilename(suffix, format);
 
     if (mThreadPool.launch(std::string("create ") + filename,
             [=]() { return createInternal(reader, sampleRate, channelCount, format, filename); })
@@ -406,6 +407,7 @@
     switch (format) {
     case AUDIO_FORMAT_PCM_8_BIT:
     case AUDIO_FORMAT_PCM_16_BIT:
+    case AUDIO_FORMAT_IEC61937:
         sf_format = SF_FORMAT_PCM_16;
         writeFormat = AUDIO_FORMAT_PCM_16_BIT;
         ALOGV("%s: %s using PCM_16 for format %#x", __func__, filename.c_str(), format);
@@ -424,7 +426,6 @@
         break;
     default:
         // TODO:
-        // handle audio_has_proportional_frames() formats.
         // handle compressed formats as single byte files.
         return BAD_VALUE;
     }
@@ -440,7 +441,7 @@
         .frames = 0,
         .samplerate = (int)sampleRate,
         .channels = (int)channelCount,
-        .format = SF_FORMAT_WAV | sf_format,
+        .format = sf_format | (audio_is_linear_pcm(format) ? SF_FORMAT_WAV : 0 /* RAW */),
     };
     SNDFILE *sf = sf_open(path.c_str(), SFM_WRITE, &info);
     if (sf == nullptr) {
@@ -463,7 +464,7 @@
         }
 
         // Convert input format to writeFormat as needed.
-        if (format != writeFormat) {
+        if (format != writeFormat && audio_is_linear_pcm(format)) {
             memcpy_by_audio_format(
                     buffer, writeFormat, buffer, format, actualRead * info.channels);
         }
diff --git a/services/audioflinger/afutils/NBAIO_Tee.h b/services/audioflinger/afutils/NBAIO_Tee.h
index 17b6175..1133671 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.h
+++ b/services/audioflinger/afutils/NBAIO_Tee.h
@@ -48,7 +48,7 @@
  *
  * Some AudioFlinger specific notes:
  *
- * 1) Tees capture only linear PCM data.
+ * 1) Tees capture only linear PCM or IEC61937 data.
  * 2) Tees without any data written are considered empty and do not generate
  *    any output files.
  * 2) Once a Tee dumps data, it is considered "emptied" and new data
@@ -58,6 +58,7 @@
  *    WAV integer PCM 32 bit for AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED
  *                               AUDIO_FORMAT_PCM_32_BIT.
  *    WAV float PCM 32 bit for AUDIO_FORMAT_PCM_FLOAT.
+ *    RAW for AUDIO_FORMAT_IEC61937.
  *
  * Input_Thread:
  * 1) Capture buffer is teed when read from the HAL, before resampling for the AudioRecord
@@ -68,8 +69,8 @@
  *    NormalMixer output (if no FastMixer).
  * 2) DuplicatingThreads do not tee any mixed data. Apply a tee on the downstream OutputTrack
  *    or on the upstream playback Tracks.
- * 3) DirectThreads and OffloadThreads do not tee any data. The upstream track
- *    (if linear PCM format) may be teed to discover data.
+ * 3) DirectThreads and OffloadThreads with SpdifStreamOut will tee IEC61937 wrapped data.
+ *    Otherwise, the upstream track (if linear PCM format) may be teed to discover data.
  * 4) MmapThreads are not supported.
  *
  * Tracks:
diff --git a/services/audioflinger/datapath/Android.bp b/services/audioflinger/datapath/Android.bp
index 58f0422..ee98aef 100644
--- a/services/audioflinger/datapath/Android.bp
+++ b/services/audioflinger/datapath/Android.bp
@@ -55,10 +55,18 @@
     shared_libs: [
         "audioclient-types-aidl-cpp",
         "av-types-aidl-cpp",
+        "libaudioflinger_utils", // NBAIO_Tee
+        "libaudioprocessing",
         "libaudiospdif",
         "libaudioutils",
         "libbase",
+        "libcutils",
         "liblog",
+        "libnbaio",
         "libutils", // refbase
     ],
+
+    include_dirs: [
+        "frameworks/av/services/audioflinger",  // for configuration
+    ],
 }
diff --git a/services/audioflinger/datapath/SpdifStreamOut.cpp b/services/audioflinger/datapath/SpdifStreamOut.cpp
index 43e9c0c..6bc1f2d 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.cpp
+++ b/services/audioflinger/datapath/SpdifStreamOut.cpp
@@ -17,6 +17,7 @@
 
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
+#include "Configuration.h"
 #include <system/audio.h>
 #include <utils/Log.h>
 
@@ -96,6 +97,16 @@
 
     ALOGI("SpdifStreamOut::open() status = %d", status);
 
+#ifdef TEE_SINK
+    if (status == OK) {
+        // Don't use PCM 16-bit format to avoid WAV encoding IEC61937 data.
+        mTee.set(customConfig.sample_rate,
+                audio_channel_count_from_out_mask(customConfig.channel_mask),
+                AUDIO_FORMAT_IEC61937, NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
+        mTee.setId(std::string("_") + std::to_string(handle) + "_D");
+    }
+#endif
+
     return status;
 }
 
@@ -113,7 +124,15 @@
 
 ssize_t SpdifStreamOut::writeDataBurst(const void* buffer, size_t bytes)
 {
-    return AudioStreamOut::write(buffer, bytes);
+    const ssize_t written = AudioStreamOut::write(buffer, bytes);
+
+#ifdef TEE_SINK
+    if (written > 0) {
+        mTee.write(reinterpret_cast<const char *>(buffer),
+                written / AudioStreamOut::getFrameSize());
+    }
+#endif
+    return written;
 }
 
 ssize_t SpdifStreamOut::write(const void* buffer, size_t numBytes)
diff --git a/services/audioflinger/datapath/SpdifStreamOut.h b/services/audioflinger/datapath/SpdifStreamOut.h
index c8dc89f..1640575 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.h
+++ b/services/audioflinger/datapath/SpdifStreamOut.h
@@ -25,6 +25,7 @@
 
 #include "AudioStreamOut.h"
 
+#include <afutils/NBAIO_Tee.h>
 #include <audio_utils/spdif/SPDIFEncoder.h>
 
 namespace android {
@@ -116,6 +117,10 @@
     ssize_t  writeDataBurst(const void* data, size_t bytes);
     ssize_t  writeInternal(const void* buffer, size_t bytes);
 
+#ifdef TEE_SINK
+    NBAIO_Tee mTee;
+#endif
+
 };
 
 } // namespace android