[audio][eac3] Support EAC3 with small frames

EAC3 can have 1,2,3 or 6 audio blocks per sync frame.
The old code only supported 6 audio blocks per sync frame.
So streams with fewer blocks were not aligned correctly
in the SPDIF data burst. See IEC61937-3 spec P5.3.3.

The code now tracks how many blocks have been accumulated
for each possible substream.

Bug: 18315783
Change-Id: I75dbedeb69a597a877b2b68c6be23c831ae119b6
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/audio_utils/include/audio_utils/spdif/FrameScanner.h b/audio_utils/include/audio_utils/spdif/FrameScanner.h
index f1f2cd1..ff245e4 100644
--- a/audio_utils/include/audio_utils/spdif/FrameScanner.h
+++ b/audio_utils/include/audio_utils/spdif/FrameScanner.h
@@ -74,13 +74,10 @@
     virtual int getDataType()      const { return mDataType; }
     virtual int getDataTypeInfo()  const { return mDataTypeInfo; }
 
-    /**
-     * lengthCode is defined by the SPDIF standard
-     * @return length of the frame in bits or bytes, depending on the format.
-     */
-    virtual int getLengthCode()  const = 0;
     virtual int getMaxChannels() const = 0;
 
+    virtual void resetBurst() = 0;
+
     /**
      * @return the number of pcm frames that correspond to one encoded frame
      */
@@ -113,6 +110,7 @@
 #define EAC3_RATE_MULTIPLIER                       4
 #define EAC3_NUM_SAMPLE_RATE_TABLE_ENTRIES         3
 #define EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES   38
+#define EAC3_MAX_SUBSTREAMS                        8
 
 class AC3FrameScanner : public FrameScanner
 {
@@ -127,7 +125,6 @@
 
     virtual int getDataType()      const { return mDataType; }
     virtual int getDataTypeInfo()  const { return 0; }
-    virtual int getLengthCode()    const { return mLengthCode; }
     virtual int getMaxChannels()   const { return 5 + 1; }
 
     virtual int getMaxSampleFramesPerSyncFrame() const { return EAC3_RATE_MULTIPLIER
@@ -136,6 +133,7 @@
 
     virtual bool isFirstInBurst();
     virtual bool isLastInBurst();
+    virtual void resetBurst();
 
 protected:
 
@@ -152,7 +150,7 @@
     State    mState;
     uint32_t mBytesSkipped;
     uint8_t  mHeaderBuffer[6];
-    int      mLengthCode;
+    uint8_t  mSubstreamBlockCounts[EAC3_MAX_SUBSTREAMS];
     int      mAudioBlocksPerSyncFrame;
     uint     mCursor;
     uint     mStreamType;
diff --git a/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
index 24b6074..b880a93 100644
--- a/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
+++ b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
@@ -37,14 +37,22 @@
     SPDIFEncoder();
     virtual ~SPDIFEncoder();
 
+    // Write encoded data to be wrapped for SPDIF.
+    // The compressed frames do not have to be aligned.
     ssize_t write( const void* buffer, size_t numBytes );
 
     // Called by SPDIFEncoder when it is ready to output a data burst.
     // Must be implemented by caller.
     virtual ssize_t writeOutput( const void* buffer, size_t numBytes ) = 0;
 
+    // Get ration of the encoded data burst sample rate to the encoded rate.
+    // For example, EAC3 data bursts are 4X the encoded rate.
     uint32_t getRateMultiplier() const { return mRateMultiplier; }
+
+    // Return the number of PCM frames in a data burst.
     uint32_t getBurstFrames() const { return mBurstFrames; }
+
+    // Return number of bytes per PCM frame for the data burst.
     int      getBytesPerOutputFrame();
 
 protected:
@@ -54,7 +62,8 @@
     void   writeBurstBufferBytes(const uint8_t* buffer, size_t numBytes);
     void   sendZeroPad();
     void   flushBurstBuffer();
-    size_t startDataBurst();
+    void   startDataBurst();
+    size_t startSyncFrame();
 
     // State machine states.
     enum State {
diff --git a/audio_utils/spdif/FrameScanner.cpp b/audio_utils/spdif/FrameScanner.cpp
index f12e538..5a6e21f 100644
--- a/audio_utils/spdif/FrameScanner.cpp
+++ b/audio_utils/spdif/FrameScanner.cpp
@@ -15,7 +15,7 @@
 ** limitations under the License.
 */
 
-#define LOG_TAG "AudioHardwareTungsten"
+#define LOG_TAG "AudioSPDIF"
 
 #include <utils/Log.h>
 #include <audio_utils/spdif/FrameScanner.h>
@@ -104,13 +104,13 @@
  : FrameScanner(SPDIF_DATA_TYPE_AC3)
  , mState(STATE_EXPECTING_SYNC_1)
  , mBytesSkipped(0)
- , mLengthCode(0)
  , mAudioBlocksPerSyncFrame(6)
  , mCursor(AC3_SYNCWORD_SIZE) // past sync word
  , mStreamType(0)
  , mSubstreamID(0)
  , mFormatDumpCount(0)
 {
+    memset(mSubstreamBlockCounts, 0, sizeof(mSubstreamBlockCounts));
     // Define beginning of syncinfo for getSyncAddress()
     mHeaderBuffer[0] = kAC3SyncByte1;
     mHeaderBuffer[1] = kAC3SyncByte2;
@@ -125,14 +125,36 @@
     return mRateMultiplier * AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * AC3_PCM_FRAMES_PER_BLOCK;
 }
 
+void AC3FrameScanner::resetBurst()
+{
+    for (int i = 0; i < EAC3_MAX_SUBSTREAMS; i++) {
+        if (mSubstreamBlockCounts[i] >= AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK) {
+            mSubstreamBlockCounts[i] -= AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK;
+        } else if (mSubstreamBlockCounts[i] > 0) {
+            ALOGW("EAC3 substream[%d] has only %d audio blocks!",
+                i, mSubstreamBlockCounts[i]);
+            mSubstreamBlockCounts[i] = 0;
+        }
+    }
+}
+
 // per IEC 61973-3 Paragraph 5.3.3
+// We have to send 6 audio blocks on all active substreams.
+// Substream zero must be the first.
+// We don't know if we have all the blocks we need until we see
+// the 7th block of substream#0.
 bool AC3FrameScanner::isFirstInBurst()
 {
     if (mDataType == SPDIF_DATA_TYPE_E_AC3) {
-        return (((mStreamType == 0) || (mStreamType == 2)) && (mSubstreamID == 0));
-    } else {
-        return false; // For AC3 just flush at end.
+        if (((mStreamType == 0) || (mStreamType == 2))
+            && (mSubstreamID == 0)
+            // The ">" is intentional. We have to see the beginning of the block
+            // in the next burst before we can send the current burst.
+            && (mSubstreamBlockCounts[0] > AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK)) {
+            return true;
+        }
     }
+    return false;
 }
 
 bool AC3FrameScanner::isLastInBurst()
@@ -165,14 +187,9 @@
     // The names fscod, frmsiz are from the AC3 spec.
     int fscod = mHeaderBuffer[4] >> 6;
     if (mDataType == SPDIF_DATA_TYPE_E_AC3) {
-        mStreamType = mHeaderBuffer[2] >> 6;
+        mStreamType = mHeaderBuffer[2] >> 6; // strmtyp in spec
         mSubstreamID = (mHeaderBuffer[2] >> 3) & 0x07;
 
-        // Print enough so we can see all the substreams.
-        ALOGD_IF((mFormatDumpCount < 3*8 ),
-                "EAC3 strmtyp = %d, substreamid = %d",
-                mStreamType, mSubstreamID);
-
         // Frame size is explicit in EAC3. Paragraph E2.3.1.3
         int frmsiz = ((mHeaderBuffer[2] & 0x07) << 8) + mHeaderBuffer[3];
         mFrameSizeBytes = (frmsiz + 1) * sizeof(int16_t);
@@ -191,8 +208,17 @@
             numblkscod = (mHeaderBuffer[4] >> 4) & 0x03;
         }
         mRateMultiplier = EAC3_RATE_MULTIPLIER; // per IEC 61973-3 Paragraph 5.3.3
-        // TODO Don't send data burst until we have 6 blocks per substream.
+        // Don't send data burst until we have 6 blocks per substream.
         mAudioBlocksPerSyncFrame = kEAC3BlocksPerFrameTable[numblkscod];
+        // Keep track of how many audio blocks we have for each substream.
+        // This should be safe because mSubstreamID is ANDed with 0x07 above.
+        // And the array is allocated as [8].
+        mSubstreamBlockCounts[mSubstreamID] += mAudioBlocksPerSyncFrame;
+
+        // Print enough so we can see all the substreams.
+        ALOGD_IF((mFormatDumpCount < 3*8 ),
+                "EAC3 mStreamType = %d, mSubstreamID = %d",
+                mStreamType, mSubstreamID);
     } else { // regular AC3
         // Extract sample rate and frame size from codes.
         unsigned int frmsizcod = mHeaderBuffer[4] & 0x3F; // frame size code
@@ -211,7 +237,6 @@
         }
         mAudioBlocksPerSyncFrame = 6;
     }
-    mLengthCode = 8 * mFrameSizeBytes; // size in bits
     ALOGI_IF((mFormatDumpCount == 0),
             "AC3 frame rate = %d * %d, size = %d, audioBlocksPerSyncFrame = %d\n",
             mSampleRate, mRateMultiplier, mFrameSizeBytes, mAudioBlocksPerSyncFrame);
diff --git a/audio_utils/spdif/SPDIFEncoder.cpp b/audio_utils/spdif/SPDIFEncoder.cpp
index 07a1800..df39f14 100644
--- a/audio_utils/spdif/SPDIFEncoder.cpp
+++ b/audio_utils/spdif/SPDIFEncoder.cpp
@@ -18,7 +18,7 @@
 
 #include <stdint.h>
 
-#define LOG_TAG "AudioHardwareTungsten"
+#define LOG_TAG "AudioSPDIF"
 #include <utils/Log.h>
 #include <audio_utils/spdif/SPDIFEncoder.h>
 
@@ -48,8 +48,9 @@
     mBurstBufferSizeBytes = sizeof(uint16_t)
             * SPDIF_ENCODED_CHANNEL_COUNT
             * mFramer->getMaxSampleFramesPerSyncFrame();
+
     ALOGI("SPDIFEncoder: mBurstBufferSizeBytes = %d, littleEndian = %d",
-        mBurstBufferSizeBytes, isLittleEndian());
+            mBurstBufferSizeBytes, isLittleEndian());
     mBurstBuffer = new uint16_t[mBurstBufferSizeBytes >> 1];
     clearBurstBuffer();
 }
