SPDIF: add DTS support to SPDIF wrapper
Refactor AC3 out of FrameScanner.cpp.
Simplify scanning state machine and move up into FrameScanner.cpp.
Bug: 18292317
Change-Id: Iaefdce9c960abbea5dcdc2390a5da00181da0f8c
Signed-off-by: Phil Burk <philburk@google.com>
diff --git a/audio_utils/include/audio_utils/spdif/FrameScanner.h b/audio_utils/include/audio_utils/spdif/FrameScanner.h
index ff245e4..7b88ae2 100644
--- a/audio_utils/include/audio_utils/spdif/FrameScanner.h
+++ b/audio_utils/include/audio_utils/spdif/FrameScanner.h
@@ -1,19 +1,18 @@
/*
-**
-** 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.
-*/
+ * 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
@@ -33,25 +32,28 @@
*/
class FrameScanner {
public:
-
- FrameScanner(int dataType);
+ 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) = 0;
+ virtual bool scan(uint8_t byte);
/**
* @return address of where the sync header was stored by scan()
*/
- virtual const uint8_t *getHeaderAddress() const = 0;
+ const uint8_t *getHeaderAddress() const { return mHeaderBuffer; }
/**
* @return number of bytes in sync header stored by scan()
*/
- virtual size_t getHeaderSizeBytes() const = 0;
+ size_t getHeaderSizeBytes() const { return mHeaderLength; }
/**
* @return sample rate of the encoded audio
@@ -71,8 +73,8 @@
/**
* dataType is defined by the SPDIF standard for each format
*/
- virtual int getDataType() const { return mDataType; }
- virtual int getDataTypeInfo() const { return mDataTypeInfo; }
+ int getDataType() const { return mDataType; }
+ int getDataTypeInfo() const { return mDataTypeInfo; }
virtual int getMaxChannels() const = 0;
@@ -96,77 +98,28 @@
virtual bool isLastInBurst() = 0;
protected:
- uint32_t mSampleRate;
- uint32_t mRateMultiplier;
- size_t mFrameSizeBytes;
- int mDataType;
- int mDataTypeInfo;
-};
+ 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
-#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:
- 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 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();
- virtual void resetBurst();
-
-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];
- uint8_t mSubstreamBlockCounts[EAC3_MAX_SUBSTREAMS];
- 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];
+ /**
+ * 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/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
index b880a93..171fec1 100644
--- a/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
+++ b/audio_utils/include/audio_utils/spdif/SPDIFEncoder.h
@@ -1,24 +1,24 @@
/*
-**
-** 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.
-*/
+ * 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 <hardware/audio.h>
#include <audio_utils/spdif/FrameScanner.h>
namespace android {
@@ -34,30 +34,49 @@
class SPDIFEncoder {
public:
+ 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.
+ /**
+ * 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 by caller.
+ /**
+ * 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 ration of the encoded data burst sample rate to the encoded rate.
- // For example, EAC3 data bursts are 4X the encoded rate.
+ /**
+ * 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 the number of PCM frames in a data burst.
+ /**
+ * @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.
+ /**
+ * @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);
+
protected:
void clearBurstBuffer();
-
void writeBurstBufferShorts(const uint16_t* buffer, size_t numBytes);
void writeBurstBufferBytes(const uint8_t* buffer, size_t numBytes);
void sendZeroPad();
@@ -65,25 +84,20 @@
void startDataBurst();
size_t startSyncFrame();
- // 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;
+ 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;
+ size_t mByteCursor; // cursor into data burst
int mBitstreamNumber;
- size_t mPayloadBytesPending;
+ size_t mPayloadBytesPending; // number of bytes needed to finish burst
+ // state variable, true if scanning for start of frame
+ bool mScanning;
static const unsigned short kSPDIFSync1; // Pa
static const unsigned short kSPDIFSync2; // Pb
diff --git a/audio_utils/spdif/AC3FrameScanner.cpp b/audio_utils/spdif/AC3FrameScanner.cpp
new file mode 100644
index 0000000..7f8068d
--- /dev/null
+++ b/audio_utils/spdif/AC3FrameScanner.cpp
@@ -0,0 +1,238 @@
+/*
+ * 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 <utils/Log.h>
+#include <audio_utils/spdif/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()
+ : FrameScanner(SPDIF_DATA_TYPE_AC3,
+ AC3FrameScanner::kSyncBytes,
+ sizeof(AC3FrameScanner::kSyncBytes), 6)
+ , mStreamType(0)
+ , mSubstreamID(0)
+{
+ 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 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;
+ }
+
+ // 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\n", 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].
+ 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\n", fscod);
+ return false;
+ } else if (frmsizcod >= AC3_NUM_FRAME_SIZE_TABLE_ENTRIES) {
+ ALOGW("Invalid AC3 frameSizeCode = %d\n", frmsizcod);
+ return false;
+ } else {
+ mSampleRate = kAC3SampleRateTable[fscod];
+ mRateMultiplier = 1;
+ mFrameSizeBytes = sizeof(uint16_t)
+ * kAC3FrameSizeTable[frmsizcod][fscod];
+ }
+ mAudioBlocksPerSyncFrame = 6;
+ }
+ ALOGI_IF((mFormatDumpCount == 0),
+ "AC3 frame rate = %d * %d, size = %d, audioBlocksPerSyncFrame = %d\n",
+ mSampleRate, mRateMultiplier, mFrameSizeBytes, mAudioBlocksPerSyncFrame);
+ mFormatDumpCount++;
+ return true;
+}
+
+} // namespace android
diff --git a/audio_utils/spdif/AC3FrameScanner.h b/audio_utils/spdif/AC3FrameScanner.h
new file mode 100644
index 0000000..f944dcc
--- /dev/null
+++ b/audio_utils/spdif/AC3FrameScanner.h
@@ -0,0 +1,77 @@
+/*
+ * 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 <audio_utils/spdif/FrameScanner.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:
+ AC3FrameScanner();
+ 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();
+
+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;
+
+ // 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/audio_utils/spdif/Android.mk b/audio_utils/spdif/Android.mk
index 5d1ac49..39c2fa2 100644
--- a/audio_utils/spdif/Android.mk
+++ b/audio_utils/spdif/Android.mk
@@ -6,7 +6,10 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= \
+ BitFieldParser.cpp \
FrameScanner.cpp \
+ AC3FrameScanner.cpp \
+ DTSFrameScanner.cpp \
SPDIFEncoder.cpp
LOCAL_C_INCLUDES += $(call include-path-for, audio-utils)
diff --git a/audio_utils/spdif/BitFieldParser.cpp b/audio_utils/spdif/BitFieldParser.cpp
new file mode 100644
index 0000000..8f1c11e
--- /dev/null
+++ b/audio_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 <utils/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/audio_utils/spdif/BitFieldParser.h b/audio_utils/spdif/BitFieldParser.h
new file mode 100644
index 0000000..1cf45d0
--- /dev/null
+++ b/audio_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:
+
+ 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 suffcient 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/audio_utils/spdif/DTSFrameScanner.cpp b/audio_utils/spdif/DTSFrameScanner.cpp
new file mode 100644
index 0000000..7ee4fd4
--- /dev/null
+++ b/audio_utils/spdif/DTSFrameScanner.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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 <utils/Log.h>
+#include <audio_utils/spdif/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.
+ uint32_t ftype = parser.readBits(1);
+ 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);
+ uint32_t amode = parser.readBits(6);
+ uint32_t sfreq = parser.readBits(4);
+ uint32_t rate = parser.readBits(5);
+ // 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[rate];
+ if (sampleRate < 0) {
+ ALOGE("DTSFrameScanner: ERROR - invalid sampleRate = %d", 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 = %d\n",
+ mSampleRate, mRateMultiplier, mFrameSizeBytes);
+ mFormatDumpCount++;
+ return true;
+}
+
+
+} // namespace android
diff --git a/audio_utils/spdif/DTSFrameScanner.h b/audio_utils/spdif/DTSFrameScanner.h
new file mode 100644
index 0000000..883ded9
--- /dev/null
+++ b/audio_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 <audio_utils/spdif/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/audio_utils/spdif/FrameScanner.cpp b/audio_utils/spdif/FrameScanner.cpp
index 72edd20..80c1d94 100644
--- a/audio_utils/spdif/FrameScanner.cpp
+++ b/audio_utils/spdif/FrameScanner.cpp
@@ -1,36 +1,40 @@
/*
-**
-** 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.
-*/
+ * 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 <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)
+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)
@@ -42,256 +46,34 @@
{
}
-// ------------------- 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)
- , mAudioBlocksPerSyncFrame(6)
- , mCursor(AC3_SYNCWORD_SIZE) // past sync word
- , mStreamType(0)
- , mSubstreamID(0)
- , mFormatDumpCount(0)
-{
- memset(mSubstreamBlockCounts, 0, sizeof(mSubstreamBlockCounts));
- // 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;
-}
-
-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 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 == 0) || (mStreamType == 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.
-}
-
-// 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; // strmtyp in spec
- mSubstreamID = (mHeaderBuffer[2] >> 3) & 0x07;
-
- // 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
- // 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].
- 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.
- 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;
- }
- 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.
+// State machine that scans for headers in a byte stream.
// @return true if we have detected a complete and valid header.
-bool AC3FrameScanner::scan(uint8_t byte)
+bool FrameScanner::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
+ bool result = false;
+ ALOGV("FrameScanner: byte = 0x%02X, mCursor = %d\n", 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;
}
- 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;
+ } 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 = AC3_SYNCWORD_SIZE;
- nextState = STATE_GATHERING; // advance
- } else if (byte == kAC3SyncByte1) {
- nextState = STATE_EXPECTING_SYNC_2; // resync
- } else {
- nextState = STATE_EXPECTING_SYNC_1; // restart
+ mCursor = 0;
}
- 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;
+ return result;
}
} // namespace android
diff --git a/audio_utils/spdif/SPDIFEncoder.cpp b/audio_utils/spdif/SPDIFEncoder.cpp
index 99cde2a..251e367 100644
--- a/audio_utils/spdif/SPDIFEncoder.cpp
+++ b/audio_utils/spdif/SPDIFEncoder.cpp
@@ -1,20 +1,18 @@
/*
-**
-** 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.
-*/
-
+ * 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>
@@ -23,6 +21,9 @@
#include <utils/Log.h>
#include <audio_utils/spdif/SPDIFEncoder.h>
+#include "AC3FrameScanner.h"
+#include "DTSFrameScanner.h"
+
namespace android {
// Burst Preamble defined in IEC61937-1
@@ -32,9 +33,8 @@
static int32_t sEndianDetector = 1;
#define isLittleEndian() (*((uint8_t *)&sEndianDetector))
-SPDIFEncoder::SPDIFEncoder()
- : mState(STATE_IDLE)
- , mSampleRate(48000)
+SPDIFEncoder::SPDIFEncoder(audio_format_t format)
+ : mSampleRate(48000)
, mBurstBuffer(NULL)
, mBurstBufferSizeBytes(0)
, mRateMultiplier(1)
@@ -42,9 +42,22 @@
, mByteCursor(0)
, mBitstreamNumber(0)
, mPayloadBytesPending(0)
+ , mScanning(true)
{
- // TODO support other compressed audio formats
- mFramer = new AC3FrameScanner();
+ switch(format) {
+ case AUDIO_FORMAT_AC3:
+ case AUDIO_FORMAT_E_AC3:
+ mFramer = new AC3FrameScanner();
+ break;
+ case AUDIO_FORMAT_DTS:
+ case AUDIO_FORMAT_DTS_HD:
+ mFramer = new DTSFrameScanner();
+ break;
+ default:
+ ALOGE("SPDIFEncoder: ERROR invalid audio format = 0x%08X", format);
+ mFramer = NULL;
+ break;
+ }
mBurstBufferSizeBytes = sizeof(uint16_t)
* SPDIF_ENCODED_CHANNEL_COUNT
@@ -56,9 +69,28 @@
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()
@@ -182,13 +214,11 @@
{
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);
+ ALOGV("SPDIFEncoder: mScanning = %d, write(buffer[0] = 0x%02X, numBytes = %u)",
+ mScanning, (uint) *data, numBytes);
while (bytesLeft > 0) {
- State nextState = mState;
- switch (mState) {
+ if (mScanning) {
// Look for beginning of next encoded frame.
- case STATE_IDLE:
if (mFramer->scan(*data)) {
if (mByteCursor == 0) {
startDataBurst();
@@ -198,42 +228,31 @@
startDataBurst();
}
mPayloadBytesPending = startSyncFrame();
- nextState = STATE_BURST;
+ mScanning = false;
}
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()) {
- flushBurstBuffer();
- }
- nextState = STATE_IDLE;
- }
+ } 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;
}
- break;
+ writeBurstBufferBytes(data, bytesToWrite);
- default:
- ALOGE("SPDIFEncoder: illegal state = %d\n", mState);
- nextState = STATE_IDLE;
- break;
+ 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;
+ }
}
- mState = nextState;
}
return numBytes;
}