[audio][spdif] Move AC3/SPDIF wrapper from Molly HAL

Wrap encoded AC3 data in a PCM data burst according
to the IEC61937 spec.

Change-Id: I59b81cafffb36cc430ee2d0776b511576643069f
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
new file mode 100644
index 0000000..f1f2cd1
--- /dev/null
+++ b/audio_utils/include/audio_utils/spdif/FrameScanner.h
@@ -0,0 +1,174 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_FRAME_SCANNER_H
+#define ANDROID_AUDIO_FRAME_SCANNER_H
+
+#include <stdint.h>
+
+namespace android {
+
+
+/**
+ * Scan a byte stream looking for the start of an encoded frame.
+ * Parse the sample rate and the size of the encoded frame.
+ * Buffer the sync header so it can be prepended to the remaining data.
+ *
+ * This is used directly by the SPDIFEncoder. External clients will
+ * generally not call this class.
+ */
+class FrameScanner {
+public:
+
+    FrameScanner(int dataType);
+    virtual ~FrameScanner();
+
+    /**
+     * Pass each byte of the encoded stream to this scanner.
+     * @return true if a complete and valid header was detected
+     */
+    virtual bool scan(uint8_t) = 0;
+
+    /**
+     * @return address of where the sync header was stored by scan()
+     */
+    virtual const uint8_t *getHeaderAddress() const = 0;
+
+    /**
+     * @return number of bytes in sync header stored by scan()
+     */
+    virtual size_t getHeaderSizeBytes() const = 0;
+
+    /**
+     * @return sample rate of the encoded audio
+     */
+    uint32_t getSampleRate()   const { return mSampleRate; }
+
+    /**
+     * Some formats, for example EAC3, are wrapped in data bursts that have
+     * a sample rate that is a multiple of the encoded sample rate.
+     * The default multiplier is 1.
+     * @return sample rate multiplier for the SP/DIF PCM data bursts
+     */
+    uint32_t getRateMultiplier()   const { return mRateMultiplier; }
+
+    size_t getFrameSizeBytes()     const { return mFrameSizeBytes; }
+
+    /**
+     * dataType is defined by the SPDIF standard for each format
+     */
+    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;
+
+    /**
+     * @return the number of pcm frames that correspond to one encoded frame
+     */
+    virtual int getMaxSampleFramesPerSyncFrame() const = 0;
+    virtual int getSampleFramesPerSyncFrame()    const = 0;
+
+    /**
+     * @return true if this parsed frame must be the first frame in a data burst.
+     */
+    virtual bool isFirstInBurst() = 0;
+
+    /**
+     * If this returns false then the previous frame may or may not be the last frame.
+     * @return true if this parsed frame is definitely the last frame in a data burst.
+     */
+    virtual bool isLastInBurst()  = 0;
+
+protected:
+    uint32_t mSampleRate;
+    uint32_t mRateMultiplier;
+    size_t   mFrameSizeBytes;
+    int      mDataType;
+    int      mDataTypeInfo;
+};
+
+#define AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES          3
+#define AC3_NUM_FRAME_SIZE_TABLE_ENTRIES          38
+#define AC3_PCM_FRAMES_PER_BLOCK                 256
+#define AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK        6
+#define EAC3_RATE_MULTIPLIER                       4
+#define EAC3_NUM_SAMPLE_RATE_TABLE_ENTRIES         3
+#define EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES   38
+
+class AC3FrameScanner : public FrameScanner
+{
+public:
+    AC3FrameScanner();
+    virtual ~AC3FrameScanner();
+
+    virtual bool scan(uint8_t);
+
+    virtual const uint8_t *getHeaderAddress() const { return mHeaderBuffer; }
+    virtual size_t getHeaderSizeBytes() const { return sizeof(mHeaderBuffer); }
+
+    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
+            * AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * AC3_PCM_FRAMES_PER_BLOCK; }
+    virtual int getSampleFramesPerSyncFrame() const;
+
+    virtual bool isFirstInBurst();
+    virtual bool isLastInBurst();
+
+protected:
+
+    // Preamble state machine states.
+    enum State {
+         STATE_EXPECTING_SYNC_1,
+         STATE_EXPECTING_SYNC_2,
+         STATE_GATHERING,
+         STATE_GOT_HEADER,
+    };
+
+    State parseHeader(void);
+
+    State    mState;
+    uint32_t mBytesSkipped;
+    uint8_t  mHeaderBuffer[6];
+    int      mLengthCode;
+    int      mAudioBlocksPerSyncFrame;
+    uint     mCursor;
+    uint     mStreamType;
+    uint     mSubstreamID;
+    uint     mFormatDumpCount;
+
+    static const uint8_t kAC3SyncByte1;
+    static const uint8_t kAC3SyncByte2;
+    static const uint16_t   kAC3SampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+    static const uint16_t kAC3FrameSizeTable[AC3_NUM_FRAME_SIZE_TABLE_ENTRIES]
+            [AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+
+    static const uint16_t   kEAC3ReducedSampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+    static const uint16_t kEAC3BlocksPerFrameTable[EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES];
+
+};
+
+}  // namespace android
+#endif  // ANDROID_AUDIO_FRAME_SCANNER_H
diff --git a/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
new file mode 100644
index 0000000..24b6074
--- /dev/null
+++ b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
@@ -0,0 +1,85 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_AUDIO_SPDIF_ENCODER_H
+#define ANDROID_AUDIO_SPDIF_ENCODER_H
+
+#include <stdint.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+namespace android {
+
+/**
+ * Scan the incoming byte stream for a frame sync.
+ * Then wrap the encoded frame in a data burst and send it as if it were PCM.
+ * The receiver will see the data burst header and decode the wrapped frame.
+ */
+#define SPDIF_MAX_CHANNELS          8
+#define SPDIF_ENCODED_CHANNEL_COUNT 2
+
+class SPDIFEncoder {
+public:
+
+    SPDIFEncoder();
+    virtual ~SPDIFEncoder();
+
+    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;
+
+    uint32_t getRateMultiplier() const { return mRateMultiplier; }
+    uint32_t getBurstFrames() const { return mBurstFrames; }
+    int      getBytesPerOutputFrame();
+
+protected:
+    void   clearBurstBuffer();
+
+    void   writeBurstBufferShorts(const uint16_t* buffer, size_t numBytes);
+    void   writeBurstBufferBytes(const uint8_t* buffer, size_t numBytes);
+    void   sendZeroPad();
+    void   flushBurstBuffer();
+    size_t startDataBurst();
+
+    // State machine states.
+    enum State {
+        STATE_IDLE,   // Waiting to sync with encoded data.
+        STATE_BURST,  // In the middle of a data burst.
+    };
+
+    // Works with various formats including AC3.
+    FrameScanner *mFramer;
+
+    State     mState;
+    uint32_t  mSampleRate;
+    size_t    mFrameSize;
+    uint16_t *mBurstBuffer; // ALSA wants to get SPDIF data as shorts.
+    size_t    mBurstBufferSizeBytes;
+    uint32_t  mRateMultiplier;
+    uint32_t  mBurstFrames;
+    size_t    mByteCursor;
+    int       mBitstreamNumber;
+    size_t    mPayloadBytesPending;
+
+    static const unsigned short kSPDIFSync1; // Pa
+    static const unsigned short kSPDIFSync2; // Pb
+};
+
+}  // namespace android
+
+#endif  // ANDROID_AUDIO_SPDIF_ENCODER_H
diff --git a/audio_utils/spdif/Android.mk b/audio_utils/spdif/Android.mk
new file mode 100644
index 0000000..5d1ac49
--- /dev/null
+++ b/audio_utils/spdif/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaudiospdif
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES:= \
+	FrameScanner.cpp \
+	SPDIFEncoder.cpp
+
+LOCAL_C_INCLUDES += $(call include-path-for, audio-utils)
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	liblog
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/audio_utils/spdif/FrameScanner.cpp b/audio_utils/spdif/FrameScanner.cpp
new file mode 100644
index 0000000..f12e538
--- /dev/null
+++ b/audio_utils/spdif/FrameScanner.cpp
@@ -0,0 +1,270 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "AudioHardwareTungsten"
+
+#include <utils/Log.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+namespace android {
+
+#define SPDIF_DATA_TYPE_AC3     1
+#define SPDIF_DATA_TYPE_E_AC3  21
+
+#define AC3_SYNCWORD_SIZE  2
+
+FrameScanner::FrameScanner(int dataType)
+ : mSampleRate(0)
+ , mRateMultiplier(1)
+ , mFrameSizeBytes(0)
+ , mDataType(dataType)
+ , mDataTypeInfo(0)
+{
+}
+
+FrameScanner::~FrameScanner()
+{
+}
+
+// ------------------- AC3 -----------------------------------------------------
+// These values are from the AC3 spec. Do not change them.
+const uint8_t AC3FrameScanner::kAC3SyncByte1 = 0x0B;
+const uint8_t AC3FrameScanner::kAC3SyncByte2 = 0x77;
+
+const uint16_t AC3FrameScanner::kAC3SampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES]
+    = { 48000, 44100, 32000 };
+
+// Table contains number of 16-bit words in an AC3 frame.
+const uint16_t AC3FrameScanner::kAC3FrameSizeTable[AC3_NUM_FRAME_SIZE_TABLE_ENTRIES]
+        [AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES] = {
+    { 64, 69, 96 },
+    { 64, 70, 96 },
+    { 80, 87, 120 },
+    { 80, 88, 120 },
+    { 96, 104, 144 },
+    { 96, 105, 144 },
+    { 112, 121, 168 },
+    { 112, 122, 168 },
+    { 128, 139, 192 },
+    { 128, 140, 192 },
+    { 160, 174, 240 },
+    { 160, 175, 240 },
+    { 192, 208, 288 },
+    { 192, 209, 288 },
+    { 224, 243, 336 },
+    { 224, 244, 336 },
+    { 256, 278, 384 },
+    { 256, 279, 384 },
+    { 320, 348, 480 },
+    { 320, 349, 480 },
+    { 384, 417, 576 },
+    { 384, 418, 576 },
+    { 448, 487, 672 },
+    { 448, 488, 672 },
+    { 512, 557, 768 },
+    { 512, 558, 768 },
+    { 640, 696, 960 },
+    { 640, 697, 960 },
+    { 768, 835, 1152 },
+    { 768, 836, 1152 },
+    { 896, 975, 1344 },
+    { 896, 976, 1344 },
+    { 1024, 1114, 1536 },
+    { 1024, 1115, 1536 },
+    { 1152, 1253, 1728 },
+    { 1152, 1254, 1728 },
+    { 1280, 1393, 1920 },
+    { 1280, 1394, 1920 }
+};
+
+const uint16_t AC3FrameScanner::kEAC3ReducedSampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES]
+        = { 24000, 22050, 16000 };
+
+const uint16_t
+        AC3FrameScanner::kEAC3BlocksPerFrameTable[EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES]
+        = { 1, 2, 3, 6 };
+// -----------------------------------------------------------------------------
+
+// Scanner for AC3 byte streams.
+AC3FrameScanner::AC3FrameScanner()
+ : 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)
+{
+    // Define beginning of syncinfo for getSyncAddress()
+    mHeaderBuffer[0] = kAC3SyncByte1;
+    mHeaderBuffer[1] = kAC3SyncByte2;
+}
+
+AC3FrameScanner::~AC3FrameScanner()
+{
+}
+
+int AC3FrameScanner::getSampleFramesPerSyncFrame() const
+{
+    return mRateMultiplier * AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * AC3_PCM_FRAMES_PER_BLOCK;
+}
+
+// per IEC 61973-3 Paragraph 5.3.3
+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.
+    }
+}
+
+bool AC3FrameScanner::isLastInBurst()
+{
+    // For EAC3 we don't know if we are the end until we see a
+    // frame that must be at the beginning. See isFirstInBurst().
+    return (mDataType != SPDIF_DATA_TYPE_E_AC3); // Just one AC3 frame per burst.
+}
+
+// Parse AC3 header.
+// Detect whether the stream is AC3 or EAC3. Extract data depending on type.
+// Sets mDataType, mFrameSizeBytes, mAudioBlocksPerSyncFrame,
+//      mSampleRate, mRateMultiplier, mLengthCode.
+//
+// @return next state for scanner
+AC3FrameScanner::State AC3FrameScanner::parseHeader()
+{
+    // Interpret bsid based on paragraph E2.3.1.6 of EAC3 spec.
+    int bsid = mHeaderBuffer[5] >> 3; // bitstream ID
+    // Check BSID to see if this is EAC3 or regular AC3
+    if ((bsid >= 10) && (bsid <= 16)) {
+        mDataType = SPDIF_DATA_TYPE_E_AC3;
+    } else if ((bsid >= 0) && (bsid <= 8)) {
+        mDataType = SPDIF_DATA_TYPE_AC3;
+    } else {
+        ALOGW("AC3 bsid = %d not supported", bsid);
+        return STATE_EXPECTING_SYNC_1;
+    }
+
+    // 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;
+        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);
+
+        int numblkscod = 3; // 6 blocks default
+        if (fscod == 3) {
+            int fscod2 = (mHeaderBuffer[4] >> 4) & 0x03;
+            if (fscod2 >= AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES) {
+                ALOGW("Invalid EAC3 fscod2 = %d\n", fscod2);
+                return STATE_EXPECTING_SYNC_1;
+            } else {
+                mSampleRate = kEAC3ReducedSampleRateTable[fscod2];
+            }
+        } else {
+            mSampleRate = kAC3SampleRateTable[fscod];
+            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.
+        mAudioBlocksPerSyncFrame = kEAC3BlocksPerFrameTable[numblkscod];
+    } else { // regular AC3
+        // Extract sample rate and frame size from codes.
+        unsigned int frmsizcod = mHeaderBuffer[4] & 0x3F; // frame size code
+
+        if (fscod >= AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES) {
+            ALOGW("Invalid AC3 sampleRateCode = %d\n", fscod);
+            return STATE_EXPECTING_SYNC_1;
+        } else if (frmsizcod >= AC3_NUM_FRAME_SIZE_TABLE_ENTRIES) {
+            ALOGW("Invalid AC3 frameSizeCode = %d\n", frmsizcod);
+            return STATE_EXPECTING_SYNC_1;
+        } else {
+            mSampleRate = kAC3SampleRateTable[fscod];
+            mRateMultiplier = 1;
+            mFrameSizeBytes = sizeof(uint16_t)
+                    * kAC3FrameSizeTable[frmsizcod][fscod];
+        }
+        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);
+    mFormatDumpCount++;
+    return STATE_GOT_HEADER;
+}
+
+// State machine that scans for AC3 headers in a byte stream.
+// @return true if we have detected a complete and valid header.
+bool AC3FrameScanner::scan(uint8_t byte)
+{
+    State nextState = mState;
+    switch (mState) {
+    case STATE_GOT_HEADER:
+        nextState = STATE_EXPECTING_SYNC_1;
+        // deliberately fall through
+    case STATE_EXPECTING_SYNC_1:
+        if (byte == kAC3SyncByte1) {
+            nextState = STATE_EXPECTING_SYNC_2; // advance
+        } else {
+            mBytesSkipped += 1; // skip unsynchronized data
+        }
+        break;
+
+    case STATE_EXPECTING_SYNC_2:
+        if (byte == kAC3SyncByte2) {
+            if (mBytesSkipped > 0) {
+                ALOGI("WARNING AC3 skipped %u bytes looking for a valid header.\n", mBytesSkipped);
+                mBytesSkipped = 0;
+            }
+            mCursor = AC3_SYNCWORD_SIZE;
+            nextState = STATE_GATHERING; // advance
+        } else if (byte == kAC3SyncByte1) {
+            nextState = STATE_EXPECTING_SYNC_2; // resync
+        } else {
+            nextState = STATE_EXPECTING_SYNC_1; // restart
+        }
+        break;
+
+    case STATE_GATHERING:
+        mHeaderBuffer[mCursor++] = byte; // save for getSyncAddress()
+        if (mCursor >= sizeof(mHeaderBuffer)) {
+            nextState = parseHeader();
+        }
+        break;
+
+    default:
+        ALOGE("AC3FrameScanner: invalid state = %d\n", mState);
+        nextState = STATE_EXPECTING_SYNC_1; // restart
+        break;
+    }
+    mState = nextState;
+    return mState == STATE_GOT_HEADER;
+}
+
+}  // namespace android
diff --git a/audio_utils/spdif/SPDIFEncoder.cpp b/audio_utils/spdif/SPDIFEncoder.cpp
new file mode 100644
index 0000000..07a1800
--- /dev/null
+++ b/audio_utils/spdif/SPDIFEncoder.cpp
@@ -0,0 +1,229 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+#include <stdint.h>
+
+#define LOG_TAG "AudioHardwareTungsten"
+#include <utils/Log.h>
+#include <audio_utils/spdif/SPDIFEncoder.h>
+
+namespace android {
+
+// Burst Preamble defined in IEC61937-1
+const unsigned short SPDIFEncoder::kSPDIFSync1 = 0xF872; // Pa
+const unsigned short SPDIFEncoder::kSPDIFSync2 = 0x4E1F; // Pb
+
+static int32_t sEndianDetector = 1;
+#define isLittleEndian()  (*((uint8_t *)&sEndianDetector))
+
+SPDIFEncoder::SPDIFEncoder()
+  : mState(STATE_IDLE)
+  , mSampleRate(48000)
+  , mBurstBuffer(NULL)
+  , mBurstBufferSizeBytes(0)
+  , mRateMultiplier(1)
+  , mBurstFrames(0)
+  , mByteCursor(0)
+  , mBitstreamNumber(0)
+  , mPayloadBytesPending(0)
+{
+    // TODO support other compressed audio formats
+    mFramer = new AC3FrameScanner();
+
+    mBurstBufferSizeBytes = sizeof(uint16_t)
+            * SPDIF_ENCODED_CHANNEL_COUNT
+            * mFramer->getMaxSampleFramesPerSyncFrame();
+    ALOGI("SPDIFEncoder: mBurstBufferSizeBytes = %d, littleEndian = %d",
+        mBurstBufferSizeBytes, isLittleEndian());
+    mBurstBuffer = new uint16_t[mBurstBufferSizeBytes >> 1];
+    clearBurstBuffer();
+}
+
+SPDIFEncoder::~SPDIFEncoder()
+{
+    delete[] mBurstBuffer;
+}
+
+int SPDIFEncoder::getBytesPerOutputFrame()
+{
+    return SPDIF_ENCODED_CHANNEL_COUNT * sizeof(int16_t);
+}
+
+void SPDIFEncoder::writeBurstBufferShorts(const uint16_t *buffer, size_t numShorts)
+{
+    mByteCursor = (mByteCursor + 1) & ~1; // round up to even byte
+    size_t bytesToWrite = numShorts * sizeof(uint16_t);
+    if ((mByteCursor + bytesToWrite) > mBurstBufferSizeBytes) {
+        ALOGE("SPDIFEncoder: Burst buffer overflow!\n");
+        clearBurstBuffer();
+        return;
+    }
+    memcpy(&mBurstBuffer[mByteCursor >> 1], buffer, bytesToWrite);
+    mByteCursor += bytesToWrite;
+}
+
+// Pack the bytes into the short buffer in the order:
+//   byte[0] -> short[0] MSB
+//   byte[1] -> short[0] LSB
+//   byte[2] -> short[1] MSB
+//   byte[3] -> short[1] LSB
+//   etcetera
+// This way they should come out in the correct order for SPDIF on both
+// Big and Little Endian CPUs.
+void SPDIFEncoder::writeBurstBufferBytes(const uint8_t *buffer, size_t numBytes)
+{
+    size_t bytesToWrite = numBytes;
+    if ((mByteCursor + bytesToWrite) > mBurstBufferSizeBytes) {
+        ALOGE("SPDIFEncoder: Burst buffer overflow!\n");
+        clearBurstBuffer();
+        return;
+    }
+    uint16_t pad = mBurstBuffer[mByteCursor >> 1];
+    for (size_t i = 0; i < bytesToWrite; i++) {
+        if (mByteCursor & 1 ) {
+            pad |= *buffer++; // put second byte in LSB
+            mBurstBuffer[mByteCursor >> 1] = pad;
+            pad = 0;
+        } else {
+            pad |= (*buffer++) << 8; // put first byte in MSB
+        }
+        mByteCursor++;
+    }
+    // Save partially filled short.
+    if (mByteCursor & 1 ){
+        mBurstBuffer[mByteCursor >> 1] = pad;
+    }
+}
+
+void SPDIFEncoder::sendZeroPad()
+{
+    // Pad remainder of burst with zeros.
+    size_t burstSize = mFramer->getSampleFramesPerSyncFrame() * sizeof(uint16_t)
+            * SPDIF_ENCODED_CHANNEL_COUNT;
+    if (mByteCursor > burstSize) {
+        ALOGE("SPDIFEncoder: Burst buffer, contents too large!\n");
+        clearBurstBuffer();
+    } else {
+        // We don't have to write zeros because buffer already set to zero
+        // by clearBurstBuffer().
+        mByteCursor = burstSize;
+    }
+}
+
+void SPDIFEncoder::flushBurstBuffer()
+{
+    if (mByteCursor > 0) {
+        sendZeroPad();
+        writeOutput(mBurstBuffer, mByteCursor);
+        clearBurstBuffer();
+    }
+}
+
+void SPDIFEncoder::clearBurstBuffer()
+{
+    if (mBurstBuffer) {
+        memset(mBurstBuffer, 0, mBurstBufferSizeBytes);
+    }
+    mByteCursor = 0;
+}
+
+size_t SPDIFEncoder::startDataBurst()
+{
+    // Encode IEC61937-1 Burst Preamble
+    uint16_t preamble[4];
+
+    uint16_t burstInfo = (mBitstreamNumber << 13)
+        | (mFramer->getDataTypeInfo() << 8)
+        | mFramer->getDataType();
+
+    mRateMultiplier = mFramer->getRateMultiplier();
+
+    preamble[0] = kSPDIFSync1;
+    preamble[1] = kSPDIFSync2;
+    preamble[2] = burstInfo;
+    preamble[3] = mFramer->getLengthCode();
+    writeBurstBufferShorts(preamble, 4);
+
+    // 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;
+}
+
+// Wraps raw encoded data into a data burst.
+ssize_t SPDIFEncoder::write( const void *buffer, size_t numBytes )
+{
+    size_t bytesLeft = numBytes;
+    const uint8_t *data = (const uint8_t *)buffer;
+    ALOGV("SPDIFEncoder: state = %d, write(buffer[0] = 0x%02X, numBytes = %u)",
+        mState, (uint) *data, numBytes);
+    while (bytesLeft > 0) {
+        State nextState = mState;
+        switch (mState) {
+        // Look for beginning of encoded frame.
+        case STATE_IDLE:
+            if (mFramer->scan(*data)) {
+                if (mFramer->isFirstInBurst()) {
+                    // Make sure that this frame is at the beginning of the data burst.
+                    flushBurstBuffer();
+                }
+                mPayloadBytesPending = startDataBurst();
+                nextState = STATE_BURST;
+            }
+            data++;
+            bytesLeft--;
+            break;
+
+        // Write payload until we hit end of frame.
+        case STATE_BURST:
+            {
+                size_t bytesToWrite = bytesLeft;
+                // Only write as many as we need to finish the frame.
+                if (bytesToWrite > mPayloadBytesPending) {
+                    bytesToWrite = mPayloadBytesPending;
+                }
+                writeBurstBufferBytes(data, bytesToWrite);
+
+                data += bytesToWrite;
+                bytesLeft -= bytesToWrite;
+                mPayloadBytesPending -= bytesToWrite;
+
+                // 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;
+                }
+            }
+            break;
+
+        default:
+            ALOGE("SPDIFEncoder: illegal state = %d\n", mState);
+            nextState = STATE_IDLE;
+            break;
+        }
+        mState = nextState;
+    }
+    return numBytes;
+}
+
+}  // namespace android