aml_amaudioutils: Add MAT 61937 encoding support [1/1]

PD#SWPL-17555

Problem:
Missing MAT SPDIF encoder support

Solution:
Add the implementation for MAT SPDIF encoding

Verify:
Dump data output after MAT SPDIF encoding and
use aplay to play encoded bit stream in 192k
sample rate and can get correct output on AVR.

Change-Id: I3865a80ed495189b5205cff9ad5ee2e8f7c8259a
diff --git a/Makefile b/Makefile
index 10e9b30..06fd75e 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,7 @@
 	src/spdif/BitFieldParser.o \
 	src/spdif/DTSFrameScanner.o \
 	src/spdif/FrameScanner.o \
+        src/spdif/MatFrameScanner.o \
 	src/spdif/SPDIFEncoder.o
 
 CUTILS_OBJS=src/cutils/hashmap.o \
@@ -13,7 +14,7 @@
 	src/cutils/threads.o \
 	src/cutils/strlcpy.o
 
-CFLAGS+=-fPIC -O2 -I./include -I./include/speex -I. -I./src -I./src/ -mfpu=neon -DFIXED_POINT -DRESAMPLE_FORCE_FULL_SINC_TABLE -D_USE_NEON -DEXPORT=
+CFLAGS+=-fPIC -O2 -I./include -I./include/speex -I. -I./src -I./src/ -mfpu=neon -DNDEBUG -DFIXED_POINT -DRESAMPLE_FORCE_FULL_SINC_TABLE -D_USE_NEON -DEXPORT=
 LDFLAGS+=-llog -ldl -lrt -lpthread -lstdc++
 
 %.o: %.cpp
diff --git a/src/cutils/strlcpy.c b/src/cutils/strlcpy.c
index c66246c..f9f1e2b 100644
--- a/src/cutils/strlcpy.c
+++ b/src/cutils/strlcpy.c
@@ -16,7 +16,7 @@
 
 #include <sys/types.h>
 
-#if defined(__GLIBC__) || defined(_WIN32)
+//#if defined(__GLIBC__) || defined(_WIN32)
 
 #include <string.h>
 
@@ -55,4 +55,4 @@
 	return(s - src - 1);	/* count does not include NUL */
 }
 