@@ -116,22 +117,29 @@
     size_t burstSize = mFramer->getSampleFramesPerSyncFrame() * sizeof(uint16_t)
             * SPDIF_ENCODED_CHANNEL_COUNT;
     if (mByteCursor > burstSize) {
-        ALOGE("SPDIFEncoder: Burst buffer, contents too large!\n");
+        ALOGE("SPDIFEncoder: Burst buffer, contents too large!");
         clearBurstBuffer();
     } else {
         // We don't have to write zeros because buffer already set to zero
-        // by clearBurstBuffer().
+        // by clearBurstBuffer(). Just pretend we wrote zeros by
+        // incrementing cursor.
         mByteCursor = burstSize;
     }
 }
 
 void SPDIFEncoder::flushBurstBuffer()
 {
-    if (mByteCursor > 0) {
+    const int preambleSize = 4 * sizeof(uint16_t);
+    if (mByteCursor > preambleSize) {
+        // Set number of bits for valid payload before zeroPad.
+        uint16_t lengthCode = (mByteCursor - preambleSize) * 8;
+        mBurstBuffer[3] = lengthCode;
+
         sendZeroPad();
         writeOutput(mBurstBuffer, mByteCursor);
-        clearBurstBuffer();
     }
+    clearBurstBuffer();
+    mFramer->resetBurst();
 }
 
 void SPDIFEncoder::clearBurstBuffer()
@@ -142,7 +150,7 @@
     mByteCursor = 0;
 }
 
-size_t SPDIFEncoder::startDataBurst()
+void SPDIFEncoder::startDataBurst()
 {
     // Encode IEC61937-1 Burst Preamble
     uint16_t preamble[4];
@@ -156,14 +164,15 @@
     preamble[0] = kSPDIFSync1;
     preamble[1] = kSPDIFSync2;
     preamble[2] = burstInfo;
-    preamble[3] = mFramer->getLengthCode();
+    preamble[3] = 0; // lengthCode - This will get set after the buffer is full.
     writeBurstBufferShorts(preamble, 4);
+}
 
+size_t SPDIFEncoder::startSyncFrame()
+{
     // Write start of encoded frame that was buffered in frame detector.
     size_t syncSize = mFramer->getHeaderSizeBytes();
     writeBurstBufferBytes(mFramer->getHeaderAddress(), syncSize);
-    ALOGV("SPDIFEncoder: startDataBurst, syncSize = %u, lengthCode = %d",
-        syncSize, mFramer->getLengthCode());
     return mFramer->getFrameSizeBytes() - syncSize;
 }
 
@@ -177,14 +186,17 @@
     while (bytesLeft > 0) {
         State nextState = mState;
         switch (mState) {
-        // Look for beginning of encoded frame.
+        // Look for beginning of next encoded frame.
         case STATE_IDLE:
             if (mFramer->scan(*data)) {
-                if (mFramer->isFirstInBurst()) {
+                if (mByteCursor == 0) {
+                    startDataBurst();
+                } else if (mFramer->isFirstInBurst()) {
                     // Make sure that this frame is at the beginning of the data burst.
                     flushBurstBuffer();
+                    startDataBurst();
                 }
-                mPayloadBytesPending = startDataBurst();
+                mPayloadBytesPending = startSyncFrame();
                 nextState = STATE_BURST;
             }
             data++;
@@ -208,7 +220,6 @@
                 // If we have all the payload then send a data burst.
                 if (mPayloadBytesPending == 0) {
                     if (mFramer->isLastInBurst()) {
-                        // Flush now if we know the burst is ready.
                         flushBurstBuffer();
                     }
                     nextState = STATE_IDLE;