diff options
Diffstat (limited to 'audio_utils/spdif/FrameScanner.cpp')
-rw-r--r-- | audio_utils/spdif/FrameScanner.cpp | 270 |
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 |