📄 pa_win_wmme.c
字号:
{ result = hostOutputSampleSize; goto error; } if( outputStreamInfo && ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) ) { /* set effectiveOutputChannelCount to the largest number of channels on any one device. */ effectiveOutputChannelCount = 0; for( i=0; i< outputStreamInfo->deviceCount; ++i ) { if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount ) effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount; } } else { effectiveOutputChannelCount = outputChannelCount; } hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount; maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize); if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ ) maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_; /* compute the following in bytes, then convert back to frames */ SelectBufferSizeAndCount( ((framesPerBuffer == paFramesPerBufferUnspecified) ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ : framesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */ ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */ 4, /* baseBufferCount */ minimumBufferCount, maximumBufferSize, &hostBufferSizeBytes, &hostBufferCount ); *framesPerHostOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize; *hostOutputBufferCount = hostBufferCount; if( inputChannelCount > 0 ) { /* ensure that both input and output buffer sizes are the same. if they don't match at this stage, choose the smallest one and use that for input and output */ if( *framesPerHostOutputBuffer != *framesPerHostInputBuffer ) { if( framesPerHostInputBuffer < framesPerHostOutputBuffer ) { unsigned long framesPerHostBuffer = *framesPerHostInputBuffer; minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_; ReselectBufferCount( framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */ ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */ 4, /* baseBufferCount */ minimumBufferCount, &hostBufferCount ); *framesPerHostOutputBuffer = framesPerHostBuffer; *hostOutputBufferCount = hostBufferCount; } else { unsigned long framesPerHostBuffer = *framesPerHostOutputBuffer; minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_; ReselectBufferCount( framesPerHostBuffer * hostInputFrameSize, /* bufferSize */ ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */ 4, /* baseBufferCount */ minimumBufferCount, &hostBufferCount ); *framesPerHostInputBuffer = framesPerHostBuffer; *hostInputBufferCount = hostBufferCount; } } } } } else { *framesPerHostOutputBuffer = 0; *hostOutputBufferCount = 0; }error: return result;}typedef struct{ HANDLE bufferEvent; void *waveHandles; unsigned int deviceCount; /* unsigned int channelCount; */ WAVEHDR **waveHeaders; /* waveHeaders[device][buffer] */ unsigned int bufferCount; unsigned int currentBufferIndex; unsigned int framesPerBuffer; unsigned int framesUsedInCurrentBuffer;}PaWinMmeSingleDirectionHandlesAndBuffers;/* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers );static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long bytesPerHostSample, double sampleRate, PaWinMmeDeviceAndChannelCount *devices, unsigned int deviceCount, int isInput );static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError );static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long hostBufferCount, PaSampleFormat hostSampleFormat, unsigned long framesPerHostBuffer, PaWinMmeDeviceAndChannelCount *devices, int isInput );static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput );static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ){ handlesAndBuffers->bufferEvent = 0; handlesAndBuffers->waveHandles = 0; handlesAndBuffers->deviceCount = 0; handlesAndBuffers->waveHeaders = 0; handlesAndBuffers->bufferCount = 0;} static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long bytesPerHostSample, double sampleRate, PaWinMmeDeviceAndChannelCount *devices, unsigned int deviceCount, int isInput ){ PaError result; MMRESULT mmresult; unsigned long bytesPerFrame; WAVEFORMATEX wfx; signed int i; /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers() has already been called to zero some fields */ result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL ); if( result != paNoError ) goto error; if( isInput ) handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount ); else handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount ); if( !handlesAndBuffers->waveHandles ) { result = paInsufficientMemory; goto error; } handlesAndBuffers->deviceCount = deviceCount; for( i = 0; i < (signed int)deviceCount; ++i ) { if( isInput ) ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0; else ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0; } wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nSamplesPerSec = (DWORD) sampleRate; wfx.cbSize = 0; for( i = 0; i < (signed int)deviceCount; ++i ) { UINT winMmeDeviceId; winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device ); wfx.nChannels = (WORD)devices[i].channelCount; bytesPerFrame = wfx.nChannels * bytesPerHostSample; wfx.nAvgBytesPerSec = (DWORD)(bytesPerFrame * sampleRate); wfx.nBlockAlign = (WORD)bytesPerFrame; wfx.wBitsPerSample = (WORD)((bytesPerFrame/wfx.nChannels) * 8); /* REVIEW: consider not firing an event for input when a full duplex stream is being used. this would probably depend on the neverDropInput flag. */ if( isInput ) mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx, (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT ); else mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx, (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT ); if( mmresult != MMSYSERR_NOERROR ) { switch( mmresult ) { case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */ result = paDeviceUnavailable; break; case MMSYSERR_NODRIVER: /* No device driver is present. */ result = paDeviceUnavailable; break; case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */ result = paInsufficientMemory; break; case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */ /* falls through */ case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */ /* falls through */ default: result = paUnanticipatedHostError; if( isInput ) { PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); } else { PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); } } goto error; } } return result;error: TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ ); return result;}static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError ){ PaError result = paNoError; MMRESULT mmresult; signed int i; if( handlesAndBuffers->waveHandles ) { for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i ) { if( isInput ) { if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] ) mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] ); } else { if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] ) mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] ); } if( mmresult != MMSYSERR_NOERROR && !currentlyProcessingAnError ) /* don't update the error state if we're already processing an error */ { result = paUnanticipatedHostError; if( isInput ) { PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ); } else { PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ); } /* note that we don't break here, we try to continue closing devices */ } } PaUtil_FreeMemory( handlesAndBuffers->waveHandles ); handlesAndBuffers->waveHandles = 0; } if( handlesAndBuffers->bufferEvent ) { result = CloseHandleWithPaError( handlesAndBuffers->bufferEvent ); handlesAndBuffers->bufferEvent = 0; } return result;}static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, unsigned long hostBufferCount, PaSampleFormat hostSampleFormat, unsigned long framesPerHostBuffer, PaWinMmeDeviceAndChannelCount *devices, int isInput ){ PaError result = paNoError; MMRESULT mmresult; WAVEHDR *deviceWaveHeaders; signed int i, j; /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers() has already been called to zero some fields */ /* allocate an array of pointers to arrays of wave headers, one array of wave headers per device */ handlesAndBuffers->waveHeaders = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * handlesAndBuffers->deviceCount ); if( !handlesAndBuffers->waveHeaders ) { result = paInsufficientMemory; goto error; } for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i ) handlesAndBuffers->waveHeaders[i] = 0; handlesAndBuffers->bufferCount = hostBufferCount; for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i ) { int bufferBytes = Pa_GetSampleSize( hostSampleFormat ) * framesPerHostBuffer * devices[i].channelCount; if( bufferBytes < 0 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -