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 #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 
     94 typedef struct
     95 {
     96     UINT8   use;
     97     UINT8   idx;
     98 } tA2D_SBC_FR_CB;
     99 
    100 typedef struct
    101 {
    102     tA2D_SBC_FR_CB  fr[2];
    103     UINT8           index;
    104     UINT8           base;
    105 } tA2D_SBC_DS_CB;
    106 
    107 static 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 ******************************************************************************/
    117 void 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 ******************************************************************************/
    147 void 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 ******************************************************************************/
    224 tA2D_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 ******************************************************************************/
    279 tA2D_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 ******************************************************************************/
    354 void 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 ******************************************************************************/
    391 void 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 
    404 void A2D_SbcChkFrInit(UINT8 *p_pkt)
    405 {
    406     UNUSED(p_pkt);
    407 }
    408 
    409 void A2D_SbcDescramble(UINT8 *p_pkt, UINT16 len)
    410 {
    411     UNUSED(p_pkt);
    412     UNUSED(len);
    413 }
    414 
    415 tA2D_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 
    424 tA2D_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 
    433 void 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 
    443 void 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