You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
8.1 KiB
275 lines
8.1 KiB
/* |
|
* 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 <utils/Log.h> |
|
#include <audio_utils/spdif/SPDIFEncoder.h> |
|
|
|
#include "AC3FrameScanner.h" |
|
#include "DTSFrameScanner.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) |
|
{ |
|
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; |
|
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
|
|
|