/* * 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 #include #include "aml_audio_log.h" #include "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