1/****************************************************************************** 2 * 3 * Copyright (C) 2002-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19/****************************************************************************** 20 * 21 * Utility functions to help build and parse SBC Codec Information Element 22 * and Media Payload. 23 * 24 ******************************************************************************/ 25 26#include "bt_target.h" 27#include <string.h> 28#include "a2d_api.h" 29#include "a2d_int.h" 30#include "a2d_sbc.h" 31#include "bt_utils.h" 32 33#if (A2D_SBC_INCLUDED == TRUE) 34 35/************************************************************************************************* 36 * SBC descramble code 37 * Purpose: to tie the SBC code with BTE/mobile stack code, 38 * especially for the case when the SBC is ported into a third-party Multimedia chip 39 * 40 * Algorithm: 41 * init process: all counters reset to 0, 42 * calculate base_index: (6 + s16NumOfChannels*s16NumOfSubBands/2) 43 * scramble side: the init process happens every time SBC_Encoder_Init() is called. 44 * descramble side: it would be nice to know if he "init" process has happened. 45 * alter the SBC SYNC word 0x9C (1001 1100) to 0x8C (1000 1100). 46 * 47 * scramble process: 48 * The CRC byte: 49 * Every SBC frame has a frame header. 50 * The 1st byte is the sync word and the following 2 bytes are about the stream format. 51 * They are supposed to be "constant" within a "song" 52 * The 4th byte is the CRC byte. The CRC byte is bound to be random. 53 * Derive 2 items from the CRC byte; one is the "use" bit, the other is the "index". 54 * 55 * SBC keeps 2 sets of "use" & "index"; derived the current and the previous frame. 56 * 57 * The "use" bit is any bit in SBC_PRTC_USE_MASK is set. 58 * If set, SBC uses the "index" from the current frame. 59 * If not set, SBC uses the "index" from the previous frame or 0. 60 * 61 * index = (CRC & 0x3) + ((CRC & 0x30) >> 2) // 8 is the max index 62 * 63 * if(index > 0) 64 * { 65 * p = &u8frame[base_index]; 66 * if((index&1)&&(u16PacketLength > (base_index+index*2))) 67 * { 68 * // odd index: swap 2 bytes 69 * tmp = p[index]; 70 * p[index] = p[index*2]; 71 * p[index*2] = tmp; 72 * } 73 * else 74 * { 75 * // even index: shift by 3 76 * tmp = (p[index] >> 3) + (p[index] << 5); 77 * p[index] = tmp; 78 * } 79 * } 80 * //else index is 0. The frame stays unaltered 81 * 82 */ 83#define A2D_SBC_SYNC_WORD 0x9C 84#define A2D_SBC_CRC_IDX 3 85#define A2D_SBC_USE_MASK 0x64 86#define A2D_SBC_SYNC_MASK 0x10 87#define A2D_SBC_CIDX 0 88#define A2D_SBC_LIDX 1 89#define A2D_SBC_CH_M_BITS 0xC /* channel mode bits: 0: mono; 1 ch */ 90#define A2D_SBC_SUBBAND_BIT 0x1 /* num of subband bit: 0:4; 1: 8 */ 91 92#define A2D_SBC_GET_IDX(sc) (((sc) & 0x3) + (((sc) & 0x30) >> 2)) 93 94typedef struct 95{ 96 UINT8 use; 97 UINT8 idx; 98} tA2D_SBC_FR_CB; 99 100typedef struct 101{ 102 tA2D_SBC_FR_CB fr[2]; 103 UINT8 index; 104 UINT8 base; 105} tA2D_SBC_DS_CB; 106 107static tA2D_SBC_DS_CB a2d_sbc_ds_cb; 108/*int a2d_count = 0;*/ 109/****************************************************************************** 110** 111** Function A2D_SbcChkFrInit 112** 113** Description check if need to init the descramble control block. 114** 115** Returns nothing. 116******************************************************************************/ 117void A2D_SbcChkFrInit(UINT8 *p_pkt) 118{ 119 UINT8 fmt; 120 UINT8 num_chnl = 1; 121 UINT8 num_subband = 4; 122 123 if((p_pkt[0] & A2D_SBC_SYNC_MASK) == 0) 124 { 125 a2d_cb.use_desc = TRUE; 126 fmt = p_pkt[1]; 127 p_pkt[0] |= A2D_SBC_SYNC_MASK; 128 memset(&a2d_sbc_ds_cb, 0, sizeof(tA2D_SBC_DS_CB)); 129 if(fmt & A2D_SBC_CH_M_BITS) 130 num_chnl = 2; 131 if(fmt & A2D_SBC_SUBBAND_BIT) 132 num_subband = 8; 133 a2d_sbc_ds_cb.base = 6 + num_chnl*num_subband/2; 134 /*printf("base: %d\n", a2d_sbc_ds_cb.base); 135 a2d_count = 0;*/ 136 } 137} 138 139/****************************************************************************** 140** 141** Function A2D_SbcDescramble 142** 143** Description descramble the packet. 144** 145** Returns nothing. 146******************************************************************************/ 147void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len) 148{ 149 tA2D_SBC_FR_CB *p_cur, *p_last; 150 UINT32 idx, tmp, tmp2; 151 152 if(a2d_cb.use_desc) 153 { 154 /* c2l */ 155 p_last = &a2d_sbc_ds_cb.fr[A2D_SBC_LIDX]; 156 p_cur = &a2d_sbc_ds_cb.fr[A2D_SBC_CIDX]; 157 p_last->idx = p_cur->idx; 158 p_last->use = p_cur->use; 159 /* getc */ 160 p_cur->use = p_pkt[A2D_SBC_CRC_IDX] & A2D_SBC_USE_MASK; 161 p_cur->idx = A2D_SBC_GET_IDX(p_pkt[A2D_SBC_CRC_IDX]); 162 a2d_sbc_ds_cb.index = (p_cur->use)?A2D_SBC_CIDX:A2D_SBC_LIDX; 163 /* 164 printf("%05d: ar[%02d]: x%02x, msk: x%02x, use: %s, idx: %02d, ", 165 a2d_count++, 166 A2D_SBC_CRC_IDX, p_pkt[A2D_SBC_CRC_IDX], A2D_SBC_USE_MASK, 167 (p_cur->use)?"cur":"lst", p_cur->idx); 168 */ 169 /* descramble */ 170 idx = a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx; 171 if(idx > 0) 172 { 173 p_pkt = &p_pkt[a2d_sbc_ds_cb.base]; 174 if((idx&1) && (len > (a2d_sbc_ds_cb.base+(idx<<1)))) 175 { 176 tmp2 = (idx<<1); 177 tmp = p_pkt[idx]; 178 p_pkt[idx] = p_pkt[tmp2]; 179 p_pkt[tmp2] = tmp; 180 /* 181 printf("tmp2: %02d, len: %d, idx: %d\n", 182 tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx); 183 */ 184 } 185 else 186 { 187 tmp2 = p_pkt[idx]; 188 tmp = (tmp2>>3)+(tmp2<<5); 189 p_pkt[idx] = (UINT8)tmp; 190 /* 191 printf("tmp: x%02x, len: %d, idx: %d(cmp:%d)\n", 192 (UINT8)tmp2, len, a2d_sbc_ds_cb.fr[a2d_sbc_ds_cb.index].idx, 193 (a2d_sbc_ds_cb.base+(idx<<1))); 194 */ 195 } 196 } 197 /* 198 else 199 { 200 printf("!!!!\n"); 201 } 202 */ 203 } 204} 205 206/****************************************************************************** 207** 208** Function A2D_BldSbcInfo 209** 210** Description This function is called by an application to build 211** the SBC Media Codec Capabilities byte sequence 212** beginning from the LOSC octet. 213** Input Parameters: 214** media_type: Indicates Audio, or Multimedia. 215** 216** p_ie: The SBC Codec Information Element information. 217** 218** Output Parameters: 219** p_result: the resulting codec info byte sequence. 220** 221** Returns A2D_SUCCESS if function execution succeeded. 222** Error status code, otherwise. 223******************************************************************************/ 224tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie, UINT8 *p_result) 225{ 226 tA2D_STATUS status; 227 228 if( p_ie == NULL || p_result == NULL || 229 (p_ie->samp_freq & ~A2D_SBC_IE_SAMP_FREQ_MSK) || 230 (p_ie->ch_mode & ~A2D_SBC_IE_CH_MD_MSK) || 231 (p_ie->block_len & ~A2D_SBC_IE_BLOCKS_MSK) || 232 (p_ie->num_subbands & ~A2D_SBC_IE_SUBBAND_MSK) || 233 (p_ie->alloc_mthd & ~A2D_SBC_IE_ALLOC_MD_MSK) || 234 (p_ie->max_bitpool < p_ie->min_bitpool) || 235 (p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL) || 236 (p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL) || 237 (p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL) || 238 (p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL) ) 239 { 240 /* if any unused bit is set */ 241 status = A2D_INVALID_PARAMS; 242 } 243 else 244 { 245 status = A2D_SUCCESS; 246 *p_result++ = A2D_SBC_INFO_LEN; 247 *p_result++ = media_type; 248 *p_result++ = A2D_MEDIA_CT_SBC; 249 250 /* Media Codec Specific Information Element */ 251 *p_result++ = p_ie->samp_freq | p_ie->ch_mode; 252 253 *p_result++ = p_ie->block_len | p_ie->num_subbands | p_ie->alloc_mthd; 254 255 *p_result++ = p_ie->min_bitpool; 256 *p_result = p_ie->max_bitpool; 257 } 258 return status; 259} 260 261/****************************************************************************** 262** 263** Function A2D_ParsSbcInfo 264** 265** Description This function is called by an application to parse 266** the SBC Media Codec Capabilities byte sequence 267** beginning from the LOSC octet. 268** Input Parameters: 269** p_info: the byte sequence to parse. 270** 271** for_caps: TRUE, if the byte sequence is for get capabilities response. 272** 273** Output Parameters: 274** p_ie: The SBC Codec Information Element information. 275** 276** Returns A2D_SUCCESS if function execution succeeded. 277** Error status code, otherwise. 278******************************************************************************/ 279tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info, BOOLEAN for_caps) 280{ 281 tA2D_STATUS status; 282 UINT8 losc; 283 UINT8 mt; 284 285 if( p_ie == NULL || p_info == NULL) 286 status = A2D_INVALID_PARAMS; 287 else 288 { 289 losc = *p_info++; 290 mt = *p_info++; 291 /* If the function is called for the wrong Media Type or Media Codec Type */ 292 if(losc != A2D_SBC_INFO_LEN || *p_info != A2D_MEDIA_CT_SBC) 293 status = A2D_WRONG_CODEC; 294 else 295 { 296 p_info++; 297 p_ie->samp_freq = *p_info & A2D_SBC_IE_SAMP_FREQ_MSK; 298 p_ie->ch_mode = *p_info & A2D_SBC_IE_CH_MD_MSK; 299 p_info++; 300 p_ie->block_len = *p_info & A2D_SBC_IE_BLOCKS_MSK; 301 p_ie->num_subbands = *p_info & A2D_SBC_IE_SUBBAND_MSK; 302 p_ie->alloc_mthd = *p_info & A2D_SBC_IE_ALLOC_MD_MSK; 303 p_info++; 304 p_ie->min_bitpool = *p_info++; 305 p_ie->max_bitpool = *p_info; 306 status = A2D_SUCCESS; 307 if(p_ie->min_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->min_bitpool > A2D_SBC_IE_MAX_BITPOOL ) 308 status = A2D_BAD_MIN_BITPOOL; 309 310 if(p_ie->max_bitpool < A2D_SBC_IE_MIN_BITPOOL || p_ie->max_bitpool > A2D_SBC_IE_MAX_BITPOOL || 311 p_ie->max_bitpool < p_ie->min_bitpool) 312 status = A2D_BAD_MAX_BITPOOL; 313 314 if(for_caps == FALSE) 315 { 316 if(A2D_BitsSet(p_ie->samp_freq) != A2D_SET_ONE_BIT) 317 status = A2D_BAD_SAMP_FREQ; 318 if(A2D_BitsSet(p_ie->ch_mode) != A2D_SET_ONE_BIT) 319 status = A2D_BAD_CH_MODE; 320 if(A2D_BitsSet(p_ie->block_len) != A2D_SET_ONE_BIT) 321 status = A2D_BAD_BLOCK_LEN; 322 if(A2D_BitsSet(p_ie->num_subbands) != A2D_SET_ONE_BIT) 323 status = A2D_BAD_SUBBANDS; 324 if(A2D_BitsSet(p_ie->alloc_mthd) != A2D_SET_ONE_BIT) 325 status = A2D_BAD_ALLOC_MTHD; 326 } 327 } 328 } 329 return status; 330} 331 332/****************************************************************************** 333** 334** Function A2D_BldSbcMplHdr 335** 336** Description This function is called by an application to parse 337** the SBC Media Payload header. 338** Input Parameters: 339** frag: 1, if fragmented. 0, otherwise. 340** 341** start: 1, if the starting packet of a fragmented frame. 342** 343** last: 1, if the last packet of a fragmented frame. 344** 345** num: If frag is 1, this is the number of remaining fragments 346** (including this fragment) of this frame. 347** If frag is 0, this is the number of frames in this packet. 348** 349** Output Parameters: 350** p_dst: the resulting media payload header byte sequence. 351** 352** Returns void. 353******************************************************************************/ 354void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start, BOOLEAN last, UINT8 num) 355{ 356 if(p_dst) 357 { 358 *p_dst = 0; 359 if(frag) 360 *p_dst |= A2D_SBC_HDR_F_MSK; 361 if(start) 362 *p_dst |= A2D_SBC_HDR_S_MSK; 363 if(last) 364 *p_dst |= A2D_SBC_HDR_L_MSK; 365 *p_dst |= (A2D_SBC_HDR_NUM_MSK & num); 366 } 367} 368 369/****************************************************************************** 370** 371** Function A2D_ParsSbcMplHdr 372** 373** Description This function is called by an application to parse 374** the SBC Media Payload header. 375** Input Parameters: 376** p_src: the byte sequence to parse.. 377** 378** Output Parameters: 379** frag: 1, if fragmented. 0, otherwise. 380** 381** start: 1, if the starting packet of a fragmented frame. 382** 383** last: 1, if the last packet of a fragmented frame. 384** 385** num: If frag is 1, this is the number of remaining fragments 386** (including this fragment) of this frame. 387** If frag is 0, this is the number of frames in this packet. 388** 389** Returns void. 390******************************************************************************/ 391void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag, BOOLEAN *p_start, BOOLEAN *p_last, UINT8 *p_num) 392{ 393 if(p_src && p_frag && p_start && p_last && p_num) 394 { 395 *p_frag = (*p_src & A2D_SBC_HDR_F_MSK) ? TRUE: FALSE; 396 *p_start= (*p_src & A2D_SBC_HDR_S_MSK) ? TRUE: FALSE; 397 *p_last = (*p_src & A2D_SBC_HDR_L_MSK) ? TRUE: FALSE; 398 *p_num = (*p_src & A2D_SBC_HDR_NUM_MSK); 399 } 400} 401 402#else /* A2D_SBC_INCLUDED == TRUE */ 403 404void A2D_SbcChkFrInit(UINT8 *p_pkt) 405{ 406 UNUSED(p_pkt); 407} 408 409void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len) 410{ 411 UNUSED(p_pkt); 412 UNUSED(len); 413} 414 415tA2D_STATUS A2D_BldSbcInfo(UINT8 media_type, tA2D_SBC_CIE *p_ie, 416 UINT8 *p_result) 417{ 418 UNUSED(media_type); 419 UNUSED(p_ie); 420 UNUSED(p_result); 421 return A2D_FAIL; 422} 423 424tA2D_STATUS A2D_ParsSbcInfo(tA2D_SBC_CIE *p_ie, UINT8 *p_info, 425 BOOLEAN for_caps) 426{ 427 UNUSED(p_ie); 428 UNUSED(p_info); 429 UNUSED(for_caps); 430 return A2D_FAIL; 431} 432 433void A2D_BldSbcMplHdr(UINT8 *p_dst, BOOLEAN frag, BOOLEAN start, 434 BOOLEAN last, UINT8 num) 435{ 436 UNUSED(p_dst); 437 UNUSED(frag); 438 UNUSED(start); 439 UNUSED(last); 440 UNUSED(num); 441} 442 443void A2D_ParsSbcMplHdr(UINT8 *p_src, BOOLEAN *p_frag, 444 BOOLEAN *p_start, BOOLEAN *p_last, 445 UINT8 *p_num) 446{ 447 UNUSED(p_src); 448 UNUSED(p_frag); 449 UNUSED(p_start); 450 UNUSED(p_last); 451 UNUSED(p_num); 452} 453 454 455#endif /* A2D_SBC_INCLUDED == TRUE */ 456