📄 pa_win_wmme.c
字号:
/* * $Id: pa_win_wmme.c,v 1.2 2004/04/22 04:19:51 mbrubeck Exp $ * 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 obtaining * 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. * *//* Modification History: PLB = Phil Burk JM = Julien Maillard RDB = Ross Bencina 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 conditional inclusion 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. JM20020118 - prevent hung thread when buffers underflow. PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices refactoring, renaming and fixed a few edge case bugs RDB20020531 - converted to V19 framework ** NOTE maintanance history is now stored in CVS ***//** @file @todo Fix buffer catch up code, can sometimes get stuck (perhaps fixed now, needs to be reviewed and tested.) @todo implement paInputUnderflow, paOutputOverflow streamCallback statusFlags, paNeverDropInput. @todo BUG: PA_MME_SET_LAST_WAVEIN/OUT_ERROR is used in functions which may be called asynchronously from the callback thread. this is bad. @todo implement inputBufferAdcTime in callback thread @todo review/fix error recovery and cleanup in marked functions @todo implement timeInfo for stream priming @todo handle the case where the callback returns paAbort or paComplete during stream priming. @todo review input overflow and output underflow handling in ReadStream and WriteStreamNon-critical stuff for the future: @todo Investigate supporting host buffer formats > 16 bits @todo define UNICODE and _UNICODE in the project settings and see what breaks*//* How it works: For both callback and blocking read/write streams we open the MME devices in CALLBACK_EVENT mode. In this mode, MME signals an Event object whenever it has finished with a buffer (either filled it for input, or played it for output). Where necessary we block waiting for Event objects using WaitMultipleObjects(). When implementing a PA callback stream, we set up a high priority thread which waits on the MME buffer Events and drains/fills the buffers when they are ready. When implementing a PA blocking read/write stream, we simply wait on these Events (when necessary) inside the ReadStream() and WriteStream() functions.*/#include <stdio.h>#include <stdlib.h>#include <math.h>#include <windows.h>#include <mmsystem.h>#include <process.h>#include <assert.h>/* 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_trace.h"#include "pa_util.h"#include "pa_allocation.h"#include "pa_hostapi.h"#include "pa_stream.h"#include "pa_cpuload.h"#include "pa_process.h"#include "pa_win_wmme.h"#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */#pragma comment(lib, "winmm.lib")#endif/************************************************* Constants ********/#define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */#if PA_MME_USE_HIGH_DEFAULT_LATENCY_ #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4) #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (4) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (4) #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16) #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.3) /* Do not exceed unless user buffer exceeds */ #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */#else #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.2) #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (2) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (3) #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (2) #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16) #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.1) /* Do not exceed unless user buffer exceeds */ #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */#endif/* Use higher latency for NT because it is even worse at real-time operation than Win9x.*/#define PA_MME_WIN_NT_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_ * 2)#define PA_MME_WIN_WDM_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_)#define PA_MME_MIN_TIMEOUT_MSEC_ (1000)static const char constInputMapperSuffix_[] = " - Input";static const char constOutputMapperSuffix_[] = " - Output";/********************************************************************/typedef struct PaWinMmeStream PaWinMmeStream; /* forward declaration *//* prototypes for functions declared in this file */#ifdef __cplusplusextern "C"{#endif /* __cplusplus */PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );#ifdef __cplusplus}#endif /* __cplusplus */static void Terminate( struct PaUtilHostApiRepresentation *hostApi );static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData );static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate );static PaError CloseStream( PaStream* stream );static PaError StartStream( PaStream *stream );static PaError StopStream( PaStream *stream );static PaError AbortStream( PaStream *stream );static PaError IsStreamStopped( PaStream *s );static PaError IsStreamActive( PaStream *stream );static PaTime GetStreamTime( PaStream *stream );static double GetStreamCpuLoad( PaStream* stream );static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );static signed long GetStreamReadAvailable( PaStream* stream );static signed long GetStreamWriteAvailable( PaStream* stream );/* macros for setting last host error information */#ifdef UNICODE#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \ { \ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ }#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \ { \ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ } #else /* !UNICODE */#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \ { \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ }#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \ { \ char mmeErrorText[ MAXERRORLENGTH ]; \ waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \ }#endif /* UNICODE */static void PaMme_SetLastSystemError( DWORD errorCode ){ char *lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf ); LocalFree( lpMsgBuf );}#define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \ PaMme_SetLastSystemError( errorCode )/* PaError returning wrappers for some commonly used win32 functions note that we allow passing a null ptr to have no effect.*/static PaError CreateEventWithPaError( HANDLE *handle, LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName ){ PaError result = paNoError; *handle = NULL; *handle = CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName ); if( *handle == NULL ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); } return result;}static PaError ResetEventWithPaError( HANDLE handle ){ PaError result = paNoError; if( handle ) { if( ResetEvent( handle ) == 0 ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); } } return result;}static PaError CloseHandleWithPaError( HANDLE handle ){ PaError result = paNoError; if( handle ) { if( CloseHandle( handle ) == 0 ) { result = paUnanticipatedHostError; PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() ); } } return result;}/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */typedef struct{ PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -