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

📄 pa_win_wmme.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * pa_win_wmme.c
 * Implementation of PortAudio for Windows MultiMedia Extensions (WMME)
 *
 * PortAudio Portable Real-Time Audio Library
 * Latest Version at: http://www.portaudio.com
 *
 * Authors: Ross Bencina and Phil Burk
 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
 *
 * Permission is hereby granted, free of charge, to any person obtainingF
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * Any person wishing to distribute modifications to the Software is
 * requested to send the modifications to the original developer so that
 * they can be incorporated into the canonical version.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
/*
  All memory allocations and frees are marked with MEM for quick review.
*/
/* Modification History:
 PLB = Phil Burk
 PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)
 PLB20010413 - check for excessive numbers of channels
 PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
               including condition including of memory.h,
			   and explicit typecasting on memory allocation
 PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory
 PLB20010816 - pass process instead of thread to SetPriorityClass()
 PLB20010927 - use number of frames instead of real-time for CPULoad calculation.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
#include <mmsystem.h>

/* <process.h> not available for Win CE except for H/PC */
/* #include <process.h> */   /* GJG20021019 */

/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
#ifndef __MWERKS__
#include <malloc.h>
#include <memory.h>
#endif /* __MWERKS__ */
#include "portaudio.h"
#include "pa_host.h"
#include "pa_trace.h"
/************************************************* Constants ********/
#define PA_USE_TIMER_CALLBACK    (0)  /* Select between two options for background task. 0=thread, 1=timer */
#define PA_USE_HIGH_LATENCY      (0)  /* For debugging glitches. */
/* Switches for debugging. */
#define PA_SIMULATE_UNDERFLOW    (0)  /* Set to one to force an underflow of the output buffer. */
/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */
#define PA_TRACE_RUN             (0)
#define PA_TRACE_START_STOP      (1)
#if PA_USE_HIGH_LATENCY
	#define PA_MIN_MSEC_PER_HOST_BUFFER  (100)
	#define PA_MAX_MSEC_PER_HOST_BUFFER  (300) /* Do not exceed unless user buffer exceeds */
	#define PA_MIN_NUM_HOST_BUFFERS      (4)
	#define PA_MAX_NUM_HOST_BUFFERS      (16)  /* OK to exceed if necessary */
	#define PA_WIN_9X_LATENCY            (400)
#else
	#define PA_MIN_MSEC_PER_HOST_BUFFER  (10)
	#define PA_MAX_MSEC_PER_HOST_BUFFER  (100) /* Do not exceed unless user buffer exceeds */
	#define PA_MIN_NUM_HOST_BUFFERS      (3)
	#define PA_MAX_NUM_HOST_BUFFERS      (16)  /* OK to exceed if necessary */
	#define PA_WIN_9X_LATENCY            (200)
#endif
#define MIN_TIMEOUT_MSEC                 (1000)
/*
** Use higher latency for NT because it is even worse at real-time
** operation than Win9x.
*/
#define PA_WIN_NT_LATENCY        (PA_WIN_9X_LATENCY * 2)
#if PA_SIMULATE_UNDERFLOW
static  gUnderCallbackCounter = 0;
#define UNDER_SLEEP_AT       (40)
#define UNDER_SLEEP_FOR      (500)
#endif
#define PRINT(x) { printf x; fflush(stdout); }
#define ERR_RPT(x) PRINT(x)
#define DBUG(x)  /* PRINT(x) */
#define DBUGX(x) /* PRINT(x) */

/************************************************* Definitions ********/
/**************************************************************
 * Structure for internal host specific stream data.
 * This is allocated on a per stream basis.
 */
typedef struct PaHostSoundControl
{
/* Input -------------- */
    HWAVEIN            pahsc_HWaveIn;
    WAVEHDR           *pahsc_InputBuffers;
    int                pahsc_CurrentInputBuffer;
	int                pahsc_BytesPerHostInputBuffer;
	int                pahsc_BytesPerUserInputBuffer;    /* native buffer size in bytes */
/* Output -------------- */    
    HWAVEOUT           pahsc_HWaveOut;
    WAVEHDR           *pahsc_OutputBuffers;
    int                pahsc_CurrentOutputBuffer;
	int                pahsc_BytesPerHostOutputBuffer;
	int                pahsc_BytesPerUserOutputBuffer;    /* native buffer size in bytes */
/* Run Time -------------- */    
	PaTimestamp        pahsc_FramesPlayed;
	long               pahsc_LastPosition;                /* used to track frames played. */
/* For measuring CPU utilization. */
	LARGE_INTEGER      pahsc_EntryCount;
	double             pahsc_InverseTicksPerHostBuffer;
/* Init Time -------------- */    
	int                pahsc_NumHostBuffers;
	int                pahsc_FramesPerHostBuffer;
	int                pahsc_UserBuffersPerHostBuffer;
    CRITICAL_SECTION   pahsc_StreamLock;                  /* Mutext to prevent threads from colliding. */
	INT                pahsc_StreamLockInited;
#if PA_USE_TIMER_CALLBACK
	BOOL               pahsc_IfInsideCallback;            /* Test for reentrancy. */
	MMRESULT           pahsc_TimerID;
#else
    HANDLE             pahsc_AbortEvent;
    int                pahsc_AbortEventInited;
    HANDLE             pahsc_BufferEvent;
    int                pahsc_BufferEventInited;
    HANDLE             pahsc_EngineThread;
    DWORD              pahsc_EngineThreadID;
#endif
} PaHostSoundControl;
/************************************************* Shared Data ********/
/* FIXME - put Mutex around this shared data. */
static int sNumInputDevices = 0;
static int sNumOutputDevices = 0;
static int sNumDevices = 0;
static PaDeviceInfo **sDevicePtrs = NULL;
static int sDefaultInputDeviceID = paNoDevice;
static int sDefaultOutputDeviceID = paNoDevice;
static int sPaHostError = 0;
static const char sMapperSuffixInput[] = " - Input";
static const char sMapperSuffixOutput[] = " - Output";
/************************************************* Macros ********/
/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */
#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1))
/************************************************* Prototypes **********/
static Pa_QueryDevices( void );
static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg,
									  DWORD dwUser, DWORD dw1, DWORD dw2);
PaError PaHost_GetTotalBufferFrames( internalPortAudioStream   *past );
static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc );
static PaError PaHost_BackgroundManager( internalPortAudioStream   *past );
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
static void Pa_StartUsageCalculation( internalPortAudioStream   *past )
{
	PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
	if( pahsc == NULL ) return;
/* Query system timer for usage analysis and to prevent overuse of CPU. */
	QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
}
static void Pa_EndUsageCalculation( internalPortAudioStream   *past )
{
	LARGE_INTEGER CurrentCount = { 0, 0 };
	PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
	if( pahsc == NULL ) return;
/*
** Measure CPU utilization during this callback. Note that this calculation
** assumes that we had the processor the whole time.
*/
#define LOWPASS_COEFFICIENT_0   (0.9)
#define LOWPASS_COEFFICIENT_1   (0.99999 - LOWPASS_COEFFICIENT_0)
	if( QueryPerformanceCounter( &CurrentCount ) )
	{
		LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart;	
		double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerHostBuffer;
		past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
			(LOWPASS_COEFFICIENT_1 * newUsage);
	}
}
/****************************************** END CPU UTILIZATION *******/
static PaError Pa_QueryDevices( void )
{
	int numBytes;
/* Count the devices and add one extra for the WAVE_MAPPER */
    sNumInputDevices = waveInGetNumDevs() + 1;
	sDefaultInputDeviceID = 0;
    sNumOutputDevices = waveOutGetNumDevs() + 1;
	sDefaultOutputDeviceID = sNumInputDevices;
    sNumDevices = sNumInputDevices + sNumOutputDevices;
/* Allocate structures to hold device info. */
/* PLB20010402 - was allocating too much memory. */
/*	numBytes = sNumDevices * sizeof(PaDeviceInfo);  // PLB20010402 */
	numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */
	sDevicePtrs = (PaDeviceInfo **) GlobalAlloc( GPTR, numBytes ); /* MEM */
	if( sDevicePtrs == NULL ) return paInsufficientMemory;
	return paNoError;
}
/************************************************************************************/
long Pa_GetHostError()
{
	return sPaHostError;
}
/*************************************************************************/
int Pa_CountDevices()
{
	if( sNumDevices <= 0 ) Pa_Initialize();
	return sNumDevices;
}
/*************************************************************************
** If a PaDeviceInfo structure has not already been created,
** then allocate one and fill it in for the selected device.
**
** We create one extra input and one extra output device for the WAVE_MAPPER.
** [Does anyone know how to query the default device and get its name?]
*/
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
{	
#define NUM_STANDARDSAMPLINGRATES   3   /* 11.025, 22.05, 44.1 */
#define NUM_CUSTOMSAMPLINGRATES     5   /* must be the same number of elements as in the array below */
#define MAX_NUMSAMPLINGRATES        (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES)
    static DWORD customSamplingRates[] = { 32000, 48000, 64000, 88200, 96000 };
    PaDeviceInfo *deviceInfo;
    double *sampleRates; /* non-const ptr */
    int i;
    char *s;
    
    if( id < 0 || id >= sNumDevices )
        return NULL;
    if( sDevicePtrs[ id ] != NULL )
	{
        return sDevicePtrs[ id ];
    }
    deviceInfo = (PaDeviceInfo *)GlobalAlloc( GPTR, sizeof(PaDeviceInfo) ); /* MEM */
	if( deviceInfo == NULL ) return NULL;
    deviceInfo->structVersion = 1;
    deviceInfo->maxInputChannels = 0;
    deviceInfo->maxOutputChannels = 0;
    deviceInfo->numSampleRates = 0;
    sampleRates = (double*)GlobalAlloc( GPTR, MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */
    deviceInfo->sampleRates = sampleRates;
    deviceInfo->nativeSampleFormats = paInt16;       /* should query for higher bit depths below */
    if( id < sNumInputDevices )
	{
        /* input device */
        int inputMmID = id - 1; /* WAVE_MAPPER is -1 so we start with WAVE_MAPPER */
        WAVEINCAPS wic;
/* MK: changed inputMmID in id*/
/*        if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR )
            goto error;*/
        if( waveInGetDevCaps( id, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR )
            goto error;
        
	/* Append I/O suffix to WAVE_MAPPER device. */
		if( inputMmID == WAVE_MAPPER )
		{
			s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */
			strcpy( s, wic.szPname );
			strcat( s, sMapperSuffixInput );
		}
		else
		{
			s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 ); /* MEM */
			strcpy( s, wic.szPname );
		}
        deviceInfo->name = s;
        deviceInfo->maxInputChannels = wic.wChannels;
	/* Sometimes a device can return a rediculously large number of channels.
	** This happened with an SBLive card on a Windows ME box.
	** If that happens, then force it to 2 channels.  PLB20010413
	*/
		if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )
		{
			ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
			deviceInfo->maxInputChannels = 2;
		}
	/* Add a sample rate to the list if we can do stereo 16 bit at that rate
	 * based on the format flags. */
        if( wic.dwFormats & WAVE_FORMAT_1M16 ||wic.dwFormats & WAVE_FORMAT_1S16 )
            sampleRates[ deviceInfo->numSampleRates++ ] = 11025.;
        if( wic.dwFormats & WAVE_FORMAT_2M16 ||wic.dwFormats & WAVE_FORMAT_2S16 )
            sampleRates[ deviceInfo->numSampleRates++ ] = 22050.;
        if( wic.dwFormats & WAVE_FORMAT_4M16 ||wic.dwFormats & WAVE_FORMAT_4S16 )
            sampleRates[ deviceInfo->numSampleRates++ ] = 44100.;
	/* Add a sample rate to the list if we can do stereo 16 bit at that rate
	 * based on opening the device successfully. */
        for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ){
            WAVEFORMATEX wfx;
            wfx.wFormatTag = WAVE_FORMAT_PCM;
            wfx.nSamplesPerSec = customSamplingRates[i];
            wfx.wBitsPerSample = 16;
            wfx.cbSize = 0; /* ignored */
            wfx.nChannels = (WORD)deviceInfo->maxInputChannels;
            wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short);
            wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short));
            if( waveInOpen( NULL, inputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR )
			{
                sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i];
            }
        }
        
    }
	else if( id - sNumInputDevices < sNumOutputDevices )
	{
        /* output device */
        int outputMmID = id - sNumInputDevices - 1;
        WAVEOUTCAPS woc;
        if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR )
            goto error;
	/* Append I/O suffix to WAVE_MAPPER device. */
		if( outputMmID == WAVE_MAPPER )
		{
			s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) );  /* MEM */
			strcpy( s, woc.szPname );
			strcat( s, sMapperSuffixOutput );
		}
		else
		{
			s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 );  /* MEM */
			strcpy( s, woc.szPname );
		}
        deviceInfo->name = s;
        deviceInfo->maxOutputChannels = woc.wChannels;
	/* Sometimes a device can return a rediculously large number of channels.
	** This happened with an SBLive card on a Windows ME box.
	** If that happens, then force it to 2 channels. PLB20010413
	*/
		if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )
		{
			ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
			deviceInfo->maxOutputChannels = 2;
		}
	/* Add a sample rate to the list if we can do stereo 16 bit at that rate
	 * based on the format flags. */
        if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 )
            sampleRates[ deviceInfo->numSampleRates++ ] = 11025.;
        if( woc.dwFormats & WAVE_FORMAT_2M16 ||woc.dwFormats & WAVE_FORMAT_2S16 )
            sampleRates[ deviceInfo->numSampleRates++ ] = 22050.;
        if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 )
            sampleRates[ deviceInfo->numSampleRates++ ] = 44100.;
	/* Add a sample rate to the list if we can do stereo 16 bit at that rate
	 * based on opening the device successfully. */
        for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ )
		{
            WAVEFORMATEX wfx;
            wfx.wFormatTag = WAVE_FORMAT_PCM;
            wfx.nSamplesPerSec = customSamplingRates[i];
            wfx.wBitsPerSample = 16;
            wfx.cbSize = 0; /* ignored */
            wfx.nChannels = (WORD)deviceInfo->maxOutputChannels;
            wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short);
            wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short));
            if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ){
                sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i];
            }
        }
    }
    sDevicePtrs[ id ] = deviceInfo;
    return deviceInfo;
error:
    GlobalFree( sampleRates ); /* MEM */
    GlobalFree( deviceInfo ); /* MEM */

⌨️ 快捷键说明

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