-#endif
+//#endif
diff --git a/src/spdif/MatFrameScanner.cpp b/src/spdif/MatFrameScanner.cpp
new file mode 100644
index 0000000..11d82ea
--- /dev/null
+++ b/src/spdif/MatFrameScanner.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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 "AudioSPDIF"
+//#define LOG_NDEBUG 0
+
+#include <string.h>
+#include <assert.h>
+
+#include <cutils/log.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+#include "MatFrameScanner.h"
+
+namespace android {
+
+// MAT Transport stream sync word
+const uint8_t MatFrameScanner::kSyncBytes[] = { 0x07, 0x9E };
+
+// Defined in IEC61937-9
+#define SPDIF_DATA_TYPE_MAT 22
+
+#define MAT_MAX_CHUNK_SIZE 30720
+
+// MAT transport format
+// { Syncword (16 bits) }
+// { metadata_payload_length   (16 bits), Metadata Payload, Payload CRC (16 bits) }
+// { top_of_channels_length    (16 bits), Top of Channels Audio Chunk, Payload CRC (16 bits) }
+// { bottom_of_channels_length (16 bits), Bottom of Channels Audio Chunk, Payload CRC (16 bits) }
+// Length does not include bytes for length itself and the CRC after payload.
+
+// For frame parsing, we use three frame chunks for a single IEC61937 frame
+// 1. {syncword, metadata_payload_length, Metadata Payload}
+// 2. {metadata_payload_crc, top_of_channels_length, Top of Channels Audio Chunk}
+// 3. {Top channels chunk crc, bottom_of_channels_length, Bottom of Channels Audio Chunk, Bottom Channels Chunk crc}
+// such that the header buffer for the three "virtual" frames have fixed 4 bytes size (mHeaderLength = 4)
+// and we can control the frame size to collect in each chunk state.
+
+#define CHUNK_TYPE_METADATA 0
+#define CHUNK_TYPE_TOP      1
+#define CHUNK_TYPE_BOTTOM   2
+
+MatFrameScanner::MatFrameScanner()
+ : FrameScanner(SPDIF_DATA_TYPE_MAT,
+        MatFrameScanner::kSyncBytes,
+        sizeof(MatFrameScanner::kSyncBytes), 4)
+ , mChunkType(CHUNK_TYPE_METADATA)
+ , mLastChunk(false)
+{
+}
+
+MatFrameScanner::~MatFrameScanner()
+{
+}
+
+void MatFrameScanner::resetBurst()
+{
+    mChunkType = CHUNK_TYPE_METADATA;
+}
+
+// Per IEC 61973-9:5.3.1, for MAT burst-length shall be in bytes.
+uint16_t MatFrameScanner::convertBytesToLengthCode(uint16_t numBytes) const
+{
+    return numBytes;
+}
+
+bool MatFrameScanner::isLastInBurst()
+{
+    return mLastChunk;
+}
+
+bool MatFrameScanner::parseHeader()
+{
+    size_t payload_length = ((size_t)(mHeaderBuffer[2]) << 8) | mHeaderBuffer[3];
+
+    if ((payload_length <= 0) || (payload_length > MAT_MAX_CHUNK_SIZE))
+        return false;
+
+    payload_length <<= 1;   // convert to bytes
+
+    if (mChunkType == CHUNK_TYPE_METADATA) {
+        mFrameSizeBytes = mHeaderLength;    // sync word, metadata length
+        mFrameSizeBytes += payload_length;
+        mChunkType = CHUNK_TYPE_TOP;
+        mLastChunk = false;
+    } else if (mChunkType == CHUNK_TYPE_TOP) {
+        mFrameSizeBytes = mHeaderLength;    // metadata crc, top length
+        mFrameSizeBytes += payload_length;
+        mChunkType = CHUNK_TYPE_BOTTOM;
+        mLastChunk = false;
+    } else {
+        mFrameSizeBytes = mHeaderLength;    // top crc, bottom length
+        mFrameSizeBytes += payload_length;
+        mFrameSizeBytes += 2;               // bottom crc
+        mChunkType == CHUNK_TYPE_METADATA;
+        mLastChunk = true;
+    }
+
+    return true;
+}
+
+// State machine that scans for headers in a byte stream.
+// @return true if we have detected a complete and valid header.
+bool MatFrameScanner::scan(uint8_t byte)
+{
+    bool result = false;
+
+    //ALOGV("MatFrameScanner: byte = 0x%02X, mCursor = %d", byte, mCursor);
+    assert(mCursor < sizeof(mHeaderBuffer));
+
+    if ((mChunkType == CHUNK_TYPE_METADATA) && (mCursor < mSyncLength)) {
+        // match sync word
+        if (byte == mSyncBytes[mCursor]) {
+            mHeaderBuffer[mCursor++] = byte;
+        } else {
+            mBytesSkipped += 1; // skip unsynchronized data
+            mCursor = 0;
+        }
+    } else if (mCursor < mHeaderLength) {
+        // gather header for parsing metadata payload length
+        mHeaderBuffer[mCursor++] = byte;
+        if (mCursor >= mHeaderLength) {
+            if (parseHeader()) {
+                result = true;
+            } else {
+                ALOGE("MatFrameScanner: ERROR - parseHeader() failed.");
+            }
+            mCursor = 0;
+        }
+    }
+
+    return result;
+}
+
+}  // namespace android
diff --git a/src/spdif/MatFrameScanner.h b/src/spdif/MatFrameScanner.h
new file mode 100644
index 0000000..c4ce825
--- /dev/null
+++ b/src/spdif/MatFrameScanner.h
@@ -0,0 +1,60 @@
+/*
+ * 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_MAT_FRAME_SCANNER_H
+#define ANDROID_AUDIO_MAT_FRAME_SCANNER_H
+
+#include <stdint.h>
+#include <system/audio.h>
+#include <audio_utils/spdif/FrameScanner.h>
+
+namespace android {
+
+#define MAT_PCM_FRAMES                          1536
+#define MAT_RATE_MULTIPLIER                       10
+
+class MatFrameScanner : public FrameScanner
+{
+public:
+    MatFrameScanner();
+    virtual ~MatFrameScanner();
+
+    virtual int getMaxChannels()   const { return 5 + 1 + 2; } // 5.1.2 surround
+
+    virtual int getMaxSampleFramesPerSyncFrame() const { return MAT_RATE_MULTIPLIER
+            * MAT_PCM_FRAMES; }
+    virtual int getSampleFramesPerSyncFrame() const { return MAT_RATE_MULTIPLIER
+            * MAT_PCM_FRAMES; }
+
+    virtual bool isFirstInBurst() { return false; }
+    virtual bool isLastInBurst();
+    virtual void resetBurst();
+
+    virtual uint16_t convertBytesToLengthCode(uint16_t numBytes) const;
+    virtual bool scan(uint8_t byte);
+
+protected:
+    // used to recognize the start of a MAT sync frame
+    static const uint8_t kSyncBytes[];
+    int mChunkType;
+    bool mLastChunk;
+
+    virtual bool parseHeader();
+};
+
+}  // namespace android
+
+#endif  // ANDROID_AUDIO_MAT_FRAME_SCANNER_H
diff --git a/src/spdif/SPDIFEncoder.cpp b/src/spdif/SPDIFEncoder.cpp
index 221a072..62f547d 100644
--- a/src/spdif/SPDIFEncoder.cpp
+++ b/src/spdif/SPDIFEncoder.cpp
@@ -23,6 +23,7 @@
 
 #include "AC3FrameScanner.h"
 #include "DTSFrameScanner.h"
+#include "MatFrameScanner.h"
 
 namespace android {
 
@@ -54,6 +55,9 @@
         case AUDIO_FORMAT_DTS_HD:
             mFramer = new DTSFrameScanner();
             break;
+        case AUDIO_FORMAT_MAT:
+            mFramer = new MatFrameScanner();
+            break;
         default:
             break;
     }