1 /*
2 * Copyright 2023, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdint.h>
18 #include <string.h>
19
20 #define LOG_TAG "AudioSPDIF"
21 // #define LOG_NDEBUG 0
22 #include <log/log.h>
23 #include <audio_utils/spdif/SPDIFDecoder.h>
24
25 #include "SPDIFFrameScanner.h"
26
27 namespace android {
28
SPDIFDecoder(audio_format_t format)29 SPDIFDecoder::SPDIFDecoder(audio_format_t format)
30 : mFramer(std::make_unique<SPDIFFrameScanner>(format))
31 , mBurstDataBuffer(sizeof(uint16_t) * kSpdifEncodedChannelCount
32 * mFramer->getMaxSampleFramesPerSyncFrame())
33 , mPayloadBytesPending(0)
34 , mPayloadBytesRead(0)
35 , mScanning(true) {
36 }
37
isFormatSupported(audio_format_t format)38 bool SPDIFDecoder::isFormatSupported(audio_format_t format) {
39 switch (format) {
40 case AUDIO_FORMAT_AC3:
41 case AUDIO_FORMAT_E_AC3:
42 case AUDIO_FORMAT_E_AC3_JOC:
43 return true;
44 default:
45 return false;
46 }
47 }
48
reset()49 void SPDIFDecoder::reset() {
50 ALOGV("SPDIFDecoder: reset()");
51 if (mFramer != NULL) {
52 mFramer->resetBurst();
53 }
54 mPayloadBytesPending = 0;
55 mPayloadBytesRead = 0;
56 mScanning = true;
57 }
58
fillBurstDataBuffer()59 ssize_t SPDIFDecoder::fillBurstDataBuffer() {
60 const auto bytesToFill = mBurstDataBuffer.availableToWrite();
61 std::vector<uint8_t> tmpBuffer(bytesToFill);
62 auto bytesRead = readInput(&tmpBuffer[0], bytesToFill);
63 if (bytesRead > 0) {
64 ALOGV("SPDIFDecoder: read %zd burst data bytes", bytesRead);
65 auto written = mBurstDataBuffer.write(tmpBuffer.data(), bytesRead);
66 LOG_ALWAYS_FATAL_IF(written != bytesRead);
67 }
68 return bytesRead;
69 }
70
71 // Read burst payload data.
read(void * buffer,size_t numBytes)72 ssize_t SPDIFDecoder::read(void *buffer, size_t numBytes) {
73 size_t bytesRead = 0;
74 uint16_t *buf = reinterpret_cast<uint16_t *>(buffer);
75 ALOGV("SPDIFDecoder: mScanning = %d numBytes = %zu", mScanning, numBytes);
76 while (bytesRead < numBytes) {
77 if (mBurstDataBuffer.empty()) {
78 if (fillBurstDataBuffer() <= 0) {
79 return -1;
80 }
81 if (bytesRead > 0) {
82 return bytesRead;
83 }
84 }
85 if (mScanning) {
86 // Look for beginning of next IEC61937 frame.
87 if (!mBurstDataBuffer.empty() && mFramer->scan(mBurstDataBuffer.readByte())) {
88 mPayloadBytesPending = mFramer->getFrameSizeBytes();
89 mPayloadBytesRead = 0;
90 mScanning = false;
91 }
92 } else {
93 // Read until we hit end of burst payload.
94 size_t bytesToRead = std::min(numBytes, mBurstDataBuffer.availableToRead());
95 // Only read as many as we need to finish the frame.
96 if (bytesToRead > mPayloadBytesPending) {
97 bytesToRead = mPayloadBytesPending;
98 }
99 // Unpack the bytes from short buffer into byte array in the order:
100 // short[0] MSB -> byte[0]
101 // short[0] LSB -> byte[1]
102 // short[1] MSB -> byte[2]
103 // short[1] LSB -> byte[3]
104 // ...
105 // This way the payload should be extracted correctly on both
106 // Big and Little Endian CPUs.
107 uint16_t pad = 0;
108 size_t actualBytesRead = 0;
109 for (; !mBurstDataBuffer.empty() && actualBytesRead < bytesToRead; ++actualBytesRead) {
110 if (mPayloadBytesRead & 1) {
111 pad |= mBurstDataBuffer.readByte(); // Read second byte from LSB
112 buf[bytesRead >> 1] = pad;
113 pad = 0;
114 } else {
115 pad |= mBurstDataBuffer.readByte() << 8; // Read first byte from MSB
116 }
117 mPayloadBytesRead++;
118 bytesRead++;
119 }
120 // Read out last byte from partially filled short.
121 if (mPayloadBytesRead & 1) {
122 reinterpret_cast<uint8_t *>(buffer)[bytesRead] = pad >> 8;
123 }
124
125 buf += (bytesRead >> 1);
126 mPayloadBytesPending -= actualBytesRead;
127 mPayloadBytesRead += actualBytesRead;
128
129 // If we have read the entire payload, prepare to look for the next IEC61937 frame.
130 if (mPayloadBytesPending == 0) {
131 reset();
132 }
133 }
134 }
135 return numBytes;
136 }
137
138 } // namespace android
139