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;
}