⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wmaudiostream.c

📁 pxa270平台 windows mobile 5.2 wm9713 触摸屏+音频驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
 /*-----------------------------------------------------------------------------
 * Copyright (c) Wolfson Microelectronics plc.  All rights reserved.
 *
 * This software as well as any related documentation is furnished under 
 * license and may only be used or copied in accordance with the terms of the 
 * license. The information in this file is furnished for informational use 
 * only, is subject to change without notice, and should not be construed as 
 * a commitment by Wolfson Microelectronics plc. Wolfson Microelectronics plc
 * assumes no responsibility or liability for any errors or inaccuracies that
 * may appear in this document or any software that may be provided in
 * association with this document. 
 *
 * Except as permitted by such license, no part of this document may be 
 * reproduced, stored in a retrieval system, or transmitted in any form or by 
 * any means without the express written consent of Wolfson Microelectronics plc. 
 *
 * $Id: WMAudioStream.c 4452 2007-05-29 09:40:15Z fb $
 *
 * This file contains platform-independent routines for controlling the audio
 * operation on Wolfson codecs.
 *
 * Warning:
 *  This driver is specifically written for Wolfson Codecs. It is not a 
 *  general CODEC device driver.
 *
 * -----------------------------------------------------------------------------*/

/*
 * Include files
 */
#include <string.h>

#include "WMCommon.h"
#include "WMDevice.h"
#include "WMGlobals.h"
#include "WMAudio.h"
#include "WMAudioInternal.h"
#include "WMDMA.h"
#include "WMWaveGen.h"
#include "WMVoice.h"
#include "Test/WMTestCommon.h"
#include "Test/WMInternalTests.h"

/*
 * Only build this if we're doing Audio support.
 */
#if WM_AUDIO_STREAM

/*
 * Global definitions
 */

typedef void (*CopyBufferFn)( void *pDest, void *pSrc, unsigned int nSamples );

/*
 * Structure for holding details about an audio stream.
 */
typedef struct tagStreamCtx
{
    WM_STREAM_ID        stream;
    WMAUDIO_CHANNEL     APIChannel;
    WMDMA_CHAN_HANDLE   DMAChan;
    int                 sampleRate;
    int                 samplesPerBuffer;
    int                 nSamples;
    int                 bytesPerUserSample;
    int                 bytesPerDMASample;
    CopyBufferFn        copyFunc;
    unsigned int        flags;
} StreamCtx;

/*
 * Stream flags.
 */
#define STREAM_ACTIVE           0x00000001
#define STREAM_STEREO_USER      0x00000010
#define STREAM_STEREO_DMA       0x00000020
#define STREAM_MONO_DMA         0x00000040
#define STREAM_MONO_DMA_WIDE    0x00000080
#define STREAM_INPUT            0x00000100
#define STREAM_OUTPUT           0x00000200
#define STREAM_DEFAULT          0x00001000

/*
 * The number of stream contexts we support.
 * Defined channels + 2 to allow for the default channels.
 */
#define WM_STREAM_CONTEXTS  (WMAUDIO_DEFINED_CHANNELS + 2)

/*
 * The WM_STREAM_ID in StreamCtx structures which haven't yet been assigned
 * to a stream.
 */
#define STREAM_UNASSIGNED   0

/*
 * Convert between 8-bit (0-255) and 16-bit data (-32768-32767).
 */
#define CONVERT_8BIT_TO_16BIT( _sample ) \
            ((unsigned short) ((int)((unsigned char)(_sample) - 128) << 8 ))
#define CONVERT_16BIT_TO_8BIT( _sample ) \
            ((unsigned char)(((_sample) >> 8) + 128 ))

/*
 * Convert between stream handles and stream contexts.
 * The basic level of obfuscation gives us a good chance of catching bogus
 * handles.
 */
#define STREAM_HANDLE_BASE                      0x574D4C00
#define STREAM_HANDLE_BASE_MASK                 0xFFFFFF00
#if WM_STREAM_CONTEXTS > 256
#   error If you really want this many streams, you will need to change the way handles work.
#endif /* WM_STREAM_CONTEXTS > 256 */

#define STREAM_INDEX_FROM_CONTEXT( _pCtx )      ((_pCtx) - s_streamContexts)
#define STREAM_CONTEXT_FROM_INDEX( _index )     (&s_streamContexts[_index])
#define STREAM_HANDLE_FROM_INDEX( _index ) \
    ((WM_STREAM_HANDLE)(((unsigned int)(_index)) | STREAM_HANDLE_BASE))
#define STREAM_INDEX_FROM_HANDLE( _handle ) \
    ((((unsigned int)(_handle)) & ~STREAM_HANDLE_BASE_MASK))
#define IS_VALID_STREAM_HANDLE( _handle ) \
    ((STREAM_HANDLE_BASE == \
      (((unsigned int)(_handle)) & STREAM_HANDLE_BASE_MASK) \
     ) && (STREAM_INDEX_FROM_HANDLE( _handle ) < WM_STREAM_CONTEXTS ))
#define STREAM_HANDLE_FROM_CONTEXT( _pCtx ) \
    ( STREAM_HANDLE_FROM_INDEX( STREAM_INDEX_FROM_CONTEXT( _pCtx ) ) )
#define STREAM_CONTEXT_FROM_HANDLE( _handle ) \
    ( IS_VALID_STREAM_HANDLE( _handle ) ? \
      STREAM_CONTEXT_FROM_INDEX( STREAM_INDEX_FROM_HANDLE(_handle) ) : \
      NULL )

/*
 * Private data
 */

/*
 * The stream data.
 */
static StreamCtx s_streamContexts[ WM_STREAM_CONTEXTS ] = {0};

/*
 * Function prototypes
 */
static void private_ClearRestOfBuffer( WM_DEVICE_HANDLE hDevice,
                                       StreamCtx        *pStreamCtx
                                     );

/* Stream context management */
static StreamCtx *private_GetStreamContext( WM_DEVICE_HANDLE    hDevice,
                                            WM_STREAM_ID        stream
                                          );
static WMSTATUS private_AllocateStreamContext( WM_DEVICE_HANDLE   hDevice,
                                               WM_STREAM_ID       stream,
                                               StreamCtx          **ppStreamCtx
                                             );
static void private_InitialiseStreamContext( WM_DEVICE_HANDLE   hDevice,
                                             WM_STREAM_ID       stream,
                                             StreamCtx          *pStreamCtx
                                           );
static void private_FreeStreamContext( WM_DEVICE_HANDLE hDevice,
                                       StreamCtx        *pStreamCtx
                                     );

