C++程序  |  696行  |  28.17 KB

/******************************************************************************
 *
 *  Copyright (C) 2003-2012 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  This file contains the down sampling utility to convert PCM samples in
 *  16k/32k/48k/44.1k/22050/11025 sampling rate into 8K/16bits samples
 *  required for SCO channel format. One API function isprovided and only
 *  possible to be used when transmitting SCO data is sent via HCI
 *  interface.
 *
 ******************************************************************************/
#include <string.h>
#include "bta_api.h"
#include "bta_sys.h"

#if (BTM_SCO_HCI_INCLUDED == TRUE)

#ifndef BTA_DM_SCO_DEBUG
#define BTA_DM_SCO_DEBUG    FALSE
#endif
/*****************************************************************************
**  Constants
*****************************************************************************/

#define BTA_DM_PCM_OVERLAP_SIZE			     48

#define BTA_DM_PCM_SMPL_RATE_44100     44100
#define BTA_DM_PCM_SMPL_RATE_22050     22050
#define BTA_DM_PCM_SMPL_RATE_11025     11025

/*****************************************************************************
**  Data types for PCM Resampling utility
*****************************************************************************/

typedef INT32   (*PCONVERT_TO_BT_FILTERED)  (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
                             UINT32 dwSrcSps,INT32 *pLastCurPos, UINT8 *pOverlapArea);
typedef INT32   (*PCONVERT_TO_BT_NOFILTER)  (void *pSrc, void *pDst, UINT32 dwSrcSamples,
                                             UINT32 dwSrcSps);
typedef struct
{
    UINT8               overlap_area[BTA_DM_PCM_OVERLAP_SIZE * 4];
    UINT32              cur_pos;    /* current position */
    UINT32              src_sps;    /* samples per second (source audio data) */
    PCONVERT_TO_BT_FILTERED     filter;    /* the action function to do the
                                    conversion 44100, 22050, 11025*/
    PCONVERT_TO_BT_NOFILTER     nofilter;    /* the action function to do
                                        the conversion 48000, 32000, 16000*/
    UINT32              bits;       /* number of bits per pcm sample */
    UINT32              n_channels; /* number of channels (i.e. mono(1), stereo(2)...) */
    UINT32              sample_size;
    UINT32              can_be_filtered;
    UINT32	            divisor;
} tBTA_DM_PCM_RESAMPLE_CB;

tBTA_DM_PCM_RESAMPLE_CB bta_dm_pcm_cb;

/*****************************************************************************
**  Macro Definition
*****************************************************************************/


#define CHECK_SATURATION16(x)                                           \
            if (x > 32767)                                              \
                x = 32767;                                              \
            else if (x < -32768)                                        \
                x = -32768;

////////////////////////////////////////////////////////////////////////////////////////////////////
//
#define CONVERT_44100_TO_BLUETOOTH(pStart, pEnd)                            \
    {                                                                       \
        INT32         out1, out2, out3, out4, out5;                         \
        SRC_TYPE    *pS = (SRC_TYPE *)pStart;                               \
        SRC_TYPE    *pSEnd = (SRC_TYPE *)pEnd;                              \
                                                                            \
        while (pS < pSEnd)                                                  \
        {                                                                   \
            CurrentPos -= 8000;                                             \
                                                                            \
            if (CurrentPos >= 0)                                            \
            {                                                               \
                pS += SRC_CHANNELS;                                         \
                continue;                                                   \
            }                                                               \
            CurrentPos += dwSrcSps;                                         \
                                                                            \
            out1 = (SRC_SAMPLE(0) * 1587)                                   \
                 + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 1522)                \
                 + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1337)                \
                 + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 1058);               \
                                                                            \
            out1 = out1 / 30000;                                            \
                                                                            \
            out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 725)                 \
                 + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 384)                 \
                 + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 79);                 \
                                                                            \
            out2 = out2 / 30000;                                            \
                                                                            \
            out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 156)                 \
                 + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 298)                 \
                 + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 345);                \
                                                                            \
            out3 = out3 / 30000;                                            \
                                                                            \
            out4 = ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 306)               \
                 + ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 207)               \
                 + ((SRC_SAMPLE(12) + SRC_SAMPLE(-12)) * 78);               \
                                                                            \
            out4 = out4 / 30000;                                            \
                                                                            \
            out5 = out1 + out2 - out3 - out4;                               \
                                                                            \
            CHECK_SATURATION16(out5);                                       \
            *psBtOut++ = (INT16)out5;                                       \
                                                                            \
            pS += SRC_CHANNELS;                                             \
        }                                                                   \
    }


