blob: 11d82ea26734e30db8c920d2be00c18b01f59cb1 [file] [log] [blame]
Tim Yaocd4e4eb2020-07-24 01:47:28 -07001/*
2 * Copyright 2014, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "AudioSPDIF"
18//#define LOG_NDEBUG 0
19
20#include <string.h>
21#include <assert.h>
22
23#include <cutils/log.h>
24#include <audio_utils/spdif/FrameScanner.h>
25
26#include "MatFrameScanner.h"
27
28namespace android {
29
30// MAT Transport stream sync word
31const uint8_t MatFrameScanner::kSyncBytes[] = { 0x07, 0x9E };
32
33// Defined in IEC61937-9
34#define SPDIF_DATA_TYPE_MAT 22
35
36#define MAT_MAX_CHUNK_SIZE 30720
37
38// MAT transport format
39// { Syncword (16 bits) }
40// { metadata_payload_length (16 bits), Metadata Payload, Payload CRC (16 bits) }
41// { top_of_channels_length (16 bits), Top of Channels Audio Chunk, Payload CRC (16 bits) }
42// { bottom_of_channels_length (16 bits), Bottom of Channels Audio Chunk, Payload CRC (16 bits) }
43// Length does not include bytes for length itself and the CRC after payload.
44
45// For frame parsing, we use three frame chunks for a single IEC61937 frame
46// 1. {syncword, metadata_payload_length, Metadata Payload}
47// 2. {metadata_payload_crc, top_of_channels_length, Top of Channels Audio Chunk}
48// 3. {Top channels chunk crc, bottom_of_channels_length, Bottom of Channels Audio Chunk, Bottom Channels Chunk crc}
49// such that the header buffer for the three "virtual" frames have fixed 4 bytes size (mHeaderLength = 4)
50// and we can control the frame size to collect in each chunk state.
51
52#define CHUNK_TYPE_METADATA 0
53#define CHUNK_TYPE_TOP 1
54#define CHUNK_TYPE_BOTTOM 2
55
56MatFrameScanner::MatFrameScanner()
57 : FrameScanner(SPDIF_DATA_TYPE_MAT,
58 MatFrameScanner::kSyncBytes,
59 sizeof(MatFrameScanner::kSyncBytes), 4)
60 , mChunkType(CHUNK_TYPE_METADATA)
61 , mLastChunk(false)
62{
63}
64
65MatFrameScanner::~MatFrameScanner()
66{
67}
68
69void MatFrameScanner::resetBurst()
70{
71 mChunkType = CHUNK_TYPE_METADATA;
72}
73
74// Per IEC 61973-9:5.3.1, for MAT burst-length shall be in bytes.
75uint16_t MatFrameScanner::convertBytesToLengthCode(uint16_t numBytes) const
76{
77 return numBytes;
78}
79
80bool MatFrameScanner::isLastInBurst()
81{
82 return mLastChunk;
83}
84
85bool MatFrameScanner::parseHeader()
86{
87 size_t payload_length = ((size_t)(mHeaderBuffer[2]) << 8) | mHeaderBuffer[3];
88
89 if ((payload_length <= 0) || (payload_length > MAT_MAX_CHUNK_SIZE))
90 return false;
91
92 payload_length <<= 1; // convert to bytes
93
94 if (mChunkType == CHUNK_TYPE_METADATA) {
95 mFrameSizeBytes = mHeaderLength; // sync word, metadata length
96 mFrameSizeBytes += payload_length;
97 mChunkType = CHUNK_TYPE_TOP;
98 mLastChunk = false;
99 } else if (mChunkType == CHUNK_TYPE_TOP) {
100 mFrameSizeBytes = mHeaderLength; // metadata crc, top length
101 mFrameSizeBytes += payload_length;
102 mChunkType = CHUNK_TYPE_BOTTOM;
103 mLastChunk = false;
104 } else {
105 mFrameSizeBytes = mHeaderLength; // top crc, bottom length
106 mFrameSizeBytes += payload_length;
107 mFrameSizeBytes += 2; // bottom crc
108 mChunkType == CHUNK_TYPE_METADATA;
109 mLastChunk = true;
110 }
111
112 return true;
113}
114
115// State machine that scans for headers in a byte stream.
116// @return true if we have detected a complete and valid header.
117bool MatFrameScanner::scan(uint8_t byte)
118{
119 bool result = false;
120
121 //ALOGV("MatFrameScanner: byte = 0x%02X, mCursor = %d", byte, mCursor);
122 assert(mCursor < sizeof(mHeaderBuffer));
123
124 if ((mChunkType == CHUNK_TYPE_METADATA) && (mCursor < mSyncLength)) {
125 // match sync word
126 if (byte == mSyncBytes[mCursor]) {
127 mHeaderBuffer[mCursor++] = byte;
128 } else {
129 mBytesSkipped += 1; // skip unsynchronized data
130 mCursor = 0;
131 }
132 } else if (mCursor < mHeaderLength) {
133 // gather header for parsing metadata payload length
134 mHeaderBuffer[mCursor++] = byte;
135 if (mCursor >= mHeaderLength) {
136 if (parseHeader()) {
137 result = true;
138 } else {
139 ALOGE("MatFrameScanner: ERROR - parseHeader() failed.");
140 }
141 mCursor = 0;
142 }
143 }
144
145 return result;
146}
147
148} // namespace android