From 4171478fff66683841fde9810ccc39ebe87c0ccd Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Tue, 5 Aug 2014 15:15:29 -0700 Subject: [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 --- .../include/audio_utils/spdif/FrameScanner.h | 174 +++++++++++++++++++++ .../include/audio_utils/spdif/SPDIFEncoder.h | 85 ++++++++++ 2 files changed, 259 insertions(+) create mode 100644 audio_utils/include/audio_utils/spdif/FrameScanner.h create mode 100644 audio_utils/include/audio_utils/spdif/SPDIFEncoder.h (limited to 'audio_utils/include') 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 + +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 +#include + +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 -- cgit v1.2.3