diff options
author | Phil Burk <philburk@google.com> | 2014-08-05 15:15:29 -0700 |
---|---|---|
committer | Phil Burk <philburk@google.com> | 2014-08-06 10:36:10 -0700 |
commit | 4171478fff66683841fde9810ccc39ebe87c0ccd (patch) | |
tree | 24e453e8adc83a8038e5dae8d85ee9eb61c59726 | |
parent | 122906cb559a82b1ff1a2158e3d7181b9fe7a49b (diff) | |
download | android_system_media-4171478fff66683841fde9810ccc39ebe87c0ccd.tar.gz android_system_media-4171478fff66683841fde9810ccc39ebe87c0ccd.tar.bz2 android_system_media-4171478fff66683841fde9810ccc39ebe87c0ccd.zip |
[audio][spdif] Move AC3/SPDIF wrapper from Molly HAL
Wrap encoded AC3 data in a PCM data burst according
to the IEC61937 spec.
Change-Id: I59b81cafffb36cc430ee2d0776b511576643069f
Signed-off-by: Phil Burk <philburk@google.com>
-rw-r--r-- | audio_utils/include/audio_utils/spdif/FrameScanner.h | 174 | ||||
-rw-r--r-- | audio_utils/include/audio_utils/spdif/SPDIFEncoder.h | 85 | ||||
-rw-r--r-- | audio_utils/spdif/Android.mk | 18 | ||||
-rw-r--r-- | audio_utils/spdif/FrameScanner.cpp | 270 | ||||
-rw-r--r-- | audio_utils/spdif/SPDIFEncoder.cpp | 229 |
5 files changed, 776 insertions, 0 deletions
diff --git a/audio_utils/include/audio_utils/spdif/FrameScanner.h b/audio_utils/include/audio_utils/spdif/FrameScanner.h new file mode 100644 index 00000000..f1f2cd1e --- /dev/null +++ b/audio_utils/include/audio_utils/spdif/FrameScanner.h @@ -0,0 +1,174 @@ +/* +** +** 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_FRAME_SCANNER_H +#define ANDROID_AUDIO_FRAME_SCANNER_H + +#include <stdint.h> + +namespace android { + + +/** + * Scan a byte stream looking for the start of an encoded frame. + * Parse the sample rate and the size of the encoded frame. + * Buffer the sync header so it can be prepended to the remaining data. + * + * This is used directly by the SPDIFEncoder. External clients will + * generally not call this class. + */ +class FrameScanner { +public: + + FrameScanner(int dataType); + virtual ~FrameScanner(); + + /** + * Pass each byte of the encoded stream to this scanner. + * @return true if a complete and valid header was detected + */ + virtual bool scan(uint8_t) = 0; + + /** + * @return address of where the sync header was stored by scan() + */ + virtual const uint8_t *getHeaderAddress() const = 0; + + /** + * @return number of bytes in sync header stored by scan() + */ + virtual size_t getHeaderSizeBytes() const = 0; + + /** + * @return sample rate of the encoded audio + */ + uint32_t getSampleRate() const { return mSampleRate; } + + /** + * Some formats, for example EAC3, are wrapped in data bursts that have + * a sample rate that is a multiple of the encoded sample rate. + * The default multiplier is 1. + * @return sample rate multiplier for the SP/DIF PCM data bursts + */ + uint32_t getRateMultiplier() const { return mRateMultiplier; } + + size_t getFrameSizeBytes() const { return mFrameSizeBytes; } + + /** + * dataType is defined by the SPDIF standard for each format + */ + virtual int getDataType() const { return mDataType; } + virtual int getDataTypeInfo() const { return mDataTypeInfo; } + + /** + * lengthCode is defined by the SPDIF standard + * @return length of the frame in bits or bytes, depending on the format. + */ + virtual int getLengthCode() const = 0; + virtual int getMaxChannels() const = 0; + + /** + * @return the number of pcm frames that correspond to one encoded frame + */ + virtual int getMaxSampleFramesPerSyncFrame() const = 0; + virtual int getSampleFramesPerSyncFrame() const = 0; + + /** + * @return true if this parsed frame must be the first frame in a data burst. + */ + virtual bool isFirstInBurst() = 0; + + /** + * If this returns false then the previous frame may or may not be the last frame. + * @return true if this parsed frame is definitely the last frame in a data burst. + */ + virtual bool isLastInBurst() = 0; + +protected: + uint32_t mSampleRate; + uint32_t mRateMultiplier; + size_t mFrameSizeBytes; + int mDataType; + int mDataTypeInfo; +}; + +#define AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES 3 +#define AC3_NUM_FRAME_SIZE_TABLE_ENTRIES 38 +#define AC3_PCM_FRAMES_PER_BLOCK 256 +#define AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK 6 +#define EAC3_RATE_MULTIPLIER 4 +#define EAC3_NUM_SAMPLE_RATE_TABLE_ENTRIES 3 +#define EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES 38 + +class AC3FrameScanner : public FrameScanner +{ +public: + AC3FrameScanner(); + virtual ~AC3FrameScanner(); + + virtual bool scan(uint8_t); + + virtual const uint8_t *getHeaderAddress() const { return mHeaderBuffer; } + virtual size_t getHeaderSizeBytes() const { return sizeof(mHeaderBuffer); } + + virtual int getDataType() const { return mDataType; } + virtual int getDataTypeInfo() const { return 0; } + virtual int getLengthCode() const { return mLengthCode; } + virtual int getMaxChannels() const { return 5 + 1; } + + virtual int getMaxSampleFramesPerSyncFrame() const { return EAC3_RATE_MULTIPLIER + * AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * AC3_PCM_FRAMES_PER_BLOCK; } + virtual int getSampleFramesPerSyncFrame() const; + + virtual bool isFirstInBurst(); + virtual bool isLastInBurst(); + +protected: + + // Preamble state machine states. + enum State { + STATE_EXPECTING_SYNC_1, + STATE_EXPECTING_SYNC_2, + STATE_GATHERING, + STATE_GOT_HEADER, + }; + + State parseHeader(void); + + State mState; + uint32_t mBytesSkipped; + uint8_t mHeaderBuffer[6]; + int mLengthCode; + int mAudioBlocksPerSyncFrame; + uint mCursor; + uint mStreamType; + uint mSubstreamID; + uint mFormatDumpCount; + + static const uint8_t kAC3SyncByte1; + static const uint8_t kAC3SyncByte2; + static const uint16_t kAC3SampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES]; + static const uint16_t kAC3FrameSizeTable[AC3_NUM_FRAME_SIZE_TABLE_ENTRIES] + [AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES]; + + static const uint16_t kEAC3ReducedSampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES]; + static const uint16_t kEAC3BlocksPerFrameTable[EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES]; + +}; + +} // namespace android +#endif // ANDROID_AUDIO_FRAME_SCANNER_H diff --git a/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h new file mode 100644 index 00000000..24b6074d --- /dev/null +++ b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h @@ -0,0 +1,85 @@ +/* +** +** 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_SPDIF_ENCODER_H +#define ANDROID_AUDIO_SPDIF_ENCODER_H + +#include <stdint.h> +#include <audio_utils/spdif/FrameScanner.h> + +namespace android { + +/** + * Scan the incoming byte stream for a frame sync. + * Then wrap the encoded frame in a data burst and send it as if it were PCM. + * The receiver will see the data burst header and decode the wrapped frame. + */ +#define SPDIF_MAX_CHANNELS 8 +#define SPDIF_ENCODED_CHANNEL_COUNT 2 + +class SPDIFEncoder { +public: + + SPDIFEncoder(); + virtual ~SPDIFEncoder(); + + ssize_t write( const void* buffer, size_t numBytes ); + + // Called by SPDIFEncoder when it is ready to output a data burst. + // Must be implemented by caller. + virtual ssize_t writeOutput( const void* buffer, size_t numBytes ) = 0; + + uint32_t getRateMultiplier() const { return mRateMultiplier; } + uint32_t getBurstFrames() const { return mBurstFrames; } + int getBytesPerOutputFrame(); + +protected: + void clearBurstBuffer(); + + void writeBurstBufferShorts(const uint16_t* buffer, size_t numBytes); + void writeBurstBufferBytes(const uint8_t* buffer, size_t numBytes); + void sendZeroPad(); + void flushBurstBuffer(); + size_t startDataBurst(); + + // State machine states. + enum State { + STATE_IDLE, // Waiting to sync with encoded data. + STATE_BURST, // In the middle of a data burst. + }; + + // Works with various formats including AC3. + FrameScanner *mFramer; + + State mState; + uint32_t mSampleRate; + size_t mFrameSize; + uint16_t *mBurstBuffer; // ALSA wants to get SPDIF data as shorts. + size_t mBurstBufferSizeBytes; + uint32_t mRateMultiplier; + uint32_t mBurstFrames; + size_t mByteCursor; + int mBitstreamNumber; + size_t mPayloadBytesPending; + + static const unsigned short kSPDIFSync1; // Pa + static const unsigned short kSPDIFSync2; // Pb +}; + +} // namespace android + +#endif // ANDROID_AUDIO_SPDIF_ENCODER_H diff --git a/audio_utils/spdif/Android.mk b/audio_utils/spdif/Android.mk new file mode 100644 index 00000000..5d1ac491 --- /dev/null +++ b/audio_utils/spdif/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libaudiospdif +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES:= \ + FrameScanner.cpp \ + SPDIFEncoder.cpp + +LOCAL_C_INCLUDES += $(call include-path-for, audio-utils) + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog + +include $(BUILD_SHARED_LIBRARY) 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 diff --git a/audio_utils/spdif/SPDIFEncoder.cpp b/audio_utils/spdif/SPDIFEncoder.cpp new file mode 100644 index 00000000..07a1800d --- /dev/null +++ b/audio_utils/spdif/SPDIFEncoder.cpp @@ -0,0 +1,229 @@ +/* +** +** 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. +*/ + + +#include <stdint.h> + +#define LOG_TAG "AudioHardwareTungsten" +#include <utils/Log.h> +#include <audio_utils/spdif/SPDIFEncoder.h> + +namespace android { + +// Burst Preamble defined in IEC61937-1 +const unsigned short SPDIFEncoder::kSPDIFSync1 = 0xF872; // Pa +const unsigned short SPDIFEncoder::kSPDIFSync2 = 0x4E1F; // Pb + +static int32_t sEndianDetector = 1; +#define isLittleEndian() (*((uint8_t *)&sEndianDetector)) + +SPDIFEncoder::SPDIFEncoder() + : mState(STATE_IDLE) + , mSampleRate(48000) + , mBurstBuffer(NULL) + , mBurstBufferSizeBytes(0) + , mRateMultiplier(1) + , mBurstFrames(0) + , mByteCursor(0) + , mBitstreamNumber(0) + , mPayloadBytesPending(0) +{ + // TODO support other compressed audio formats + mFramer = new AC3FrameScanner(); + + mBurstBufferSizeBytes = sizeof(uint16_t) + * SPDIF_ENCODED_CHANNEL_COUNT + * mFramer->getMaxSampleFramesPerSyncFrame(); + ALOGI("SPDIFEncoder: mBurstBufferSizeBytes = %d, littleEndian = %d", + mBurstBufferSizeBytes, isLittleEndian()); + mBurstBuffer = new uint16_t[mBurstBufferSizeBytes >> 1]; + clearBurstBuffer(); +} + +SPDIFEncoder::~SPDIFEncoder() +{ + delete[] mBurstBuffer; +} + +int SPDIFEncoder::getBytesPerOutputFrame() +{ + return SPDIF_ENCODED_CHANNEL_COUNT * sizeof(int16_t); +} + +void SPDIFEncoder::writeBurstBufferShorts(const uint16_t *buffer, size_t numShorts) +{ + mByteCursor = (mByteCursor + 1) & ~1; // round up to even byte + size_t bytesToWrite = numShorts * sizeof(uint16_t); + if ((mByteCursor + bytesToWrite) > mBurstBufferSizeBytes) { + ALOGE("SPDIFEncoder: Burst buffer overflow!\n"); + clearBurstBuffer(); + return; + } + memcpy(&mBurstBuffer[mByteCursor >> 1], buffer, bytesToWrite); + mByteCursor += bytesToWrite; +} + +// Pack the bytes into the short buffer in the order: +// byte[0] -> short[0] MSB +// byte[1] -> short[0] LSB +// byte[2] -> short[1] MSB +// byte[3] -> short[1] LSB +// etcetera +// This way they should come out in the correct order for SPDIF on both +// Big and Little Endian CPUs. +void SPDIFEncoder::writeBurstBufferBytes(const uint8_t *buffer, size_t numBytes) +{ + size_t bytesToWrite = numBytes; + if ((mByteCursor + bytesToWrite) > mBurstBufferSizeBytes) { + ALOGE("SPDIFEncoder: Burst buffer overflow!\n"); + clearBurstBuffer(); + return; + } + uint16_t pad = mBurstBuffer[mByteCursor >> 1]; + for (size_t i = 0; i < bytesToWrite; i++) { + if (mByteCursor & 1 ) { + pad |= *buffer++; // put second byte in LSB + mBurstBuffer[mByteCursor >> 1] = pad; + pad = 0; + } else { + pad |= (*buffer++) << 8; // put first byte in MSB + } + mByteCursor++; + } + // Save partially filled short. + if (mByteCursor & 1 ){ + mBurstBuffer[mByteCursor >> 1] = pad; + } +} + +void SPDIFEncoder::sendZeroPad() +{ + // Pad remainder of burst with zeros. + size_t burstSize = mFramer->getSampleFramesPerSyncFrame() * sizeof(uint16_t) + * SPDIF_ENCODED_CHANNEL_COUNT; + if (mByteCursor > burstSize) { + ALOGE("SPDIFEncoder: Burst buffer, contents too large!\n"); + clearBurstBuffer(); + } else { + // We don't have to write zeros because buffer already set to zero + // by clearBurstBuffer(). + mByteCursor = burstSize; + } +} + +void SPDIFEncoder::flushBurstBuffer() +{ + if (mByteCursor > 0) { + sendZeroPad(); + writeOutput(mBurstBuffer, mByteCursor); + clearBurstBuffer(); + } +} + +void SPDIFEncoder::clearBurstBuffer() +{ + if (mBurstBuffer) { + memset(mBurstBuffer, 0, mBurstBufferSizeBytes); + } + mByteCursor = 0; +} + +size_t SPDIFEncoder::startDataBurst() +{ + // Encode IEC61937-1 Burst Preamble + uint16_t preamble[4]; + + uint16_t burstInfo = (mBitstreamNumber << 13) + | (mFramer->getDataTypeInfo() << 8) + | mFramer->getDataType(); + + mRateMultiplier = mFramer->getRateMultiplier(); + + preamble[0] = kSPDIFSync1; + preamble[1] = kSPDIFSync2; + preamble[2] = burstInfo; + preamble[3] = mFramer->getLengthCode(); + writeBurstBufferShorts(preamble, 4); + + // Write start of encoded frame that was buffered in frame detector. + size_t syncSize = mFramer->getHeaderSizeBytes(); + writeBurstBufferBytes(mFramer->getHeaderAddress(), syncSize); + ALOGV("SPDIFEncoder: startDataBurst, syncSize = %u, lengthCode = %d", + syncSize, mFramer->getLengthCode()); + return mFramer->getFrameSizeBytes() - syncSize; +} + +// Wraps raw encoded data into a data burst. +ssize_t SPDIFEncoder::write( const void *buffer, size_t numBytes ) +{ + size_t bytesLeft = numBytes; + const uint8_t *data = (const uint8_t *)buffer; + ALOGV("SPDIFEncoder: state = %d, write(buffer[0] = 0x%02X, numBytes = %u)", + mState, (uint) *data, numBytes); + while (bytesLeft > 0) { + State nextState = mState; + switch (mState) { + // Look for beginning of encoded frame. + case STATE_IDLE: + if (mFramer->scan(*data)) { + if (mFramer->isFirstInBurst()) { + // Make sure that this frame is at the beginning of the data burst. + flushBurstBuffer(); + } + mPayloadBytesPending = startDataBurst(); + nextState = STATE_BURST; + } + data++; + bytesLeft--; + break; + + // Write payload until we hit end of frame. + case STATE_BURST: + { + size_t bytesToWrite = bytesLeft; + // Only write as many as we need to finish the frame. + if (bytesToWrite > mPayloadBytesPending) { + bytesToWrite = mPayloadBytesPending; + } + writeBurstBufferBytes(data, bytesToWrite); + + data += bytesToWrite; + bytesLeft -= bytesToWrite; + mPayloadBytesPending -= bytesToWrite; + + // If we have all the payload then send a data burst. + if (mPayloadBytesPending == 0) { + if (mFramer->isLastInBurst()) { + // Flush now if we know the burst is ready. + flushBurstBuffer(); + } + nextState = STATE_IDLE; + } + } + break; + + default: + ALOGE("SPDIFEncoder: illegal state = %d\n", mState); + nextState = STATE_IDLE; + break; + } + mState = nextState; + } + return numBytes; +} + +} // namespace android |