summaryrefslogtreecommitdiffstats
path: root/audio_utils/spdif/FrameScanner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'audio_utils/spdif/FrameScanner.cpp')
-rw-r--r--audio_utils/spdif/FrameScanner.cpp270
1 files changed, 270 insertions, 0 deletions
diff --git a/audio_utils/spdif/FrameScanner.cpp b/audio_utils/spdif/FrameScanner.cpp
new file mode 100644
index 00000000..f12e5382
--- /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