/* * 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 unsigned short SPDIFEncoder::kSPDIFSync1 = 0xF872; // Pa const unsigned short SPDIFEncoder::kSPDIFSync2 = 0x4E1F; // Pb static int32_t sEndianDetector = 1; #define isLittleEndian() (*((uint8_t *)&sEndianDetector)) SPDIFEncoder::SPDIFEncoder(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(); 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