pa_win_ds.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 1,801 行 · 第 1/5 页
C
1,801 行
unless some flag indicated otherwise */ /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate hostApiSpecificStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; suggestedInputLatencyFrames = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate); /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate hostApiSpecificStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; suggestedOutputLatencyFrames = 0; } /* IMPLEMENT ME: ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() ) - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - if a full duplex stream is requested, check that the combination of input and output parameters is supported - check that the device supports sampleRate - alter sampleRate to a close allowable rate if possible / necessary - validate suggestedInputLatency and suggestedOutputLatency parameters, use default values where necessary */ /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) ); if( !stream ) { result = paInsufficientMemory; goto error; } if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &winDsHostApi->callbackStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &winDsHostApi->blockingStreamInterface, streamCallback, userData ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); if( inputParameters ) { /* IMPLEMENT ME - establish which host formats are available */ hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputParameters->sampleFormat ); } if( outputParameters ) { /* IMPLEMENT ME - establish which host formats are available */ hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputParameters->sampleFormat ); } result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, outputChannelCount, outputSampleFormat, hostOutputSampleFormat, sampleRate, streamFlags, framesPerBuffer, framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */ /* This next mode is required because DS can split the host buffer when it wraps around. */ paUtilVariableHostBufferSizePartialUsageAllowed, streamCallback, userData ); if( result != paNoError ) goto error; stream->streamRepresentation.streamInfo.inputLatency = PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */ stream->streamRepresentation.streamInfo.outputLatency = PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */ stream->streamRepresentation.streamInfo.sampleRate = sampleRate; /* DirectSound specific initialization */ { HRESULT hr; int bytesPerDirectSoundBuffer; DSoundWrapper *dsw; int userLatencyFrames; int minLatencyFrames; stream->timerID = 0; dsw = &stream->directSoundWrapper; DSW_Init( dsw ); /* Get system minimum latency. */ minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate ); /* Let user override latency by passing latency parameter. */ userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames) ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames; if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames; /* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */ if( framesPerBuffer == paFramesPerBufferUnspecified ) { /* App support variable framesPerBuffer */ stream->framesPerDSBuffer = minLatencyFrames; stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate; } else { /* Round up to number of buffers needed to guarantee that latency. */ int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer; if( numUserBuffers < 1 ) numUserBuffers = 1; numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */ stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers; stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate; } { /** @todo REVIEW: this calculation seems incorrect to me - rossb. */ int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate); PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency )); } /* ------------------ OUTPUT */ if( outputParameters ) { /* PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ]; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputParameters->device)); */ bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * sizeof(short); if( bytesPerDirectSoundBuffer < DSBSIZE_MIN ) { result = paBufferTooSmall; goto error; } else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX ) { result = paBufferTooBig; goto error; } hr = dswDSoundEntryPoints.DirectSoundCreate( winDsHostApi->winDsDeviceInfos[outputParameters->device].lpGUID, &dsw->dsw_pDirectSound, NULL ); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n")); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } hr = DSW_InitOutputBuffer( dsw, (unsigned long) (sampleRate + 0.5), (WORD)outputParameters->channelCount, bytesPerDirectSoundBuffer ); DBUG(("DSW_InitOutputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } /* Calculate value used in latency calculation to avoid real-time divides. */ stream->secondsPerHostByte = 1.0 / (stream->bufferProcessor.bytesPerHostOutputSample * outputChannelCount * sampleRate); } /* ------------------ INPUT */ if( inputParameters ) { /* PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ]; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", inputParameters->device)); */ bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * sizeof(short); if( bytesPerDirectSoundBuffer < DSBSIZE_MIN ) { result = paBufferTooSmall; goto error; } else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX ) { result = paBufferTooBig; goto error; } hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( winDsHostApi->winDsDeviceInfos[inputParameters->device].lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n")); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } hr = DSW_InitInputBuffer( dsw, (unsigned long) (sampleRate + 0.5), (WORD)inputParameters->channelCount, bytesPerDirectSoundBuffer ); DBUG(("DSW_InitInputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr)); result = paUnanticipatedHostError; PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ); goto error; } } } *s = (PaStream*)stream; return result;error: if( stream ) PaUtil_FreeMemory( stream ); return result;}/***********************************************************************************/static PaError Pa_TimeSlice( PaWinDsStream *stream ){ PaError result = 0; /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/ DSoundWrapper *dsw; long numFrames = 0; long bytesEmpty = 0; long bytesFilled = 0; long bytesToXfer = 0; long framesToXfer = 0; long numInFramesReady = 0; long numOutFramesReady = 0; long bytesProcessed; HRESULT hresult; double outputLatency = 0; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */ /* Input */ LPBYTE lpInBuf1 = NULL; LPBYTE lpInBuf2 = NULL; DWORD dwInSize1 = 0; DWORD dwInSize2 = 0;/* Output */ LPBYTE lpOutBuf1 = NULL; LPBYTE lpOutBuf2 = NULL; DWORD dwOutSize1 = 0; DWORD dwOutSize2 = 0; dsw = &stream->directSoundWrapper; /* How much input data is available? */ if( stream->bufferProcessor.inputChannelCount > 0 ) { DSW_QueryInputFilled( dsw, &bytesFilled ); framesToXfer = numInFramesReady = bytesFilled / dsw->dsw_BytesPerInputFrame; outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte; /** @todo Check for overflow */ } /* How much output room is available? */ if( stream->bufferProcessor.outputChannelCount > 0 ) { UINT previousUnderflowCount = dsw->dsw_OutputUnderflows; DSW_QueryOutputSpace( dsw, &bytesEmpty ); framesToXfer = numOutFramesReady = bytesEmpty / dsw->dsw_BytesPerOutputFrame; /* 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)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?