////////////////////////////////////////////////////////////////////////////////////////////////////
//
#define CONVERT_22050_TO_BLUETOOTH(pStart, pEnd)                            \
    {                                                                       \
        INT32         out1, out2, out3, out4, out5;                         \
        SRC_TYPE    *pS = (SRC_TYPE *)pStart;                               \
        SRC_TYPE    *pSEnd = (SRC_TYPE *)pEnd;                              \
                                                                            \
        while (pS < pSEnd)                                                  \
        {                                                                   \
            CurrentPos -= 8000;                                             \
                                                                            \
            if (CurrentPos >= 0)                                            \
            {                                                               \
                pS += SRC_CHANNELS;                                         \
                continue;                                                   \
            }                                                               \
            CurrentPos += dwSrcSps;                                         \
                                                                            \
            out1 = (SRC_SAMPLE(0) * 2993)                                   \
                 + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2568)                \
                 + ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1509)                \
                 + ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 331);                \
                                                                            \
            out1 = out1 / 30000;                                            \
                                                                            \
            out2 = ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 454)                 \
                 + ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 620)                 \
                 + ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 305);                \
                                                                            \
            out2 = out2 / 30000;                                            \
                                                                            \
            out3 = ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 127)                 \
                 + ((SRC_SAMPLE(8) + SRC_SAMPLE(-8)) * 350)                 \
                 + ((SRC_SAMPLE(9) + SRC_SAMPLE(-9)) * 265)                 \
                 + ((SRC_SAMPLE(10) + SRC_SAMPLE(-10)) * 6);                \
                                                                            \
            out3 = out3 / 30000;                                            \
                                                                            \
            out4 = ((SRC_SAMPLE(11) + SRC_SAMPLE(-11)) * 201);              \
                                                                            \
            out4 = out4 / 30000;                                            \
                                                                            \
            out5 = out1 - out2 + out3 - out4;                               \
                                                                            \
            CHECK_SATURATION16(out5);                                       \
            *psBtOut++ = (INT16)out5;                                       \
                                                                            \
            pS += SRC_CHANNELS;                                             \
        }                                                                   \
    }


////////////////////////////////////////////////////////////////////////////////////////////////////
//
#define CONVERT_11025_TO_BLUETOOTH(pStart, pEnd)                            \
    {                                                                       \
        INT32         out1;                                                   \
        SRC_TYPE    *pS = (SRC_TYPE *)pStart;                               \
        SRC_TYPE    *pSEnd = (SRC_TYPE *)pEnd;                              \
                                                                            \
        while (pS < pSEnd)                                                  \
        {                                                                   \
            CurrentPos -= 8000;                                             \
                                                                            \
            if (CurrentPos >= 0)                                            \
            {                                                               \
                pS += SRC_CHANNELS;                                         \
                continue;                                                   \
            }                                                               \
            CurrentPos += dwSrcSps;                                         \
                                                                            \
            out1 = (SRC_SAMPLE(0) * 6349)                                   \
                 + ((SRC_SAMPLE(1) + SRC_SAMPLE(-1)) * 2874)                \
                 - ((SRC_SAMPLE(2) + SRC_SAMPLE(-2)) * 1148)                \
                 - ((SRC_SAMPLE(3) + SRC_SAMPLE(-3)) * 287)                 \
                 + ((SRC_SAMPLE(4) + SRC_SAMPLE(-4)) * 675)                 \
                 - ((SRC_SAMPLE(5) + SRC_SAMPLE(-5)) * 258)                 \
                 - ((SRC_SAMPLE(6) + SRC_SAMPLE(-6)) * 206)                 \
                 + ((SRC_SAMPLE(7) + SRC_SAMPLE(-7)) * 266);                \
                                                                            \
            out1 = out1 / 30000;                                            \
                                                                            \
            CHECK_SATURATION16(out1);                                       \
            *psBtOut++ = (INT16)out1;                                       \
                                                                            \
            pS += SRC_CHANNELS;                                             \
        }                                                                   \
    }


////////////////////////////////////////////////////////////////////////////////////////////////////
//
#undef  SRC_CHANNELS
#undef  SRC_SAMPLE
#undef  SRC_TYPE

#define SRC_TYPE        UINT8
#define SRC_CHANNELS    1
#define SRC_SAMPLE(x)   ((pS[x]  - 0x80) << 8)

/*****************************************************************************
**  Local Function
*****************************************************************************/
INT32 Convert_8M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
                    UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
{
    INT32             CurrentPos = *pLastCurPos;
    SRC_TYPE        *pIn, *pInEnd;
    SRC_TYPE        *pOv, *pOvEnd;
    INT16           *psBtOut = (INT16 *)pDst;
#if BTA_DM_SCO_DEBUG
    APPL_TRACE_DEBUG("Convert_8M_ToBT_Filtered,  CurrentPos %d\n", CurrentPos);
#endif
    memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);

    pOv    = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
	pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));

    pIn     = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
	pInEnd  = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
        BTA_DM_PCM_OVERLAP_SIZE);

    if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
    {
        CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
    {
        CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
    {
        CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
    }

    memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
        (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);

    *pLastCurPos = CurrentPos;

    return (psBtOut - (INT16 *)pDst);
}

INT32 Convert_8M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
{
    INT32             CurrentPos;
    UINT8            *pbSrc = (UINT8 *)pSrc;
    INT16           *psDst = (INT16 *)pDst;
    INT16           sWorker;

    //      start at dwSpsSrc / 2, decrement by 8000
    //
    CurrentPos = (dwSrcSps >> 1);

    while (dwSrcSamples--)
    {
        CurrentPos -= 8000;

        if (CurrentPos >= 0)
            pbSrc++;
        else
        {
            sWorker = *pbSrc++;
            sWorker -= 0x80;
            sWorker <<= 8;

            *psDst++ = sWorker;

            CurrentPos += dwSrcSps;
        }
    }

    return (psDst - (INT16 *)pDst);
}


////////////////////////////////////////////////////////////////////////////////////////////////////
//
#undef  SRC_CHANNELS
#undef  SRC_SAMPLE
#undef  SRC_TYPE

#define SRC_TYPE        INT16
#define SRC_CHANNELS    1
#define SRC_SAMPLE(x)   pS[x]

INT32 Convert_16M_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
                                 UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
{
    INT32             CurrentPos = *pLastCurPos;
    SRC_TYPE        *pIn, *pInEnd;
    SRC_TYPE        *pOv, *pOvEnd;
    INT16           *psBtOut = (INT16 *)pDst;

    memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);

    pOv    = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
	pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));

    pIn     = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
	pInEnd  = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE);

    if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
    {
        CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
    {
        CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
    {
        CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
    }

    memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
        (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);

    *pLastCurPos = CurrentPos;

    return (psBtOut - (INT16 *)pDst);
}

INT32 Convert_16M_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
{
    INT32             CurrentPos;
    INT16           *psSrc = (INT16 *)pSrc;
    INT16           *psDst = (INT16 *)pDst;

    //      start at dwSpsSrc / 2, decrement by 8000
    //
    CurrentPos = (dwSrcSps >> 1);

    while (dwSrcSamples--)
    {
        CurrentPos -= 8000;

        if (CurrentPos >= 0)
            psSrc++;
        else
        {
            *psDst++ = *psSrc++;

            CurrentPos += dwSrcSps;
        }
    }

    return (psDst - (INT16 *)pDst);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//
#undef  SRC_CHANNELS
#undef  SRC_SAMPLE
#undef  SRC_TYPE

#define SRC_TYPE        UINT8
#define SRC_CHANNELS    2
#define SRC_SAMPLE(x) ((((pS[x * 2]  - 0x80) << 8) + ((pS[(x * 2) + 1]  - 0x80) << 8)) >> 1)

INT32 Convert_8S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
                                UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
{
    INT32             CurrentPos = *pLastCurPos;
    SRC_TYPE        *pIn, *pInEnd;
    SRC_TYPE        *pOv, *pOvEnd;
    INT16           *psBtOut = (INT16 *)pDst;

#if BTA_DM_SCO_DEBUG
    APPL_TRACE_DEBUG("Convert_8S_ToBT_Filtered CurrentPos %d, SRC_TYPE %d, SRC_CHANNELS %d, \
        dwSrcSamples %d,  dwSrcSps %d",  	CurrentPos, sizeof (SRC_TYPE), SRC_CHANNELS, \
        dwSrcSamples, dwSrcSps);
#endif
    memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);

    pOv    = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
	pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));

    pIn     = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
	pInEnd  = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE);

    if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
    {
        CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
    {
        CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
    {
        CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
    }

    memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
        (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);

    *pLastCurPos = CurrentPos;

    return (psBtOut - (INT16 *)pDst);
}

INT32 Convert_8S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
{
    INT32             CurrentPos;
    UINT8            *pbSrc = (UINT8 *)pSrc;
    INT16           *psDst = (INT16 *)pDst;
    INT16           sWorker, sWorker2;

    //      start at dwSpsSrc / 2, decrement by 8000
    //
    CurrentPos = (dwSrcSps >> 1);

    while (dwSrcSamples--)
    {
        CurrentPos -= 8000;

        if (CurrentPos >= 0)
            pbSrc += 2;
        else
        {
            sWorker = *(unsigned char *)pbSrc;
            sWorker -= 0x80;
            sWorker <<= 8;
            pbSrc++;

            sWorker2 = *(unsigned char *)pbSrc;
            sWorker2 -= 0x80;
            sWorker2 <<= 8;
            pbSrc++;

            sWorker += sWorker2;
            sWorker >>= 1;

            *psDst++ = sWorker;

            CurrentPos += dwSrcSps;
        }
    }

    return (psDst - (INT16 *)pDst);
}


////////////////////////////////////////////////////////////////////////////////////////////////////
//
#undef  SRC_CHANNELS
#undef  SRC_SAMPLE
#undef  SRC_TYPE

#define SRC_TYPE        INT16
#define SRC_CHANNELS    2
#define SRC_SAMPLE(x) ((pS[x * 2] + pS[(x * 2) + 1]) >> 1)

INT32 Convert_16S_ToBT_Filtered (UINT8 *pSrc, void *pDst, UINT32 dwSrcSamples,
                                 UINT32 dwSrcSps, INT32 *pLastCurPos, UINT8 *pOverlapArea)
{
    INT32             CurrentPos = *pLastCurPos;
    SRC_TYPE        *pIn, *pInEnd;
    SRC_TYPE        *pOv, *pOvEnd;
    INT16           *psBtOut = (INT16 *)pDst;

    memcpy (pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 2), pSrc, BTA_DM_PCM_OVERLAP_SIZE * 2);

    pOv    = (SRC_TYPE *)(pOverlapArea + BTA_DM_PCM_OVERLAP_SIZE);
	pOvEnd = (SRC_TYPE *)(pOverlapArea + (BTA_DM_PCM_OVERLAP_SIZE * 3));

    pIn     = (SRC_TYPE *)(pSrc + BTA_DM_PCM_OVERLAP_SIZE);
	pInEnd  = (SRC_TYPE *)(pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - BTA_DM_PCM_OVERLAP_SIZE);

    if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_44100)
    {
        CONVERT_44100_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_44100_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_22050)
    {
        CONVERT_22050_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_22050_TO_BLUETOOTH(pIn, pInEnd);
    }
    else if (dwSrcSps == BTA_DM_PCM_SMPL_RATE_11025)
    {
        CONVERT_11025_TO_BLUETOOTH(pOv, pOvEnd);
        CONVERT_11025_TO_BLUETOOTH(pIn, pInEnd);
    }

    memcpy (pOverlapArea, pSrc + (dwSrcSamples * SRC_CHANNELS * sizeof (SRC_TYPE)) - \
        (BTA_DM_PCM_OVERLAP_SIZE * 2), BTA_DM_PCM_OVERLAP_SIZE * 2);

    *pLastCurPos = CurrentPos;

    return (psBtOut - (INT16 *)pDst);
}

INT32 Convert_16S_ToBT_NoFilter (void *pSrc, void *pDst, UINT32 dwSrcSamples, UINT32 dwSrcSps)
{
    INT32             CurrentPos;
    INT16           *psSrc = (INT16 *)pSrc;
    INT16           *psDst = (INT16 *)pDst;
    INT16           sWorker;

    //      start at dwSpsSrc / 2, decrement by 8000
    //
    CurrentPos = (dwSrcSps >> 1);

    while (dwSrcSamples--)
    {
        CurrentPos -= 8000;

        if (CurrentPos >= 0)
            psSrc += 2;
        else
        {
            /* CR 82894, to avoid overflow, divide before add */
            sWorker  = ((*psSrc) >> 1 );
            psSrc++;
            sWorker += ((*psSrc) >> 1 );
            psSrc++;

            *psDst++ = sWorker;

            CurrentPos += dwSrcSps;
        }
    }

    return (psDst - (INT16 *)pDst);
}

/*******************************************************************************
**
** Function         BTA_DmPcmInitSamples
**
** Description      initialize the down sample converter.
**
**                  src_sps: original samples per second (source audio data)
**                            (ex. 44100, 48000)
**                  bits: number of bits per pcm sample (16)
**                  n_channels: number of channels (i.e. mono(1), stereo(2)...)
**
** Returns          none
**
*******************************************************************************/
void BTA_DmPcmInitSamples (UINT32 src_sps, UINT32 bits, UINT32 n_channels)
{
    tBTA_DM_PCM_RESAMPLE_CB *p_cb = &bta_dm_pcm_cb;

    p_cb->cur_pos       = src_sps / 2;
    p_cb->src_sps       = src_sps;
    p_cb->bits          = bits;
    p_cb->n_channels    = n_channels;
    p_cb->sample_size   = 2;
    p_cb->divisor	    = 2;

    memset(p_cb->overlap_area, 0, sizeof(p_cb->overlap_area) );

    if ((src_sps == BTA_DM_PCM_SMPL_RATE_44100) ||
        (src_sps == BTA_DM_PCM_SMPL_RATE_22050) ||
        (src_sps == BTA_DM_PCM_SMPL_RATE_11025))
         p_cb->can_be_filtered = 1;
    else
         p_cb->can_be_filtered = 0;

#if BTA_DM_SCO_DEBUG
    APPL_TRACE_DEBUG("bta_dm_pcm_init_samples: n_channels = %d bits = %d", n_channels, bits);
#endif
    if(n_channels == 1)
    {
        /* mono */
        if(bits == 8)
        {
            p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8M_ToBT_Filtered;
            p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8M_ToBT_NoFilter;
	        p_cb->divisor	 = 1;
        }
        else
        {
            p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16M_ToBT_Filtered;
            p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16M_ToBT_NoFilter;
        }
    }
    else
    {
        /* stereo */
        if(bits == 8)
        {
            p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_8S_ToBT_Filtered;
            p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_8S_ToBT_NoFilter;
        }
        else
        {
            p_cb->filter = (PCONVERT_TO_BT_FILTERED) Convert_16S_ToBT_Filtered;
            p_cb->nofilter = (PCONVERT_TO_BT_NOFILTER) Convert_16S_ToBT_NoFilter;
	        p_cb->divisor	 = 4;
        }
    }

#if BTA_DM_SCO_DEBUG
    APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: cur_pos %d, src_sps %d", \
		p_cb->cur_pos, p_cb->src_sps);
    APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: bits %d, n_channels %d, sample_size %d, ", \
		p_cb->bits, p_cb->n_channels, p_cb->sample_size);
    APPL_TRACE_DEBUG("bta_pcm_init_dwn_sample: can_be_filtered %d, n_channels: %d, \
        divisor %d", p_cb->can_be_filtered, p_cb->n_channels, p_cb->divisor);
#endif

}

/**************************************************************************************
** Function         BTA_DmPcmResample
**
** Description      Down sampling utility to convert higher sampling rate into 8K/16bits
**                  PCM samples.
**
** Parameters       p_src: pointer to the buffer where the original sampling PCM
**                              are stored.
**                  in_bytes:  Length of the input PCM sample buffer in byte.
**                  p_dst:      pointer to the buffer which is to be used to store
**                              the converted PCM samples.
**
**
** Returns          INT32: number of samples converted.
**
**************************************************************************************/
INT32 BTA_DmPcmResample (void *p_src, UINT32 in_bytes, void *p_dst)
{
    UINT32 out_sample;

#if BTA_DM_SCO_DEBUG
    APPL_TRACE_DEBUG("bta_pcm_resample : insamples  %d",  (in_bytes  / bta_dm_pcm_cb.divisor));
#endif
    if(bta_dm_pcm_cb.can_be_filtered)
    {
        out_sample = (*bta_dm_pcm_cb.filter) (p_src, p_dst, (in_bytes  / bta_dm_pcm_cb.divisor),
            bta_dm_pcm_cb.src_sps, (INT32 *) &bta_dm_pcm_cb.cur_pos, bta_dm_pcm_cb.overlap_area);
    }
    else
    {
        out_sample = (*bta_dm_pcm_cb.nofilter) (p_src, p_dst,
            (in_bytes / bta_dm_pcm_cb.divisor), bta_dm_pcm_cb.src_sps);
    }

#if BTA_DM_SCO_DEBUG
    APPL_TRACE_DEBUG("bta_pcm_resample : outsamples  %d",  out_sample);
#endif

    return (out_sample * bta_dm_pcm_cb.sample_size);
}
#endif