?? pa_win_ds.c
字號:
/* * $Id: pa_win_ds.c 1116 2006-09-06 15:47:03Z rossb $ * Portable Audio I/O Library DirectSound implementation * * Authors: Phil Burk, Robert Marsanyi & Ross Bencina * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2006 Ross Bencina, Phil Burk, Robert Marsanyi * * 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 @todo implement paInputOverflow callback status flag @todo implement paNeverDropInput. @todo implement host api specific extension to set i/o buffer sizes in frames @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.) @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable @todo audit handling of DirectSound result codes - in many cases we could convert a HRESULT into a native portaudio error code. Standard DirectSound result codes are documented at msdn. @todo implement IsFormatSupported @todo check that CoInitialize() CoUninitialize() are always correctly paired, even in error cases. @todo call PaUtil_SetLastHostErrorInfo with a specific error string (currently just "DSound error"). @todo make sure all buffers have been played before stopping the stream when the stream callback returns paComplete old TODOs from phil, need to work out if these have been done: O- fix "patest_stop.c"*/#include <stdio.h>#include <string.h> /* strlen() */#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_ds_dynlink.h"#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */#pragma comment( lib, "dsound.lib" )#pragma comment( lib, "winmm.lib" )#endif/* provided in newer platform sdks and x64 */#ifndef DWORD_PTR#define DWORD_PTR DWORD#endif#define PRINT(x) PA_DEBUG(x);#define ERR_RPT(x) PRINT(x)#define DBUG(x) PRINT(x)#define DBUGX(x) PRINT(x)#define PA_USE_HIGH_LATENCY (0)#if PA_USE_HIGH_LATENCY#define PA_WIN_9X_LATENCY (500)#define PA_WIN_NT_LATENCY (600)#else#define PA_WIN_9X_LATENCY (140)#define PA_WIN_NT_LATENCY (280)#endif#define PA_WIN_WDM_LATENCY (120)#define SECONDS_PER_MSEC (0.001)#define MSEC_PER_SECOND (1000)/* prototypes for functions declared in this file */#ifdef __cplusplusextern "C"{#endif /* __cplusplus */PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );#ifdef __cplusplus}#endif /* __cplusplus */static void Terminate( struct PaUtilHostApiRepresentation *hostApi );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 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 );/* FIXME: should convert hr to a string */#define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \ PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" )/************************************************* DX Prototypes **********/static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext );/************************************************************************************//********************** Structures **************************************************//************************************************************************************//* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */typedef struct PaWinDsDeviceInfo{ GUID guid; GUID *lpGUID; double sampleRates[3];} PaWinDsDeviceInfo;typedef struct{ PaUtilHostApiRepresentation inheritedHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ PaWinDsDeviceInfo *winDsDeviceInfos;} PaWinDsHostApiRepresentation;/* PaWinDsStream - a stream data structure specifically for this implementation */typedef struct PaWinDsStream{ PaUtilStreamRepresentation streamRepresentation; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor;/* DirectSound specific data. *//* Output */ LPDIRECTSOUND pDirectSound; LPDIRECTSOUNDBUFFER pDirectSoundOutputBuffer; DWORD outputBufferWriteOffsetBytes; /* last write position */ INT outputBufferSizeBytes; INT bytesPerOutputFrame; /* Try to detect play buffer underflows. */ LARGE_INTEGER perfCounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */ LARGE_INTEGER previousPlayTime; UINT previousPlayCursor; UINT outputUnderflowCount; BOOL outputIsRunning; /* use double which lets us can play for several thousand years with enough precision */ double dsw_framesWritten; double framesPlayed;/* Input */ LPDIRECTSOUNDCAPTURE pDirectSoundCapture; LPDIRECTSOUNDCAPTUREBUFFER pDirectSoundInputBuffer; INT bytesPerInputFrame; UINT readOffset; /* last read position */ UINT inputSize; MMRESULT timerID; int framesPerDSBuffer; double framesWritten; double secondsPerHostByte; /* Used to optimize latency calculation for outTime */ PaStreamCallbackFlags callbackFlags; /* FIXME - move all below to PaUtilStreamRepresentation */ volatile int isStarted; volatile int isActive; volatile int stopProcessing; /* stop thread once existing buffers have been returned */ volatile int abortProcessing; /* stop thread immediately */} PaWinDsStream;/************************************************************************************** Duplicate the input string using the allocations allocator.** A NULL string is converted to a zero length string.** If memory cannot be allocated, NULL is returned.**/static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const char* src ){ char *result = 0; if( src != NULL ) { size_t len = strlen(src); result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) ); if( result ) memcpy( (void *) result, src, len+1 ); } else { result = (char*)PaUtil_GroupAllocateMemory( allocations, 1 ); if( result ) result[0] = '\0'; } return result;}/************************************************************************************** DSDeviceNameAndGUID, DSDeviceNameAndGUIDVector used for collecting preliminary** information during device enumeration.*/typedef struct DSDeviceNameAndGUID{ char *name; // allocated from parent's allocations, never deleted by this structure GUID guid; LPGUID lpGUID;} DSDeviceNameAndGUID;typedef struct DSDeviceNameAndGUIDVector{ PaUtilAllocationGroup *allocations; PaError enumerationError; int count; int free; DSDeviceNameAndGUID *items; // Allocated using LocalAlloc()} DSDeviceNameAndGUIDVector;static PaError InitializeDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector, PaUtilAllocationGroup *allocations ){ PaError result = paNoError; guidVector->allocations = allocations; guidVector->enumerationError = paNoError; guidVector->count = 0; guidVector->free = 8; guidVector->items = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * guidVector->free ); if( guidVector->items == NULL ) result = paInsufficientMemory; return result;}static PaError ExpandDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector ){ PaError result = paNoError; DSDeviceNameAndGUID *newItems; int i; /* double size of vector */ int size = guidVector->count + guidVector->free; guidVector->free += size; newItems = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * size * 2 ); if( newItems == NULL ) { result = paInsufficientMemory; } else { for( i=0; i < guidVector->count; ++i ) { newItems[i].name = guidVector->items[i].name; if( guidVector->items[i].lpGUID == NULL ) { newItems[i].lpGUID = NULL; } else { newItems[i].lpGUID = &newItems[i].guid; memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) );; } } LocalFree( guidVector->items ); guidVector->items = newItems; } return result;}/* it's safe to call DSDeviceNameAndGUIDVector multiple times*/static PaError TerminateDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector )
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -