audio: Unified audio related header files. [4/7]
PD#SWPL-140847
Problem:
Unified audio related header files.
Solution:
Delete duplicate header files.
Common header files depend on audio hal.
Verify:
Yocto: :AP222
Change-Id: Idd9903a8333ce0b4949829aac28212628ab9ace7
Signed-off-by: xingri.gao <xingri.gao@amlogic.com>
diff --git a/utils/SPDIFEncoderAD.cpp b/utils/SPDIFEncoderAD.cpp
index 4e9f677..2fcde22 100644
--- a/utils/SPDIFEncoderAD.cpp
+++ b/utils/SPDIFEncoderAD.cpp
@@ -21,9 +21,9 @@
#include <stdint.h>
#include <cutils/log.h>
#include <system/audio.h>
-#include <audio_utils/spdif/SPDIFEncoder.h>
#include <tinyalsa/asoundlib.h>
#include <cutils/properties.h>
+#include "SPDIFEncoder.h"
#include "SPDIFEncoderAD.h"
#include "aml_android_utils.h"
diff --git a/utils/include/spdif/FrameScanner.h b/utils/include/spdif/FrameScanner.h
new file mode 100644
index 0000000..6d391ee
--- /dev/null
+++ b/utils/include/spdif/FrameScanner.h
@@ -0,0 +1,130 @@
+/*
+ * 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,
+ const uint8_t *syncBytes,
+ uint32_t syncLength,
+ uint32_t headerLength
+ );
+ 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 byte);
+
+ /**
+ * @return address of where the sync header was stored by scan()
+ */
+ const uint8_t *getHeaderAddress() const { return mHeaderBuffer; }
+
+ /**
+ * @return number of bytes in sync header stored by scan()
+ */
+ size_t getHeaderSizeBytes() const { return mHeaderLength; }
+
+ /**
+ * @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
+ */
+ int getDataType() const { return mDataType; }
+ int getDataTypeInfo() const { return mDataTypeInfo; }
+
+ virtual int getMaxChannels() const = 0;
+
+ virtual void resetBurst() = 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;
+
+ /**
+ * Most compression types use a lengthCode expressed in bits.
+ */
+ virtual uint16_t convertBytesToLengthCode(uint16_t numBytes) const { return numBytes * 8; }
+
+protected:
+ uint32_t mBytesSkipped; // how many bytes were skipped looking for the start of a frame
+ const uint8_t *mSyncBytes; // pointer to the sync word specific to a format
+ uint32_t mSyncLength; // number of bytes in sync word
+ uint8_t mHeaderBuffer[32]; // a place to gather the relevant header bytes for parsing
+ uint32_t mHeaderLength; // the number of bytes we need to parse
+ uint32_t mCursor; // position in the mHeaderBuffer
+ uint32_t mFormatDumpCount; // used to thin out the debug dumps
+ uint32_t mSampleRate; // encoded sample rate
+ uint32_t mRateMultiplier; // SPDIF output data burst rate = msampleRate * mRateMultiplier
+ size_t mFrameSizeBytes; // encoded frame size
+ int mDataType; // as defined in IEC61937-2 paragraph 4.2
+ int mDataTypeInfo; // as defined in IEC61937-2 paragraph 4.1
+
+ /**
+ * Parse data in mHeaderBuffer.
+ * Sets mDataType, mFrameSizeBytes, mSampleRate, mRateMultiplier.
+ * @return true if the header is valid.
+ */
+ virtual bool parseHeader() = 0;
+
+};
+
+
+} // namespace android
+#endif // ANDROID_AUDIO_FRAME_SCANNER_H
diff --git a/utils/include/spdif/SPDIFEncoder.h b/utils/include/spdif/SPDIFEncoder.h
new file mode 100644
index 0000000..6e6a644
--- /dev/null
+++ b/utils/include/spdif/SPDIFEncoder.h
@@ -0,0 +1,113 @@
+/*
+ * 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 "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:
+
+ explicit SPDIFEncoder(audio_format_t format);
+ // Defaults to AC3 format. Was in original API.
+ SPDIFEncoder();
+
+ virtual ~SPDIFEncoder();
+
+ /**
+ * Write encoded data to be wrapped for SPDIF.
+ * The compressed frames do not have to be aligned.
+ * @return number of bytes written or negative error
+ */
+ ssize_t write( const void* buffer, size_t numBytes );
+
+ /**
+ * Called by SPDIFEncoder when it is ready to output a data burst.
+ * Must be implemented in the subclass.
+ * @return number of bytes written or negative error
+ */
+ virtual ssize_t writeOutput( const void* buffer, size_t numBytes ) = 0;
+
+ /**
+ * Get ratio of the encoded data burst sample rate to the encoded rate.
+ * For example, EAC3 data bursts are 4X the encoded rate.
+ */
+ uint32_t getRateMultiplier() const { return mRateMultiplier; }
+
+ /**
+ * @return number of PCM frames in a data burst
+ */
+ uint32_t getBurstFrames() const { return mBurstFrames; }
+
+ /**
+ * @return number of bytes per PCM frame for the data burst
+ */
+ int getBytesPerOutputFrame();
+
+ /**
+ * @return true if we can wrap this format in an SPDIF stream
+ */
+ static bool isFormatSupported(audio_format_t format);
+
+ /**
+ * Discard any data in the buffer. Reset frame scanners.
+ * This should be called when seeking to a new position in the stream.
+ */
+ void reset();
+
+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();
+ void startDataBurst();
+ size_t startSyncFrame();
+
+ // Works with various formats including AC3.
+ FrameScanner *mFramer;
+
+ uint32_t mSampleRate;
+ size_t mFrameSize; // size of sync frame in bytes
+ uint16_t *mBurstBuffer; // ALSA wants to get SPDIF data as shorts.
+ size_t mBurstBufferSizeBytes;
+ uint32_t mRateMultiplier;
+ uint32_t mBurstFrames;
+ size_t mByteCursor; // cursor into data burst
+ int mBitstreamNumber;
+ size_t mPayloadBytesPending; // number of bytes needed to finish burst
+ // state variable, true if scanning for start of frame
+ bool mScanning;
+
+ static const uint16_t kSPDIFSync1; // Pa
+ static const uint16_t kSPDIFSync2; // Pb
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_SPDIF_ENCODER_H
diff --git a/utils/spdif/AC3FrameScanner.cpp b/utils/spdif/AC3FrameScanner.cpp
new file mode 100644
index 0000000..aa041b3
--- /dev/null
+++ b/utils/spdif/AC3FrameScanner.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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 "AudioSPDIF"
+
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include "FrameScanner.h"
+#include "AC3FrameScanner.h"
+
+namespace android {
+
+// These values are from the AC3 spec. Do not change them.
+
+const uint8_t AC3FrameScanner::kSyncBytes[] = { 0x0B, 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.
+// From AC3 spec table 5.13
+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 };
+
+// Defined in IEC61937-2
+#define SPDIF_DATA_TYPE_AC3 1
+#define SPDIF_DATA_TYPE_E_AC3 21
+#define AC3_STREAM_TYPE_0 0
+#define AC3_STREAM_TYPE_1 1
+#define AC3_STREAM_TYPE_2 2
+// -----------------------------------------------------------------------------
+
+// Scanner for AC3 byte streams.
+AC3FrameScanner::AC3FrameScanner(audio_format_t format)
+ : FrameScanner(SPDIF_DATA_TYPE_AC3,
+ AC3FrameScanner::kSyncBytes,
+ sizeof(AC3FrameScanner::kSyncBytes), 6)
+ , mStreamType(0)
+ , mSubstreamID(0)
+ , mFormat(format)
+{
+ mAudioBlocksPerSyncFrame = 6;
+ memset(mSubstreamBlockCounts, 0, sizeof(mSubstreamBlockCounts));
+}
+
+AC3FrameScanner::~AC3FrameScanner()
+{
+}
+
+int AC3FrameScanner::getSampleFramesPerSyncFrame() const
+{
+ return mRateMultiplier
+ * AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * AC3_PCM_FRAMES_PER_BLOCK;
+}
+
+void AC3FrameScanner::resetBurst()
+{
+ for (int i = 0; i < EAC3_MAX_SUBSTREAMS; i++) {
+ if (mSubstreamBlockCounts[i] >= AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK) {
+ mSubstreamBlockCounts[i] -= AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK;
+ } else if (mSubstreamBlockCounts[i] > 0) {
+ ALOGW("EAC3 substream[%d] has only %d audio blocks!",
+ i, mSubstreamBlockCounts[i]);
+ mSubstreamBlockCounts[i] = 0;
+ }
+ }
+}
+
+// Per IEC 61973-3:5.3.3, for E-AC3 burst-length shall be in bytes.
+uint16_t AC3FrameScanner::convertBytesToLengthCode(uint16_t numBytes) const
+{
+ return (mDataType == SPDIF_DATA_TYPE_E_AC3) ? numBytes : numBytes * 8;
+}
+
+// per IEC 61973-3 Paragraph 5.3.3
+// We have to send 6 audio blocks on all active substreams.
+// Substream zero must be the first.
+// We don't know if we have all the blocks we need until we see
+// the 7th block of substream#0.
+bool AC3FrameScanner::isFirstInBurst()
+{
+ if (mDataType == SPDIF_DATA_TYPE_E_AC3) {
+ if (((mStreamType == AC3_STREAM_TYPE_0)
+ || (mStreamType == AC3_STREAM_TYPE_2))
+ && (mSubstreamID == 0)
+ // The ">" is intentional. We have to see the beginning
+ // of the block in the next burst before we can send
+ // the current burst.
+ && (mSubstreamBlockCounts[0] > AC3_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+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.
+}
+
+// TODO Use BitFieldParser
+
+// Parse AC3 header.
+// Detect whether the stream is AC3 or EAC3. Extract data depending on type.
+//
+// @return true if valid
+bool AC3FrameScanner::parseHeader()
+{
+ // Interpret bsid based on paragraph E2.3.1.6 of EAC3 spec.
+ uint32_t bsid = mHeaderBuffer[5] >> 3; // bitstream ID
+ // Check BSID to see if this is EAC3 or regular AC3.
+ // These arbitrary BSID numbers do not have any names in the spec.
+ if ((bsid > 10) && (bsid <= 16)) {
+ mDataType = SPDIF_DATA_TYPE_E_AC3;
+ } else if (bsid <= 8) {
+ mDataType = SPDIF_DATA_TYPE_AC3;
+ } else {
+ ALOGW("AC3 bsid = %d not supported", bsid);
+ return false;
+ }
+
+ // bitstream mode, main, commentary, etc.
+ uint32_t bsmod = mHeaderBuffer[5] & 7;
+ mDataTypeInfo = bsmod; // as per IEC61937-3, table 3.
+
+ // The names fscod, frmsiz are from the AC3 spec.
+ uint32_t fscod = mHeaderBuffer[4] >> 6;
+ if (mDataType == SPDIF_DATA_TYPE_E_AC3) {
+ mStreamType = mHeaderBuffer[2] >> 6; // strmtyp in spec
+ mSubstreamID = (mHeaderBuffer[2] >> 3) & 0x07;
+
+ // Frame size is explicit in EAC3. Paragraph E2.3.1.3
+ uint32_t frmsiz = ((mHeaderBuffer[2] & 0x07) << 8) + mHeaderBuffer[3];
+ mFrameSizeBytes = (frmsiz + 1) * sizeof(int16_t);
+
+ uint32_t numblkscod = 3; // 6 blocks default
+ if (fscod == 3) {
+ uint32_t fscod2 = (mHeaderBuffer[4] >> 4) & 0x03;
+ if (fscod2 >= AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES) {
+ ALOGW("Invalid EAC3 fscod2 = %d", fscod2);
+ return false;
+ } 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
+ // Don't send data burst until we have 6 blocks per substream.
+ mAudioBlocksPerSyncFrame = kEAC3BlocksPerFrameTable[numblkscod];
+ // Keep track of how many audio blocks we have for each substream.
+ // This should be safe because mSubstreamID is ANDed with 0x07 above.
+ // And the array is allocated as [8].
+ if ((mStreamType == AC3_STREAM_TYPE_0)
+ || (mStreamType == AC3_STREAM_TYPE_2)) {
+ mSubstreamBlockCounts[mSubstreamID] += mAudioBlocksPerSyncFrame;
+ }
+
+ // Print enough so we can see all the substreams.
+ ALOGD_IF((mFormatDumpCount < 3*8 ),
+ "EAC3 mStreamType = %d, mSubstreamID = %d",
+ mStreamType, mSubstreamID);
+ } else { // regular AC3
+ // Extract sample rate and frame size from codes.
+ uint32_t frmsizcod = mHeaderBuffer[4] & 0x3F; // frame size code
+
+ if (fscod >= AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES) {
+ ALOGW("Invalid AC3 sampleRateCode = %d", fscod);
+ return false;
+ } else if (frmsizcod >= AC3_NUM_FRAME_SIZE_TABLE_ENTRIES) {
+ ALOGW("Invalid AC3 frameSizeCode = %d", frmsizcod);
+ return false;
+ } else {
+ mSampleRate = kAC3SampleRateTable[fscod];
+ mRateMultiplier = 1;
+ mFrameSizeBytes = sizeof(uint16_t)
+ * kAC3FrameSizeTable[frmsizcod][fscod];
+ }
+ mAudioBlocksPerSyncFrame = 6;
+ if (mFormat == AUDIO_FORMAT_E_AC3) {
+ ALOGV("Its a Ac3 substream in EAC3 stream");
+ mStreamType = 2;
+ mSubstreamID = 0;
+ mSubstreamBlockCounts[0] += mAudioBlocksPerSyncFrame;
+ mDataType = SPDIF_DATA_TYPE_E_AC3;
+ mRateMultiplier = EAC3_RATE_MULTIPLIER;
+ }
+ }
+ ALOGI_IF((mFormatDumpCount == 0),
+ "AC3 frame rate = %d * %d, size = %zu, audioBlocksPerSyncFrame = %d",
+ mSampleRate, mRateMultiplier, mFrameSizeBytes, mAudioBlocksPerSyncFrame);
+ mFormatDumpCount++;
+ return true;
+}
+
+} // namespace android
diff --git a/utils/spdif/AC3FrameScanner.h b/utils/spdif/AC3FrameScanner.h
new file mode 100644
index 0000000..23746a3
--- /dev/null
+++ b/utils/spdif/AC3FrameScanner.h
@@ -0,0 +1,81 @@
+/*
+ * 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_AC3_FRAME_SCANNER_H
+#define ANDROID_AUDIO_AC3_FRAME_SCANNER_H
+
+#include <stdint.h>
+#include "FrameScanner.h"
+#include "system/audio-base.h"
+
+namespace android {
+
+#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
+#define EAC3_MAX_SUBSTREAMS 8
+
+class AC3FrameScanner : public FrameScanner
+{
+public:
+ explicit AC3FrameScanner(audio_format_t format);
+ virtual ~AC3FrameScanner();
+
+ virtual int getMaxChannels() const { return 5 + 1; } // 5.1 surround
+
+ 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();
+ virtual void resetBurst();
+
+ virtual uint16_t convertBytesToLengthCode(uint16_t numBytes) const;
+
+protected:
+ // Keep track of how many of each substream blocks have been accumulated.
+ // We need all of each substream before sending block data burst.
+ uint8_t mSubstreamBlockCounts[EAC3_MAX_SUBSTREAMS];
+ int mAudioBlocksPerSyncFrame;
+ // The type of EAC3 stream as per EAC3 spec paragraph 2.3.1.1
+ uint32_t mStreamType;
+ // substream index
+ uint32_t mSubstreamID;
+ audio_format_t mFormat;
+
+ // used to recognize the start of an AC3 sync frame
+ static const uint8_t kSyncBytes[];
+ // sample rates from AC3 spec table 5.1
+ static const uint16_t kAC3SampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+ // frame sizes from AC3 spec table 5.13
+ static const uint16_t kAC3FrameSizeTable[AC3_NUM_FRAME_SIZE_TABLE_ENTRIES]
+ [AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+ // sample rates from EAC3 spec table E2.3
+ static const uint16_t kEAC3ReducedSampleRateTable[AC3_NUM_SAMPLE_RATE_TABLE_ENTRIES];
+ // audio blocks per frame from EAC3 spec table E2.4
+ static const uint16_t kEAC3BlocksPerFrameTable[EAC3_NUM_BLOCKS_PER_FRAME_TABLE_ENTRIES];
+
+ virtual bool parseHeader();
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_AC3_FRAME_SCANNER_H
diff --git a/utils/spdif/BitFieldParser.cpp b/utils/spdif/BitFieldParser.cpp
new file mode 100644
index 0000000..d513320
--- /dev/null
+++ b/utils/spdif/BitFieldParser.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015, 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 "AudioSPDIF"
+//#define LOG_NDEBUG 0
+
+#include <string.h>
+#include <assert.h>
+
+#include <cutils/log.h>
+#include "BitFieldParser.h"
+
+namespace android {
+
+BitFieldParser::BitFieldParser(uint8_t *data)
+ : mData(data)
+ , mBitCursor(0)
+{
+}
+
+BitFieldParser::~BitFieldParser()
+{
+}
+
+uint32_t BitFieldParser::readBits(uint32_t numBits)
+{
+ ALOG_ASSERT(numBits <= 32);
+
+ // Extract some bits from the current byte.
+ uint32_t byteCursor = mBitCursor >> 3; // 8 bits per byte
+ uint8_t byte = mData[byteCursor];
+
+ uint32_t bitsLeftInByte = 8 - (mBitCursor & 7);
+ uint32_t bitsFromByte = (bitsLeftInByte < numBits) ? bitsLeftInByte : numBits;
+ uint32_t result = byte >> (bitsLeftInByte - bitsFromByte);
+ result &= (1 << bitsFromByte) - 1; // mask
+ mBitCursor += bitsFromByte;
+
+ uint32_t bitsRemaining = numBits - bitsFromByte;
+ if (bitsRemaining == 0) {
+ return result;
+ } else {
+ // Use recursion to get remaining bits.
+ return (result << bitsRemaining) | readBits(bitsRemaining);
+ }
+}
+
+} // namespace android
diff --git a/utils/spdif/BitFieldParser.h b/utils/spdif/BitFieldParser.h
new file mode 100644
index 0000000..1a6d0da
--- /dev/null
+++ b/utils/spdif/BitFieldParser.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2015, 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_BIT_FIELD_PARSER_H
+#define ANDROID_AUDIO_BIT_FIELD_PARSER_H
+
+#include <stdint.h>
+
+namespace android {
+
+/**
+ * Extract bit fields from a byte array.
+ */
+class BitFieldParser {
+public:
+
+ explicit BitFieldParser(uint8_t *data);
+ virtual ~BitFieldParser();
+
+ /**
+ * Read numBits bits from the data array.
+ * Fields may span byte boundaries but may not exceed 32-bits.
+ * Note that the caller must ensure that there is sufficient data.
+ * Assume data is organized as BigEndian format.
+ */
+ uint32_t readBits(uint32_t numBits);
+
+ /*
+ * When the cursor is zero it points to a position right before
+ * the most significant bit.
+ * When the cursor is seven it points to a position right before
+ * the least significant bit.
+ */
+ uint32_t getBitCursor() const { return mBitCursor; }
+
+private:
+ uint8_t *mData;
+ uint32_t mBitCursor;
+};
+
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_BIT_FIELD_PARSER_H
diff --git a/utils/spdif/DTSFrameScanner.cpp b/utils/spdif/DTSFrameScanner.cpp
new file mode 100644
index 0000000..0501fe2
--- /dev/null
+++ b/utils/spdif/DTSFrameScanner.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015, 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 "AudioSPDIF"
+//#define LOG_NDEBUG 0
+
+#include <assert.h>
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include "FrameScanner.h"
+#include "BitFieldParser.h"
+#include "DTSFrameScanner.h"
+
+namespace android {
+
+// TODO Handle termination frames.
+// TODO assert if parse past end of header buffer
+// TODO Handle DTS_HD
+
+const uint8_t DTSFrameScanner::kSyncBytes[] =
+ { 0x7F, 0xFE, 0x80, 0x01 };
+
+const int32_t DTSFrameScanner::kDTSSampleRateTable[DTS_NUM_SAMPLE_RATE_TABLE_ENTRIES]
+ = { -1, 8000, 16000, 32000, -1, -1,
+ 11025, 22050, 44100, -1, -1, 12000, 24000, 48000, -1, -1 };
+
+// Defined in IEC61937-2
+#define IEC61937_DATA_TYPE_DTS_I 11
+#define IEC61937_DATA_TYPE_DTS_II 12
+#define IEC61937_DATA_TYPE_DTS_III 13
+#define IEC61937_DATA_TYPE_DTS_IV 17
+
+#define IEC61937_MAX_SAMPLES_TYPE_I 512
+#define IEC61937_MAX_SAMPLES_TYPE_II 1024
+#define IEC61937_MAX_SAMPLES_TYPE_III 2048
+
+// Limits defined in DTS spec paragraph 5.3.1
+#define DTS_MINIMUM_NBLKS 5
+#define DTS_MINIMUM_FSIZE 95
+
+#define DTS_HEADER_BYTES_NEEDED 12
+
+// Scanner for DTS byte streams.
+DTSFrameScanner::DTSFrameScanner()
+ : FrameScanner(IEC61937_DATA_TYPE_DTS_I,
+ DTSFrameScanner::kSyncBytes,
+ sizeof(DTSFrameScanner::kSyncBytes),
+ DTS_HEADER_BYTES_NEEDED)
+ , mSampleFramesPerSyncFrame(0)
+{
+}
+
+DTSFrameScanner::~DTSFrameScanner()
+{
+}
+
+// Parse DTS header.
+// Detect whether the stream is DTS or DTS_HD. Extract data depending on type.
+// Sets mDataType, mFrameSizeBytes,
+// mSampleRate, mRateMultiplier, mLengthCode.
+//
+// @return true if valid
+bool DTSFrameScanner::parseHeader()
+{
+ BitFieldParser parser(&mHeaderBuffer[mSyncLength]);
+
+ // These variables are named after the fields in the DTS spec 5.3.1
+ // Extract field in order.
+ (void) /* uint32_t ftype = */ parser.readBits(1);
+ (void) /* uint32_t deficit = */ parser.readBits(5); // "short"
+ uint32_t cpf = parser.readBits(1);
+ uint32_t nblks = parser.readBits(7);
+ uint32_t fsize = parser.readBits(14);
+ (void) /* uint32_t amode = */ parser.readBits(6);
+ uint32_t sfreq = parser.readBits(4);
+ // make sure we did not read past collected data
+ ALOG_ASSERT((mSyncLength + ((parser.getBitCursor() + 7) >> 3))
+ <= mHeaderLength);
+
+ // Validate fields.
+ if (cpf != 0) {
+ ALOGE("DTSFrameScanner: ERROR - CPF not zero!");
+ return false;
+ }
+ if (nblks < DTS_MINIMUM_NBLKS) {
+ ALOGE("DTSFrameScanner: ERROR - nblks = %u", nblks);
+ return false;
+ }
+ if (fsize < DTS_MINIMUM_FSIZE) {
+ ALOGE("DTSFrameScanner: ERROR - fsize = %u", fsize);
+ return false;
+ }
+
+ int32_t sampleRate = kDTSSampleRateTable[sfreq];
+ if (sampleRate < 0) {
+ ALOGE("DTSFrameScanner: ERROR - invalid sampleRate[%u] = %d", sfreq, sampleRate);
+ return false;
+ }
+ mSampleRate = (uint32_t) sampleRate;
+
+ mSampleFramesPerSyncFrame = (nblks + 1) * DTS_PCM_FRAMES_PER_BLOCK;
+ if (mSampleFramesPerSyncFrame <= IEC61937_MAX_SAMPLES_TYPE_I) {
+ mDataType = IEC61937_DATA_TYPE_DTS_I;
+ } else if (mSampleFramesPerSyncFrame <= IEC61937_MAX_SAMPLES_TYPE_II) {
+ mDataType = IEC61937_DATA_TYPE_DTS_II;
+ } else if (mSampleFramesPerSyncFrame <= IEC61937_MAX_SAMPLES_TYPE_III) {
+ mDataType = IEC61937_DATA_TYPE_DTS_III;
+ } else {
+ mDataType = IEC61937_DATA_TYPE_DTS_IV;
+ // TODO set bits 8,10
+ }
+
+ mFrameSizeBytes = fsize + 1;
+
+ mRateMultiplier = 1; // TODO what about "frequency extension"?
+ ALOGI_IF((mFormatDumpCount == 0),
+ "DTS frame rate = %d * %d, size = %zu",
+ mSampleRate, mRateMultiplier, mFrameSizeBytes);
+ mFormatDumpCount++;
+ return true;
+}
+
+
+} // namespace android
diff --git a/utils/spdif/DTSFrameScanner.h b/utils/spdif/DTSFrameScanner.h
new file mode 100644
index 0000000..7a394c3
--- /dev/null
+++ b/utils/spdif/DTSFrameScanner.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015, 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_DTS_FRAME_SCANNER_H
+#define ANDROID_AUDIO_DTS_FRAME_SCANNER_H
+
+#include <stdint.h>
+#include "FrameScanner.h"
+
+namespace android {
+
+#define DTS_NUM_SAMPLE_RATE_TABLE_ENTRIES 16
+#define DTS_PCM_FRAMES_PER_BLOCK 32
+#define DTS_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK 128
+
+class DTSFrameScanner : public FrameScanner
+{
+public:
+ DTSFrameScanner();
+ virtual ~DTSFrameScanner();
+
+ virtual int getMaxChannels() const { return 5 + 1; }
+
+ virtual int getMaxSampleFramesPerSyncFrame() const {
+ return DTS_MAX_BLOCKS_PER_SYNC_FRAME_BLOCK * DTS_PCM_FRAMES_PER_BLOCK;
+ }
+
+ virtual int getSampleFramesPerSyncFrame() const {
+ return mSampleFramesPerSyncFrame;
+ }
+
+ virtual bool isFirstInBurst() { return true; }
+ virtual bool isLastInBurst() { return true; }
+ virtual void resetBurst() { }
+
+protected:
+
+ int mSampleFramesPerSyncFrame;
+
+ virtual bool parseHeader();
+
+ static const uint8_t kSyncBytes[];
+ static const int32_t kDTSSampleRateTable[];
+
+};
+
+} // namespace android
+#endif // ANDROID_AUDIO_DTS_FRAME_SCANNER_H
diff --git a/utils/spdif/FrameScanner.cpp b/utils/spdif/FrameScanner.cpp
new file mode 100644
index 0000000..32e5b44
--- /dev/null
+++ b/utils/spdif/FrameScanner.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "AudioSPDIF"
+
+#include <string.h>
+#include <assert.h>
+
+#include <cutils/log.h>
+#include "FrameScanner.h"
+
+namespace android {
+
+FrameScanner::FrameScanner(int dataType,
+ const uint8_t *syncBytes,
+ uint32_t syncLength,
+ uint32_t headerLength)
+ : mBytesSkipped(0)
+ , mSyncBytes(syncBytes)
+ , mSyncLength(syncLength)
+ , mHeaderLength(headerLength)
+ , mCursor(0)
+ , mFormatDumpCount(0)
+ , mSampleRate(0)
+ , mRateMultiplier(1)
+ , mFrameSizeBytes(0)
+ , mDataType(dataType)
+ , mDataTypeInfo(0)
+{
+}
+
+FrameScanner::~FrameScanner()
+{
+}
+
+// State machine that scans for headers in a byte stream.
+// @return true if we have detected a complete and valid header.
+bool FrameScanner::scan(uint8_t byte)
+{
+ bool result = false;
+ ALOGV("FrameScanner: byte = 0x%02X, mCursor = %d", byte, mCursor);
+ assert(mCursor < sizeof(mHeaderBuffer));
+ if (mCursor < mSyncLength) {
+ // match sync word
+ if (byte == mSyncBytes[mCursor]) {
+ mHeaderBuffer[mCursor++] = byte;
+ } else {
+ mBytesSkipped += 1; // skip unsynchronized data
+ mCursor = 0;
+ }
+ } else if (mCursor < mHeaderLength) {
+ // gather header for parsing
+ mHeaderBuffer[mCursor++] = byte;
+ if (mCursor >= mHeaderLength) {
+ if (parseHeader()) {
+ result = true;
+ } else {
+ ALOGE("FrameScanner: ERROR - parseHeader() failed.");
+ }
+ mCursor = 0;
+ }
+ }
+ return result;
+}
+
+} // namespace android
diff --git a/utils/spdif/MatFrameScanner.cpp b/utils/spdif/MatFrameScanner.cpp
new file mode 100644
index 0000000..6008b28
--- /dev/null
+++ b/utils/spdif/MatFrameScanner.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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 "AudioSPDIF"
+//#define LOG_NDEBUG 0
+
+#include <string.h>
+#include <assert.h>
+
+#include <cutils/log.h>
+#include "FrameScanner.h"
+
+#include "MatFrameScanner.h"
+
+namespace android {
+
+// MAT Transport stream sync word
+const uint8_t MatFrameScanner::kSyncBytes[] = { 0x07, 0x9E };
+
+// Defined in IEC61937-9
+#define SPDIF_DATA_TYPE_MAT 22
+
+#define MAT_MAX_CHUNK_SIZE 30720
+
+// MAT transport format
+// { Syncword (16 bits) }
+// { metadata_payload_length (16 bits), Metadata Payload, Payload CRC (16 bits) }
+// { top_of_channels_length (16 bits), Top of Channels Audio Chunk, Payload CRC (16 bits) }
+// { bottom_of_channels_length (16 bits), Bottom of Channels Audio Chunk, Payload CRC (16 bits) }
+// Length does not include bytes for length itself and the CRC after payload.
+
+// For frame parsing, we use three frame chunks for a single IEC61937 frame
+// 1. {syncword, metadata_payload_length, Metadata Payload}
+// 2. {metadata_payload_crc, top_of_channels_length, Top of Channels Audio Chunk}
+// 3. {Top channels chunk crc, bottom_of_channels_length, Bottom of Channels Audio Chunk, Bottom Channels Chunk crc}
+// such that the header buffer for the three "virtual" frames have fixed 4 bytes size (mHeaderLength = 4)
+// and we can control the frame size to collect in each chunk state.
+
+#define CHUNK_TYPE_METADATA 0
+#define CHUNK_TYPE_TOP 1
+#define CHUNK_TYPE_BOTTOM 2
+
+MatFrameScanner::MatFrameScanner()
+ : FrameScanner(SPDIF_DATA_TYPE_MAT,
+ MatFrameScanner::kSyncBytes,
+ sizeof(MatFrameScanner::kSyncBytes), 4)
+ , mChunkType(CHUNK_TYPE_METADATA)
+ , mLastChunk(false)
+{
+}
+
+MatFrameScanner::~MatFrameScanner()
+{
+}
+
+void MatFrameScanner::resetBurst()
+{
+ mChunkType = CHUNK_TYPE_METADATA;
+}
+
+// Per IEC 61973-9:5.3.1, for MAT burst-length shall be in bytes.
+uint16_t MatFrameScanner::convertBytesToLengthCode(uint16_t numBytes) const
+{
+ return numBytes;
+}
+
+bool MatFrameScanner::isLastInBurst()
+{
+ return mLastChunk;
+}
+
+bool MatFrameScanner::parseHeader()
+{
+ size_t payload_length = ((size_t)(mHeaderBuffer[2]) << 8) | mHeaderBuffer[3];
+
+ if ((payload_length <= 0) || (payload_length > MAT_MAX_CHUNK_SIZE))
+ return false;
+
+ payload_length <<= 1; // convert to bytes
+
+ if (mChunkType == CHUNK_TYPE_METADATA) {
+ mFrameSizeBytes = mHeaderLength; // sync word, metadata length
+ mFrameSizeBytes += payload_length;
+ mChunkType = CHUNK_TYPE_TOP;
+ mLastChunk = false;
+ } else if (mChunkType == CHUNK_TYPE_TOP) {
+ mFrameSizeBytes = mHeaderLength; // metadata crc, top length
+ mFrameSizeBytes += payload_length;
+ mChunkType = CHUNK_TYPE_BOTTOM;
+ mLastChunk = false;
+ } else {
+ mFrameSizeBytes = mHeaderLength; // top crc, bottom length
+ mFrameSizeBytes += payload_length;
+ mFrameSizeBytes += 2; // bottom crc
+ mChunkType = CHUNK_TYPE_METADATA;
+ mLastChunk = true;
+ }
+
+ return true;
+}
+
+// State machine that scans for headers in a byte stream.
+// @return true if we have detected a complete and valid header.
+bool MatFrameScanner::scan(uint8_t byte)
+{
+ bool result = false;
+
+ //ALOGV("MatFrameScanner: byte = 0x%02X, mCursor = %d", byte, mCursor);
+ assert(mCursor < sizeof(mHeaderBuffer));
+
+ if ((mChunkType == CHUNK_TYPE_METADATA) && (mCursor < mSyncLength)) {
+ // match sync word
+ if (byte == mSyncBytes[mCursor]) {
+ mHeaderBuffer[mCursor++] = byte;
+ } else {
+ mBytesSkipped += 1; // skip unsynchronized data
+ mCursor = 0;
+ }
+ } else if (mCursor < mHeaderLength) {
+ // gather header for parsing metadata payload length
+ mHeaderBuffer[mCursor++] = byte;
+ if (mCursor >= mHeaderLength) {
+ if (parseHeader()) {
+ result = true;
+ } else {
+ ALOGE("MatFrameScanner: ERROR - parseHeader() failed.");
+ }
+ mCursor = 0;
+ }
+ }
+
+ return result;
+}
+
+} // namespace android
diff --git a/utils/spdif/MatFrameScanner.h b/utils/spdif/MatFrameScanner.h
new file mode 100644
index 0000000..f51f528
--- /dev/null
+++ b/utils/spdif/MatFrameScanner.h
@@ -0,0 +1,59 @@
+/*
+ * 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_MAT_FRAME_SCANNER_H
+#define ANDROID_AUDIO_MAT_FRAME_SCANNER_H
+
+#include <stdint.h>
+#include "FrameScanner.h"
+
+namespace android {
+
+#define MAT_PCM_FRAMES 1536
+#define MAT_RATE_MULTIPLIER 10
+
+class MatFrameScanner : public FrameScanner
+{
+public:
+ MatFrameScanner();
+ virtual ~MatFrameScanner();
+
+ virtual int getMaxChannels() const { return 5 + 1 + 2; } // 5.1.2 surround
+
+ virtual int getMaxSampleFramesPerSyncFrame() const { return MAT_RATE_MULTIPLIER
+ * MAT_PCM_FRAMES; }
+ virtual int getSampleFramesPerSyncFrame() const { return MAT_RATE_MULTIPLIER
+ * MAT_PCM_FRAMES; }
+
+ virtual bool isFirstInBurst() { return false; }
+ virtual bool isLastInBurst();
+ virtual void resetBurst();
+
+ virtual uint16_t convertBytesToLengthCode(uint16_t numBytes) const;
+ virtual bool scan(uint8_t byte);
+
+protected:
+ // used to recognize the start of a MAT sync frame
+ static const uint8_t kSyncBytes[];
+ int mChunkType;
+ bool mLastChunk;
+
+ virtual bool parseHeader();
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_MAT_FRAME_SCANNER_H
diff --git a/utils/spdif/SPDIFEncoder.cpp b/utils/spdif/SPDIFEncoder.cpp
new file mode 100644
index 0000000..6bd1a08
--- /dev/null
+++ b/utils/spdif/SPDIFEncoder.cpp
@@ -0,0 +1,281 @@
+/*
+ * 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>
+#include <string.h>
+
+#define LOG_TAG "AudioSPDIF"
+#include <cutils/log.h>
+
+#include "system/audio-base.h"
+#include "SPDIFEncoder.h"
+#include "AC3FrameScanner.h"
+#include "DTSFrameScanner.h"
+#include "MatFrameScanner.h"
+
+namespace android {
+
+// Burst Preamble defined in IEC61937-1
+const uint16_t SPDIFEncoder::kSPDIFSync1 = 0xF872; // Pa
+const uint16_t SPDIFEncoder::kSPDIFSync2 = 0x4E1F; // Pb
+
+static int32_t sEndianDetector = 1;
+#define isLittleEndian() (*((uint8_t *)&sEndianDetector))
+
+SPDIFEncoder::SPDIFEncoder(audio_format_t format)
+ : mFramer(NULL)
+ , mSampleRate(48000)
+ , mBurstBuffer(NULL)
+ , mBurstBufferSizeBytes(0)
+ , mRateMultiplier(1)
+ , mBurstFrames(0)
+ , mByteCursor(0)
+ , mBitstreamNumber(0)
+ , mPayloadBytesPending(0)
+ , mScanning(true)
+ , mFrameSize(0)
+{
+ switch (format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ mFramer = new AC3FrameScanner(format);
+ break;
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ mFramer = new DTSFrameScanner();
+ break;
+ case AUDIO_FORMAT_MAT:
+ mFramer = new MatFrameScanner();
+ break;
+ default:
+ break;
+ }
+
+ // This a programmer error. Call isFormatSupported() first.
+ LOG_ALWAYS_FATAL_IF((mFramer == NULL),
+ "SPDIFEncoder: invalid audio format = 0x%08X", format);
+
+ mBurstBufferSizeBytes = sizeof(uint16_t)
+ * SPDIF_ENCODED_CHANNEL_COUNT
+ * mFramer->getMaxSampleFramesPerSyncFrame();
+
+ ALOGI("SPDIFEncoder: mBurstBufferSizeBytes = %zu, littleEndian = %d",
+ mBurstBufferSizeBytes, isLittleEndian());
+ mBurstBuffer = new uint16_t[mBurstBufferSizeBytes >> 1];
+ clearBurstBuffer();
+}
+
+SPDIFEncoder::SPDIFEncoder()
+ : SPDIFEncoder(AUDIO_FORMAT_AC3)
+{
+}
+
+SPDIFEncoder::~SPDIFEncoder()
+{
+ delete[] mBurstBuffer;
+ delete mFramer;
+}
+
+bool SPDIFEncoder::isFormatSupported(audio_format_t format)
+{
+ switch (format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int SPDIFEncoder::getBytesPerOutputFrame()
+{
+ return SPDIF_ENCODED_CHANNEL_COUNT * sizeof(int16_t);
+}
+
+void SPDIFEncoder::writeBurstBufferShorts(const uint16_t *buffer, size_t numShorts)
+{
+ // avoid static analyser warning
+ LOG_ALWAYS_FATAL_IF((mBurstBuffer == NULL), "mBurstBuffer never allocated");
+ 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!");
+ reset();
+ 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!");
+ 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!");
+ clearBurstBuffer();
+ } else {
+ // We don't have to write zeros because buffer already set to zero
+ // by clearBurstBuffer(). Just pretend we wrote zeros by
+ // incrementing cursor.
+ mByteCursor = burstSize;
+ }
+}
+
+void SPDIFEncoder::reset()
+{
+ ALOGV("SPDIFEncoder: reset()");
+ clearBurstBuffer();
+ if (mFramer != NULL) {
+ mFramer->resetBurst();
+ }
+ mPayloadBytesPending = 0;
+ mScanning = true;
+}
+
+void SPDIFEncoder::flushBurstBuffer()
+{
+ const int preambleSize = 4 * sizeof(uint16_t);
+ if (mByteCursor > preambleSize) {
+ // Set lengthCode for valid payload before zeroPad.
+ uint16_t numBytes = (mByteCursor - preambleSize);
+ mBurstBuffer[3] = mFramer->convertBytesToLengthCode(numBytes);
+
+ sendZeroPad();
+ writeOutput(mBurstBuffer, mByteCursor);
+ }
+ reset();
+}
+
+void SPDIFEncoder::clearBurstBuffer()
+{
+ if (mBurstBuffer) {
+ memset(mBurstBuffer, 0, mBurstBufferSizeBytes);
+ }
+ mByteCursor = 0;
+}
+
+void 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] = 0; // lengthCode - This will get set after the buffer is full.
+ writeBurstBufferShorts(preamble, 4);
+}
+
+size_t SPDIFEncoder::startSyncFrame()
+{
+ // Write start of encoded frame that was buffered in frame detector.
+ size_t syncSize = mFramer->getHeaderSizeBytes();
+ writeBurstBufferBytes(mFramer->getHeaderAddress(), syncSize);
+ 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: mScanning = %d, write(buffer[0] = 0x%02X, numBytes = %zu)",
+ mScanning, (uint) *data, numBytes);
+ while (bytesLeft > 0) {
+ if (mScanning) {
+ // Look for beginning of next encoded frame.
+ if (mFramer->scan(*data)) {
+ if (mByteCursor == 0) {
+ startDataBurst();
+ } else if (mFramer->isFirstInBurst()) {
+ // Make sure that this frame is at the beginning of the data burst.
+ flushBurstBuffer();
+ startDataBurst();
+ }
+ mPayloadBytesPending = startSyncFrame();
+ mScanning = false;
+ }
+ data++;
+ bytesLeft--;
+ } else {
+ // Write payload until we hit end of frame.
+ 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()) {
+ flushBurstBuffer();
+ }
+ mScanning = true;
+ }
+ }
+ }
+ return numBytes;
+}
+
+} // namespace android
diff --git a/utils/spdifenc_wrap.cpp b/utils/spdifenc_wrap.cpp
index b2561b6..a757d78 100644
--- a/utils/spdifenc_wrap.cpp
+++ b/utils/spdifenc_wrap.cpp
@@ -25,8 +25,8 @@
#include <sound/asound.h>
#include <cutils/log.h>
#include <system/audio.h>
-#include <audio_utils/spdif/SPDIFEncoder.h>
+#include "SPDIFEncoder.h"
#include <tinyalsa/asoundlib.h>
#include <cutils/properties.h>
#include <string.h>