📄 pa_win_ds.c
字号:
/* Check for underflow */ if( dsw->dsw_OutputUnderflows != previousUnderflowCount ) stream->callbackFlags |= paOutputUnderflow; } if( (numInFramesReady > 0) && (numOutFramesReady > 0) ) { framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady; } if( framesToXfer > 0 ) { PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); /* The outputBufferDacTime parameter should indicates the time at which the first sample of the output buffer is heard at the DACs. */ timeInfo.currentTime = PaUtil_GetTime(); timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency; PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, stream->callbackFlags ); stream->callbackFlags = 0; /* Input */ if( stream->bufferProcessor.inputChannelCount > 0 ) { bytesToXfer = framesToXfer * dsw->dsw_BytesPerInputFrame; hresult = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, bytesToXfer, (void **) &lpInBuf1, &dwInSize1, (void **) &lpInBuf2, &dwInSize2, 0); if (hresult != DS_OK) { ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult)); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult ); goto error2; } numFrames = dwInSize1 / dsw->dsw_BytesPerInputFrame; PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 ); /* Is input split into two regions. */ if( dwInSize2 > 0 ) { numFrames = dwInSize2 / dsw->dsw_BytesPerInputFrame; PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 ); } } /* Output */ if( stream->bufferProcessor.outputChannelCount > 0 ) { bytesToXfer = framesToXfer * dsw->dsw_BytesPerOutputFrame; hresult = IDirectSoundBuffer_Lock ( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesToXfer, (void **) &lpOutBuf1, &dwOutSize1, (void **) &lpOutBuf2, &dwOutSize2, 0); if (hresult != DS_OK) { ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult)); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult ); goto error1; } numFrames = dwOutSize1 / dsw->dsw_BytesPerOutputFrame; PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 ); /* Is output split into two regions. */ if( dwOutSize2 > 0 ) { numFrames = dwOutSize2 / dsw->dsw_BytesPerOutputFrame; PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames ); PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 ); } } result = paContinue; numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result ); stream->framesWritten += numFrames; if( stream->bufferProcessor.outputChannelCount > 0 ) { /* FIXME: an underflow could happen here */ /* Update our buffer offset and unlock sound buffer */ bytesProcessed = numFrames * dsw->dsw_BytesPerOutputFrame; dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + bytesProcessed) % dsw->dsw_OutputSize; IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2); dsw->dsw_FramesWritten += numFrames; }error1: if( stream->bufferProcessor.inputChannelCount > 0 ) { /* FIXME: an overflow could happen here */ /* Update our buffer offset and unlock sound buffer */ bytesProcessed = numFrames * dsw->dsw_BytesPerInputFrame; dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + bytesProcessed) % dsw->dsw_InputSize; IDirectSoundCaptureBuffer_Unlock( dsw->dsw_InputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2); }error2: PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames ); } return result;}/*******************************************************************/static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2){ PaWinDsStream *stream; /* suppress unused variable warnings */ (void) uID; (void) uMsg; (void) dw1; (void) dw2; stream = (PaWinDsStream *) dwUser; if( stream == NULL ) return; if( stream->isActive ) { if( stream->abortProcessing ) { stream->isActive = 0; } else if( stream->stopProcessing ) { DSoundWrapper *dsw = &stream->directSoundWrapper; if( stream->bufferProcessor.outputChannelCount > 0 ) { DSW_ZeroEmptySpace( dsw ); /* clear isActive when all sound played */ if( dsw->dsw_FramesPlayed >= stream->framesWritten ) { stream->isActive = 0; } } else { stream->isActive = 0; } } else { if( Pa_TimeSlice( stream ) != 0) /* Call time slice independant of timing method. */ { /* FIXME implement handling of paComplete and paAbort if possible */ stream->stopProcessing = 1; } } if( !stream->isActive ){ if( stream->streamRepresentation.streamFinishedCallback != 0 ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } }}/*********************************************************************************** When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted.*/static PaError CloseStream( PaStream* s ){ PaError result = paNoError; PaWinDsStream *stream = (PaWinDsStream*)s; DSW_Term( &stream->directSoundWrapper ); PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); return result;}/***********************************************************************************/static PaError StartStream( PaStream *s ){ PaError result = paNoError; PaWinDsStream *stream = (PaWinDsStream*)s; HRESULT hr; PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); if( stream->bufferProcessor.inputChannelCount > 0 ) { hr = DSW_StartInput( &stream->directSoundWrapper ); DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr)); if( hr != DS_OK ) { result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } } stream->framesWritten = 0; stream->callbackFlags = 0; stream->abortProcessing = 0; stream->stopProcessing = 0; stream->isActive = 1; if( stream->bufferProcessor.outputChannelCount > 0 ) { /* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */ result = Pa_TimeSlice( stream ); if( result != paNoError ) return result; // FIXME - what if finished? hr = DSW_StartOutput( &stream->directSoundWrapper ); DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr)); if( hr != DS_OK ) { result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } } /* Create timer that will wake us up so we can fill the DSound buffer. */ { int resolution; int framesPerWakeup = stream->framesPerDSBuffer / 4; int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate; if( msecPerWakeup < 10 ) msecPerWakeup = 10; else if( msecPerWakeup > 100 ) msecPerWakeup = 100; resolution = msecPerWakeup/4; stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback, (DWORD) stream, TIME_PERIODIC ); } if( stream->timerID == 0 ) { stream->isActive = 0; result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } stream->isStarted = TRUE;error: return result;}/***********************************************************************************/static PaError StopStream( PaStream *s ){ PaError result = paNoError; PaWinDsStream *stream = (PaWinDsStream*)s; HRESULT hr; int timeoutMsec; stream->stopProcessing = 1; /* Set timeout at 20% beyond maximum time we might wait. */ timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate); while( stream->isActive && (timeoutMsec > 0) ) { Sleep(10); timeoutMsec -= 10; } if( stream->timerID != 0 ) { timeKillEvent(stream->timerID); /* Stop callback timer. */ stream->timerID = 0; } if( stream->bufferProcessor.outputChannelCount > 0 ) { hr = DSW_StopOutput( &stream->directSoundWrapper ); } if( stream->bufferProcessor.inputChannelCount > 0 ) { hr = DSW_StopInput( &stream->directSoundWrapper ); } stream->isStarted = FALSE; return result;}/***********************************************************************************/static PaError AbortStream( PaStream *s ){ PaWinDsStream *stream = (PaWinDsStream*)s; stream->abortProcessing = 1; return StopStream( s );}/***********************************************************************************/static PaError IsStreamStopped( PaStream *s ){ PaWinDsStream *stream = (PaWinDsStream*)s; return !stream->isStarted;}/***********************************************************************************/static PaError IsStreamActive( PaStream *s ){ PaWinDsStream *stream = (PaWinDsStream*)s; return stream->isActive;}/***********************************************************************************/static PaTime GetStreamTime( PaStream *s ){ /* suppress unused variable warnings */ (void) s; /* new behavior for GetStreamTime is to return a stream based seconds clock used for the outTime parameter to the callback. FIXME: delete this comment when the other unnecessary related code has been cleaned from this file. PaWinDsStream *stream = (PaWinDsStream*)s; DSoundWrapper *dsw; dsw = &stream->directSoundWrapper; return dsw->dsw_FramesPlayed;*/ return PaUtil_GetTime();}/***********************************************************************************/static double GetStreamCpuLoad( PaStream* s ){ PaWinDsStream *stream = (PaWinDsStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );}/*********************************************************************************** As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams.*/static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ){ PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError;}/***********************************************************************************/static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames ){ PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) buffer; (void) frames; (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return paNoError;}/***********************************************************************************/static signed long GetStreamReadAvailable( PaStream* s ){ PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0;}/***********************************************************************************/static signed long GetStreamWriteAvailable( PaStream* s ){ PaWinDsStream *stream = (PaWinDsStream*)s; /* suppress unused variable warnings */ (void) stream; /* IMPLEMENT ME, see portaudio.h for required behavior*/ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -