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