/* Copy functions - playback */
static void private_Fill8BitMonoTo16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill8BitMonoTo32BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill8BitMonoToStereo( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill16BitMonoTo16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill16BitMonoTo32BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill16BitMonoToStereo( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill8BitStereoTo16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill8BitStereoTo32BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill8BitStereoToStereo( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill16BitStereoTo16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill16BitStereoTo32BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Fill16BitStereoToStereo( void *pDest, void *pSrc, unsigned int nSamples );

/* Copy functions - record */
static void private_Get8BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Get8BitMonoFrom16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Get16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Get16BitMonoFrom16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Get8BitStereo( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Get8BitStereoFrom16BitMono( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Get16BitStereo( void *pDest, void *pSrc, unsigned int nSamples );
static void private_Get16BitStereoFrom16BitMono( void *pDest, void *pSrc, unsigned int nSamples );

/*-----------------------------------------------------------------------------
 * Function:    WMAudioOpenStream
 *
 * Prepares an audio stream for communicating and streaming.
 *
 * Parameters:
 *      hDevice         handle to the device (from WMOpenDevice)
 *      stream          the stream to prepare
 *      pStreamHandle   variable to receive the stream handle
 *      sampleRate      the sample rate for the stream (in Hz, e.g. 44100)
 *      bitsPerSample   the number of bits per sample (8 or 16)
 *      isStereo        the number of channels (FALSE = mono TRUE = stereo)
 *
 * Returns:     WMSTATUS
 *		See WMStatus.h.
 *---------------------------------------------------------------------------*/
WMSTATUS WMAudioOpenStream( WM_DEVICE_HANDLE    hDevice,
                            WM_STREAM_ID        stream,
                            WM_STREAM_HANDLE    *pStreamHandle,
                            int                 sampleRate,
                            int                 bitsPerSample,
                            WM_BOOL             isStereo
                          )
{
    WMSTATUS            status;
    StreamCtx           *pStreamCtx;
    unsigned int        bufSize;
    unsigned int        bytesPerDMASample;
    unsigned int        samplesPerDMABuffer;
    WM_BOOL             isInput;
    WM_BOOL             isStereoDMA;
    WM_BOOL             isWideDMA;
    WMAUDIO_CHANNEL     APIChannel;

    /*
     * Parameter validation.
     */
    switch ( sampleRate )
    {
    case 8000:
    case 11025:
    case 16000:
    case 22050:
    case 32000:
    case 44100:
    case 48000:
        break;

    default:
        status = WMS_UNSUPPORTED;
        goto error0;
    }

    if ( bitsPerSample != 8 && bitsPerSample != 16 )
    {
        status = WMS_UNSUPPORTED;
        goto error0;
    }

    /*
     * Look up the API channel for this stream.
     */
    APIChannel = _WMAudioStreamToChannel( hDevice, stream );
    if ( WMAUDIO_INVALID_CHANNEL == APIChannel )
    {
        status = WMS_UNSUPPORTED;
        WM_TRACE( hDevice, (
                  "WMAudioOpenChannel - stream %d not supported on this codec",
                  stream
                 ));
		goto error0;
    }

    /*
     * Check no-one else is already using this stream.
     */
    pStreamCtx = private_GetStreamContext( hDevice, stream );
    if ( pStreamCtx && ( pStreamCtx->flags & STREAM_ACTIVE ) )
    {
        status = WMS_DEVICE_BUSY;
        goto error0;
    }
    
    /*
     * Set up some defaults.
     */
    bufSize = WMDMAGetMaxBufferSize( hDevice );
    bytesPerDMASample = WMDMAGetBytesPerSample( hDevice, APIChannel );
    isStereoDMA = WMDMAIsStereo( hDevice, APIChannel );
    isInput     = WMDMAIsInput( hDevice, APIChannel );
    isWideDMA   = WMDMAIsWide( hDevice, APIChannel );

	WM_ASSERT( hDevice, WM_IS_INPUT_STREAM( stream ) == isInput );

    /*
     * This can only fail if we have passed in the wrong channel number.
     * We checked the channel above, so if it failed, something's broken
     * with one or more of our tables in the ChipDef and in the DMAContext.
     */
    WM_ASSERT( hDevice, 0 != bytesPerDMASample );

    samplesPerDMABuffer = bufSize/bytesPerDMASample;
    
    /*
     * Get a stream context structure.
     */
    status = private_AllocateStreamContext( hDevice, stream, &pStreamCtx );
    if ( WM_ERROR( status ) )
    {
        goto error0;
    }

    /*
     * Support Low-latency Streaming
     *
     * Adjust the effective DMA buffer size, based on the requested sample rate.
     * The idea is that we want our DMA capture buffers to represent a fixed amount
     * of time, regardless of the sample rate.
     *
     * This means that if the application buffers are small (as is the case with
     * VoIP or DirectSoundCapture) then we still can return the buffer very soon
     * after we have enough captured data to fill it.
     *
     * If we don't do this and use fixed-size capture buffers instead, at low
     * sample rates we could wait for hundreds of milliseconds, then turn around
     * and discover that the application had only given us 80 milliseconds of wave
     * headers, so we would be forced to drop samples on the floor.
     */
    {
        unsigned int maxSamplesPerBuf;
        unsigned int maxBufferDuration;

        if ( isInput )
            maxBufferDuration = WMAUDIO_MAX_RECORD_BUFFER_DURATION;
        else
            maxBufferDuration = WMAUDIO_MAX_PLAYBACK_BUFFER_DURATION;
           
        /*
         * Calculate the maximum number of samples in a buffer, based on the time,
         * and round up to the next 32-byte boundary.
         */
        maxSamplesPerBuf = sampleRate * maxBufferDuration / 1000;
        maxSamplesPerBuf = (maxSamplesPerBuf + 31) & ~31;

        /* 
         * If the default buffer size is larger than our time based buffer size
         * set samplesPerBuffer to our time based buffer size.
         */
        if ( samplesPerDMABuffer > maxSamplesPerBuf )
            samplesPerDMABuffer = maxSamplesPerBuf;
    }

    /*
     * Now calculate the buffer size.
     */
    bufSize = samplesPerDMABuffer * bytesPerDMASample;

    /*
     * Fill in the stream structure.
     */
    pStreamCtx->APIChannel = APIChannel;
    pStreamCtx->bytesPerUserSample = bitsPerSample/8;
    if ( isInput )
    {
        pStreamCtx->flags |= STREAM_INPUT;
        pStreamCtx->bytesPerDMASample = bitsPerSample/8;
    }
    else
    {
        pStreamCtx->flags |= STREAM_OUTPUT;
        pStreamCtx->bytesPerDMASample = bytesPerDMASample;
    }
    pStreamCtx->samplesPerBuffer = samplesPerDMABuffer;
    pStreamCtx->sampleRate = sampleRate;
    pStreamCtx->nSamples = 0;
    if ( isStereo )
    {
        pStreamCtx->flags |= STREAM_STEREO_USER;
        pStreamCtx->bytesPerUserSample *= 2;
        if ( isInput )
        {
            pStreamCtx->bytesPerDMASample *= 2;
        }
    }
    if ( isStereoDMA )
    {
        pStreamCtx->flags |= STREAM_STEREO_DMA;
    }
    else if ( isWideDMA )
    {
        pStreamCtx->flags |= STREAM_MONO_DMA_WIDE;
    }
    else
    {
        pStreamCtx->flags |= STREAM_MONO_DMA;
    }
    if ( WM_IS_DEFAULT_STREAM( stream ) )
    {
        pStreamCtx->flags |= STREAM_DEFAULT;
    }

    /*
     * Set up the copy function.
     */
    if ( isInput )
    {
        if ( isStereoDMA )
        {
            if ( isStereo )
            {
                if ( 16 == bitsPerSample )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -