Home | History | Annotate | Download | only in a2dp
      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