1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
23
24
27
28
29
30
31
32
33
34
35
36
37
38
39
44
45
46
47
48
49
51
52
53
56
57
58
82
101
102
103
104
105
106
107
108
109
110
111
112
113
116
126
127
128
129
130
131
132
133
134
135
140
141
142
143
144
154
155
160
161
162
163
164
165
166
169
175
176
179
180
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
215
219
220
224
225
226
227
228
229
230
231
232
233
234
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
256
257
258
262
263
264
265
266
271
275
276
280
281
285
286
293
294
298
299
300
301
302
307
308
309
321
322
327
328
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
350
353
354
355
358
359
362
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
385
386
389
390
391
392
393
394
395
396
397
398
414
415
416
417
423
424
425
426
427
428
429
430
431
437
438
444
445
446
447
451
452
453
454
455
456
457
458
459
460
462
463
467
468
469
470
471
472
/* ... */
/* ... */
/* ... */
#include "common/bt_target.h"
#include "oi_codec_sbc_private.h"
#include "oi_bitstream.h"
#if (defined(SBC_DEC_INCLUDED) && SBC_DEC_INCLUDED == TRUE)
#define SPECIALIZE_READ_SAMPLES_JOINT
/* ... */
PRIVATE OI_STATUS FindSyncword(OI_CODEC_SBC_DECODER_CONTEXT *context,
const OI_BYTE **frameData,
OI_UINT32 *frameBytes)
{
#ifdef SBC_ENHANCED
OI_BYTE search1 = OI_SBC_SYNCWORD;
OI_BYTE search2 = OI_SBC_ENHANCED_SYNCWORD;/* ... */
#endif
if (*frameBytes == 0) {
return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
}{...}
#ifdef SBC_ENHANCED
if (context->limitFrameFormat && context->enhancedEnabled) {
search1 = search2;
}{...} else if (context->enhancedEnabled == FALSE) {
search2 = search1;
}{...}
while (*frameBytes && (**frameData != search1) && (**frameData != search2)) {
(*frameBytes)--;
(*frameData)++;
}{...}
if (*frameBytes) {
/* ... */
context->common.frameInfo.enhanced = (**frameData == OI_SBC_ENHANCED_SYNCWORD);
return OI_OK;
}{...} else {
/* ... */
return OI_CODEC_SBC_NO_SYNCWORD;
}{...}
/* ... */#else
while (*frameBytes
&& (!(context->sbc_mode == OI_SBC_MODE_STD && **frameData == OI_SBC_SYNCWORD))
&& (!(context->sbc_mode == OI_SBC_MODE_MSBC && **frameData == OI_mSBC_SYNCWORD))) {
(*frameBytes)--;
(*frameData)++;
}{...}
if (*frameBytes) {
/* ... */
context->common.frameInfo.enhanced = FALSE;
return OI_OK;
}{...} else {
/* ... */
return OI_CODEC_SBC_NO_SYNCWORD;
}{...}
/* ... */#endif
}{...}
static OI_STATUS DecodeBody(OI_CODEC_SBC_DECODER_CONTEXT *context,
const OI_BYTE *bodyData,
OI_INT16 *pcmData,
OI_UINT32 *pcmBytes,
OI_BOOL allowPartial)
{
OI_BITSTREAM bs;
OI_UINT frameSamples = context->common.frameInfo.nrof_blocks * context->common.frameInfo.nrof_subbands;
OI_UINT decode_block_count;
/* ... */
if (*pcmBytes < (sizeof(OI_INT16) * frameSamples * context->common.pcmStride) && !allowPartial) {
/* ... */
TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA"));
return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
}{...} else if (*pcmBytes < sizeof (OI_INT16) * context->common.frameInfo.nrof_subbands * context->common.pcmStride) {
/* ... */
return OI_CODEC_SBC_NOT_ENOUGH_AUDIO_DATA;
}{...}
if (context->bufferedBlocks == 0) {
TRACE(("Reading scalefactors"));
OI_SBC_ReadScalefactors(&context->common, bodyData, &bs);
TRACE(("Computing bit allocation"));
OI_SBC_ComputeBitAllocation(&context->common);
TRACE(("Reading samples"));
if (context->common.frameInfo.mode == SBC_JOINT_STEREO) {
OI_SBC_ReadSamplesJoint(context, &bs);
}{...} else {
OI_SBC_ReadSamples(context, &bs);
}{...}
context->bufferedBlocks = context->common.frameInfo.nrof_blocks;
}{...}
if (allowPartial) {
decode_block_count = *pcmBytes / sizeof(OI_INT16) / context->common.pcmStride / context->common.frameInfo.nrof_subbands;
if (decode_block_count > context->bufferedBlocks) {
decode_block_count = context->bufferedBlocks;
}{...}
}{...} else {
decode_block_count = context->common.frameInfo.nrof_blocks;
}{...}
TRACE(("Synthesizing frame"));
{
OI_UINT start_block = context->common.frameInfo.nrof_blocks - context->bufferedBlocks;
OI_SBC_SynthFrame(context, pcmData, start_block, decode_block_count);
}{...}
OI_ASSERT(context->bufferedBlocks >= decode_block_count);
context->bufferedBlocks -= decode_block_count;
frameSamples = decode_block_count * context->common.frameInfo.nrof_subbands;
/* ... */
if (context->common.frameInfo.nrof_channels == 1 && context->common.pcmStride == 2) {
OI_UINT i;
for (i = 0; i < frameSamples; ++i) {
pcmData[2 * i + 1] = pcmData[2 * i];
}{...}
}{...}
/* ... */
*pcmBytes = frameSamples * sizeof(OI_INT16) * context->common.pcmStride;
if (context->bufferedBlocks > 0) {
return OI_CODEC_SBC_PARTIAL_DECODE;
}{...} else {
return OI_OK;
}{...}
}{...}
PRIVATE OI_STATUS internal_DecodeRaw(OI_CODEC_SBC_DECODER_CONTEXT *context,
OI_UINT8 bitpool,
const OI_BYTE **frameData,
OI_UINT32 *frameBytes,
OI_INT16 *pcmData,
OI_UINT32 *pcmBytes)
{
OI_STATUS status;
OI_UINT bodyLen;
TRACE(("+OI_CODEC_SBC_DecodeRaw"));
if (context->bufferedBlocks == 0) {
/* ... */
context->common.frameInfo.bitpool = bitpool;
/* ... */
bodyLen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo) - SBC_HEADER_LEN;
if (*frameBytes < bodyLen) {
TRACE(("-OI_CODEC_SBC_Decode: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
}{...}
}{...} else {
bodyLen = 0;
}{...}
/* ... */
status = DecodeBody(context, *frameData, pcmData, pcmBytes, TRUE);
if (OI_SUCCESS(status) || status == OI_CODEC_SBC_PARTIAL_DECODE) {
*frameData += bodyLen;
*frameBytes -= bodyLen;
}{...}
TRACE(("-OI_CODEC_SBC_DecodeRaw: %d", status));
return status;
}{...}
OI_STATUS OI_CODEC_SBC_DecoderReset(OI_CODEC_SBC_DECODER_CONTEXT *context,
OI_UINT32 *decoderData,
OI_UINT32 decoderDataBytes,
OI_UINT8 maxChannels,
OI_UINT8 pcmStride,
OI_BOOL enhanced,
OI_BOOL msbc_enable)
{
return internal_DecoderReset(context, decoderData, decoderDataBytes, maxChannels, pcmStride, enhanced, msbc_enable);
}{...}
OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
const OI_BYTE **frameData,
OI_UINT32 *frameBytes,
OI_INT16 *pcmData,
OI_UINT32 *pcmBytes)
{
OI_STATUS status;
OI_UINT framelen;
OI_UINT8 crc;
TRACE(("+OI_CODEC_SBC_DecodeFrame"));
TRACE(("Finding syncword"));
status = FindSyncword(context, frameData, frameBytes);
if (!OI_SUCCESS(status)) {
return status;
}{...}
if (*frameBytes < SBC_HEADER_LEN) {
TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA"));
return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
}{...}
TRACE(("Reading Header"));
OI_SBC_ReadHeader(&context->common, *frameData);
/* ... */
if (context->limitFrameFormat && (context->common.frameInfo.subbands != context->restrictSubbands)) {
ERROR(("SBC parameters incompatible with loaded overlay"));
return OI_STATUS_INVALID_PARAMETERS;
}{...}
if (context->common.frameInfo.nrof_channels > context->common.maxChannels) {
ERROR(("SBC parameters incompatible with number of channels specified during reset"));
return OI_STATUS_INVALID_PARAMETERS;
}{...}
if (context->common.pcmStride < 1 || context->common.pcmStride > 2) {
ERROR(("PCM stride not set correctly during reset"));
return OI_STATUS_INVALID_PARAMETERS;
}{...}
/* ... */
framelen = OI_CODEC_SBC_CalculateFramelen(&context->common.frameInfo);
if (*frameBytes < framelen) {
TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA"));
return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
}{...}
TRACE(("Calculating checksum"));
crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
if (crc != context->common.frameInfo.crc) {
TRACE(("CRC Mismatch: calc=%02x read=%02x\n", crc, context->common.frameInfo.crc));
TRACE(("-OI_CODEC_SBC_DecodeFrame: OI_CODEC_SBC_CHECKSUM_MISMATCH"));
return OI_CODEC_SBC_CHECKSUM_MISMATCH;
}{...}
#ifdef OI_DEBUG
/* ... */
if ((context->common.frameInfo.bitpool < SBC_MIN_BITPOOL) && !context->common.frameInfo.enhanced) {
ERROR(("Bitpool too small: %d (must be >= 2)", context->common.frameInfo.bitpool));
return OI_STATUS_INVALID_PARAMETERS;
}{...}
if (context->common.frameInfo.bitpool > OI_SBC_MaxBitpool(&context->common.frameInfo)) {
ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo)));
return OI_STATUS_INVALID_PARAMETERS;
}{...}
/* ... */#endif
/* ... */
status = DecodeBody(context, *frameData + SBC_HEADER_LEN, pcmData, pcmBytes, FALSE);
if (OI_SUCCESS(status)) {
*frameData += framelen;
*frameBytes -= framelen;
}{...}
TRACE(("-OI_CODEC_SBC_DecodeFrame: %d", status));
return status;
}{...}
OI_STATUS OI_CODEC_SBC_SkipFrame(OI_CODEC_SBC_DECODER_CONTEXT *context,
const OI_BYTE **frameData,
OI_UINT32 *frameBytes)
{
OI_STATUS status;
OI_UINT framelen;
OI_UINT headerlen;
OI_UINT8 crc;
status = FindSyncword(context, frameData, frameBytes);
if (!OI_SUCCESS(status)) {
return status;
}{...}
if (*frameBytes < SBC_HEADER_LEN) {
return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
}{...}
OI_SBC_ReadHeader(&context->common, *frameData);
framelen = OI_SBC_CalculateFrameAndHeaderlen(&context->common.frameInfo, &headerlen);
if (*frameBytes < headerlen) {
return OI_CODEC_SBC_NOT_ENOUGH_HEADER_DATA;
}{...}
crc = OI_SBC_CalculateChecksum(&context->common.frameInfo, *frameData);
if (crc != context->common.frameInfo.crc) {
return OI_CODEC_SBC_CHECKSUM_MISMATCH;
}{...}
if (*frameBytes < framelen) {
return OI_CODEC_SBC_NOT_ENOUGH_BODY_DATA;
}{...}
context->bufferedBlocks = 0;
*frameData += framelen;
*frameBytes -= framelen;
return OI_OK;
}{...}
OI_UINT8 OI_CODEC_SBC_FrameCount(OI_BYTE *frameData,
OI_UINT32 frameBytes)
{
OI_UINT8 mode;
OI_UINT8 blocks;
OI_UINT8 subbands;
OI_UINT8 frameCount = 0;
OI_UINT frameLen;
while (frameBytes) {
while (frameBytes && ((frameData[0] & 0xFE) != 0x9C)) {
frameData++;
frameBytes--;
}{...}
if (frameBytes < SBC_HEADER_LEN) {
return frameCount;
}{...}
subbands = mode = blocks = frameData[1];;
mode = (mode & (BIT3 | BIT2)) >> 2;
blocks = block_values[(blocks & (BIT5 | BIT4)) >> 4];
subbands = band_values[(subbands & BIT0)];
frameLen = blocks * frameData[2];
switch (mode) {
case SBC_JOINT_STEREO:
frameLen += subbands + (8 * subbands);
break;
...
case SBC_DUAL_CHANNEL:
frameLen *= 2;
...
default:
if (mode == SBC_MONO) {
frameLen += 4 * subbands;
}{...} else {
frameLen += 8 * subbands;
}{...}
... }{...}
frameCount++;
frameLen = SBC_HEADER_LEN + (frameLen + 7) / 8;
if (frameBytes > frameLen) {
frameBytes -= frameLen;
frameData += frameLen;
}{...} else {
frameBytes = 0;
}{...}
}{...}
return frameCount;
}{...}
#ifdef SPECIALIZE_READ_SAMPLES_JOINT
PRIVATE void OI_SBC_ReadSamplesJoint4(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
{
#define NROF_SUBBANDS 4
#include "readsamplesjoint.inc"
#undef NROF_SUBBANDS
}{...}
PRIVATE void OI_SBC_ReadSamplesJoint8(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
{
#define NROF_SUBBANDS 8
#include "readsamplesjoint.inc"
#undef NROF_SUBBANDS
}{...}
typedef void (*READ_SAMPLES)(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs);
static const READ_SAMPLES SpecializedReadSamples[] = {
OI_SBC_ReadSamplesJoint4,
OI_SBC_ReadSamplesJoint8
}{...};
/* ... */
#endif
PRIVATE void OI_SBC_ReadSamplesJoint(OI_CODEC_SBC_DECODER_CONTEXT *context, OI_BITSTREAM *global_bs)
{
OI_CODEC_SBC_COMMON_CONTEXT *common = &context->common;
OI_UINT nrof_subbands = common->frameInfo.nrof_subbands;
#ifdef SPECIALIZE_READ_SAMPLES_JOINT
OI_ASSERT((nrof_subbands >> 3u) <= 1u);
SpecializedReadSamples[nrof_subbands >> 3](context, global_bs);/* ... */
#else
#define NROF_SUBBANDS nrof_subbands
#include "readsamplesjoint.inc"
#undef NROF_SUBBANDS/* ... */
#endif
}{...}
/* ... */
#endif