📄 pa_win_wdmks.c
字号:
/* * $Id: pa_win_wdmks.c 1097 2006-08-26 08:27:53Z rossb $ * PortAudio Windows WDM-KS interface * * Author: Andrew Baldwin * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, 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. * * 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. *//* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * 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. It is also * requested that these non-binding requests be included along with the * license above. *//** @file @ingroup hostaip_src @brief Portaudio WDM-KS host API. @note This is the implementation of the Portaudio host API using the Windows WDM/Kernel Streaming API in order to enable very low latency playback and recording on all modern Windows platforms (e.g. 2K, XP) Note: This API accesses the device drivers below the usual KMIXER component which is normally used to enable multi-client mixing and format conversion. That means that it will lock out all other users of a device for the duration of active stream using those devices*/#include <stdio.h>/* Debugging/tracing support */#define PA_LOGE_#define PA_LOGL_#ifdef __GNUC__ #include <initguid.h> #define _WIN32_WINNT 0x0501 #define WINVER 0x0501#endif#include <string.h> /* strlen() */#include <assert.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 "portaudio.h"#include <windows.h>#include <winioctl.h>#ifdef __GNUC__ #undef PA_LOGE_ #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__)) #undef PA_LOGL_ #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__)) /* These defines are set in order to allow the WIndows DirectX * headers to compile with a GCC compiler such as MinGW * NOTE: The headers may generate a few warning in GCC, but * they should compile */ #define _INC_MMSYSTEM #define _INC_MMREG #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ #define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid) #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n ) #if !defined( DEFINE_WAVEFORMATEX_GUID ) #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 #endif #define WAVE_FORMAT_ADPCM 0x0002 #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #define WAVE_FORMAT_ALAW 0x0006 #define WAVE_FORMAT_MULAW 0x0007 #define WAVE_FORMAT_MPEG 0x0050 #define WAVE_FORMAT_DRM 0x0009 #define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)#endif#ifdef _MSC_VER #define DYNAMIC_GUID(data) {data} #define _INC_MMREG #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ #undef DEFINE_GUID #define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data} #define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data) #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n) #if !defined( DEFINE_WAVEFORMATEX_GUID ) #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 #endif #define WAVE_FORMAT_ADPCM 0x0002 #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #define WAVE_FORMAT_ALAW 0x0006 #define WAVE_FORMAT_MULAW 0x0007 #define WAVE_FORMAT_MPEG 0x0050 #define WAVE_FORMAT_DRM 0x0009#endif#include <ks.h>#include <ksmedia.h>#include <tchar.h>#include <assert.h>#include <stdio.h>/* These next definitions allow the use of the KSUSER DLL */typedef KSDDKAPI DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE);extern HMODULE DllKsUser;extern KSCREATEPIN* FunctionKsCreatePin;/* Forward definition to break circular type reference between pin and filter */struct __PaWinWdmFilter;typedef struct __PaWinWdmFilter PaWinWdmFilter;/* The Pin structure * A pin is an input or output node, e.g. for audio flow */typedef struct __PaWinWdmPin{ HANDLE handle; PaWinWdmFilter* parentFilter; unsigned long pinId; KSPIN_CONNECT* pinConnect; unsigned long pinConnectSize; KSDATAFORMAT_WAVEFORMATEX* ksDataFormatWfx; KSPIN_COMMUNICATION communication; KSDATARANGE* dataRanges; KSMULTIPLE_ITEM* dataRangesItem; KSPIN_DATAFLOW dataFlow; KSPIN_CINSTANCES instances; unsigned long frameSize; int maxChannels; unsigned long formats; int bestSampleRate;}PaWinWdmPin;/* The Filter structure * A filter has a number of pins and a "friendly name" */struct __PaWinWdmFilter{ HANDLE handle; int pinCount; PaWinWdmPin** pins; TCHAR filterName[MAX_PATH]; TCHAR friendlyName[MAX_PATH]; int maxInputChannels; int maxOutputChannels; unsigned long formats; int usageCount; int bestSampleRate;};/* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */typedef struct __PaWinWdmHostApiRepresentation{ PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup* allocations; PaWinWdmFilter** filters; int filterCount;}PaWinWdmHostApiRepresentation;typedef struct __PaWinWdmDeviceInfo{ PaDeviceInfo inheritedDeviceInfo; PaWinWdmFilter* filter;}PaWinWdmDeviceInfo;typedef struct __DATAPACKET{ KSSTREAM_HEADER Header; OVERLAPPED Signal;} DATAPACKET;/* PaWinWdmStream - a stream data structure specifically for this implementation */typedef struct __PaWinWdmStream{ PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaWinWdmPin* recordingPin; PaWinWdmPin* playbackPin; char* hostBuffer; unsigned long framesPerHostIBuffer; unsigned long framesPerHostOBuffer; int bytesPerInputFrame; int bytesPerOutputFrame; int streamStarted; int streamActive; int streamStop; int streamAbort; int oldProcessPriority; HANDLE streamThread; HANDLE events[5]; /* 2 play + 2 record packets + abort events */ DATAPACKET packets[4]; /* 2 play + 2 record */ PaStreamFlags streamFlags; /* These values handle the case where the user wants to use fewer * channels than the device has */ int userInputChannels; int deviceInputChannels; int userOutputChannels; int deviceOutputChannels; int inputSampleSize; int outputSampleSize;}PaWinWdmStream;#include <setupapi.h>HMODULE DllKsUser = NULL;KSCREATEPIN* FunctionKsCreatePin = NULL;/* prototypes for functions declared in this file */#ifdef __cplusplusextern "C"{#endif /* __cplusplus */PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );#ifdef __cplusplus}#endif /* __cplusplus *//* Low level I/O functions */static PaError WdmSyncIoctl(HANDLE handle, unsigned long ioctlNumber, void* inBuffer, unsigned long inBufferCount, void* outBuffer, unsigned long outBufferCount, unsigned long* bytesReturned);static PaError WdmGetPropertySimple(HANDLE handle, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount, void* instance, unsigned long instanceCount);static PaError WdmSetPropertySimple(HANDLE handle, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount, void* instance, unsigned long instanceCount);static PaError WdmGetPinPropertySimple(HANDLE handle, unsigned long pinId, const GUID* const guidPropertySet, unsigned long property, void* value, unsigned long valueCount);static PaError WdmGetPinPropertyMulti(HANDLE handle, unsigned long pinId, const GUID* const guidPropertySet, unsigned long property, KSMULTIPLE_ITEM** ksMultipleItem);/** Pin management functions */static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error);static void PinFree(PaWinWdmPin* pin);static void PinClose(PaWinWdmPin* pin);static PaError PinInstantiate(PaWinWdmPin* pin);/*static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state); NOT USED */static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state);static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format);static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format);/* Filter management functions */static PaWinWdmFilter* FilterNew( TCHAR* filterName, TCHAR* friendlyName, PaError* error);static void FilterFree(PaWinWdmFilter* filter);static PaWinWdmPin* FilterCreateRenderPin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error);static PaWinWdmPin* FilterFindViableRenderPin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error);static PaError FilterCanCreateRenderPin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex);static PaWinWdmPin* FilterCreateCapturePin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error);static PaWinWdmPin* FilterFindViableCapturePin( PaWinWdmFilter* filter, const WAVEFORMATEX* wfex, PaError* error);static PaError FilterCanCreateCapturePin( PaWinWdmFilter* filter, const WAVEFORMATEX* pwfx);static PaError FilterUse( PaWinWdmFilter* filter);static void FilterRelease( PaWinWdmFilter* filter);/* Interface functions */static void Terminate( struct PaUtilHostApiRepresentation *hostApi );static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate );static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData );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 );/* Utility functions */static unsigned long GetWfexSize(const WAVEFORMATEX* wfex);static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi);static BOOL PinWrite(HANDLE h, DATAPACKET* p);static BOOL PinRead(HANDLE h, DATAPACKET* p);static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples);static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples);static DWORD WINAPI ProcessingThread(LPVOID pParam);/* Function bodies */static unsigned long GetWfexSize(const WAVEFORMATEX* wfex){ if( wfex->wFormatTag == WAVE_FORMAT_PCM ) { return sizeof( WAVEFORMATEX ); } else { return (sizeof( WAVEFORMATEX ) + wfex->cbSize); }}/*Low level pin/filter access functions*/static PaError WdmSyncIoctl( HANDLE handle, unsigned long ioctlNumber, void* inBuffer, unsigned long inBufferCount, void* outBuffer, unsigned long outBufferCount, unsigned long* bytesReturned){ PaError result = paNoError; OVERLAPPED overlapped; int boolResult; unsigned long dummyBytesReturned; unsigned long error; if( !bytesReturned ) { /* User a dummy as the caller hasn't supplied one */ bytesReturned = &dummyBytesReturned; } FillMemory((void *)&overlapped,sizeof(overlapped),0); overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -