📄 pa_dsound.c
字号:
if( sNumDevices <= 0 ) Pa_Initialize(); return sNumDevices;}static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ){ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; return &sDevices[id];}/*************************************************************************/const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ){ internalPortAudioDevice *pad; if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; pad = Pa_GetInternalDevice( id ); return &pad->pad_Info ;}static PaError Pa_MaybeQueryDevices( void ){ if( sNumDevices == 0 ) { return Pa_QueryDevices(); } return 0;}/*************************************************************************** Returns recommended device ID.** On the PC, the recommended device can be specified by the user by** setting an environment variable. For example, to use device #1.**** set PA_RECOMMENDED_OUTPUT_DEVICE=1**** The user should first determine the available device ID by using** the supplied application "pa_devs".*/#define PA_ENV_BUF_SIZE (32)#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ){ DWORD hresult; char envbuf[PA_ENV_BUF_SIZE]; PaDeviceID recommendedID = paNoDevice; /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { recommendedID = atoi( envbuf ); } return recommendedID;}PaDeviceID Pa_GetDefaultInputDeviceID( void ){ PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); if( result < 0 ) { result = Pa_MaybeQueryDevices(); if( result < 0 ) return result; result = sDefaultInputDeviceID; } return result;}PaDeviceID Pa_GetDefaultOutputDeviceID( void ){ PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); if( result < 0 ) { result = Pa_MaybeQueryDevices(); if( result < 0 ) return result; result = sDefaultOutputDeviceID; } return result;}/************************************************************************ Make sure that we have queried the device capabilities.*/PaError PaHost_Init( void ){#if PA_SIMULATE_UNDERFLOW PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n"));#endif return Pa_MaybeQueryDevices();}static PaError Pa_TimeSlice( internalPortAudioStream *past ){ PaError result = 0; long bytesEmpty = 0; long bytesFilled = 0; long bytesToXfer = 0; long numChunks; HRESULT hresult; PaHostSoundControl *pahsc; short *nativeBufPtr; past->past_NumCallbacks += 1; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; /* How much input data is available? */#if SUPPORT_AUDIO_CAPTURE if( past->past_NumInputChannels > 0 ) { DSW_QueryInputFilled( &pahsc->pahsc_DSoundWrapper, &bytesFilled ); bytesToXfer = bytesFilled; }#endif /* SUPPORT_AUDIO_CAPTURE */ /* How much output room is available? */ if( past->past_NumOutputChannels > 0 ) { DSW_QueryOutputSpace( &pahsc->pahsc_DSoundWrapper, &bytesEmpty ); bytesToXfer = bytesEmpty; } AddTraceMessage( "bytesEmpty ", bytesEmpty ); /* Choose smallest value if both are active. */ if( (past->past_NumInputChannels > 0) && (past->past_NumOutputChannels > 0) ) { bytesToXfer = ( bytesFilled < bytesEmpty ) ? bytesFilled : bytesEmpty; } /* printf("bytesFilled = %d, bytesEmpty = %d, bytesToXfer = %d\n", bytesFilled, bytesEmpty, bytesToXfer); */ /* Quantize to multiples of a buffer. */ numChunks = bytesToXfer / pahsc->pahsc_BytesPerBuffer; if( numChunks > (long)(past->past_NumUserBuffers/2) ) { numChunks = (long)past->past_NumUserBuffers/2; } else if( numChunks < 0 ) { numChunks = 0; } AddTraceMessage( "numChunks ", numChunks ); nativeBufPtr = pahsc->pahsc_NativeBuffer; if( numChunks > 0 ) { while( numChunks-- > 0 ) { /* Measure usage based on time to process one user buffer. */ Pa_StartUsageCalculation( past );#if SUPPORT_AUDIO_CAPTURE /* Get native data from DirectSound. */ if( past->past_NumInputChannels > 0 ) { hresult = DSW_ReadBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); if( hresult < 0 ) { ERR_RPT(("DirectSound ReadBlock failed, hresult = 0x%x\n",hresult)); sPaHostError = hresult; break; } }#endif /* SUPPORT_AUDIO_CAPTURE */ /* Convert 16 bit native data to user data and call user routine. */ result = Pa_CallConvertInt16( past, nativeBufPtr, nativeBufPtr ); if( result != 0) break; /* Pass native data to DirectSound. */ if( past->past_NumOutputChannels > 0 ) { /* static short DEBUGHACK = 0; DEBUGHACK += 0x0049; nativeBufPtr[0] = DEBUGHACK; /* Make buzz to see if DirectSound still running. */ hresult = DSW_WriteBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); if( hresult < 0 ) { ERR_RPT(("DirectSound WriteBlock failed, result = 0x%x\n",hresult)); sPaHostError = hresult; break; } } Pa_EndUsageCalculation( past ); } } return result;}/*******************************************************************/static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2){ internalPortAudioStream *past; PaHostSoundControl *pahsc;#if PA_SIMULATE_UNDERFLOW gUnderCallbackCounter++; if( (gUnderCallbackCounter >= UNDER_START_GAP) && (gUnderCallbackCounter <= UNDER_STOP_GAP) ) { if( gUnderCallbackCounter == UNDER_START_GAP) { AddTraceMessage("Begin stall: gUnderCallbackCounter =======", gUnderCallbackCounter ); } if( gUnderCallbackCounter == UNDER_STOP_GAP) { AddTraceMessage("End stall: gUnderCallbackCounter =======", gUnderCallbackCounter ); } return; }#endif past = (internalPortAudioStream *) dwUser; if( past == NULL ) return; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; if( !pahsc->pahsc_IfInsideCallback && past->past_IsActive ) { if( past->past_StopNow ) { past->past_IsActive = 0; } else if( past->past_StopSoon ) { DSoundWrapper *dsw = &pahsc->pahsc_DSoundWrapper; if( past->past_NumOutputChannels > 0 ) { DSW_ZeroEmptySpace( dsw ); AddTraceMessage("Pa_TimerCallback: waiting - written ", (int) dsw->dsw_FramesWritten ); AddTraceMessage("Pa_TimerCallback: waiting - played ", (int) dsw->dsw_FramesPlayed ); /* clear past_IsActive when all sound played */ if( dsw->dsw_FramesPlayed >= past->past_FrameCount ) { past->past_IsActive = 0; } } else { past->past_IsActive = 0; } } else { pahsc->pahsc_IfInsideCallback = 1; if( Pa_TimeSlice( past ) != 0) /* Call time slice independant of timing method. */ { past->past_StopSoon = 1; } pahsc->pahsc_IfInsideCallback = 0; } }}/*******************************************************************/PaError PaHost_OpenStream( internalPortAudioStream *past ){ HRESULT hr; PaError result = paNoError; PaHostSoundControl *pahsc; int numBytes, maxChannels; unsigned int minNumBuffers; internalPortAudioDevice *pad; DSoundWrapper *dsw; /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */ if( pahsc == NULL ) { result = paInsufficientMemory; goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; pahsc->pahsc_TimerID = 0; dsw = &pahsc->pahsc_DSoundWrapper; DSW_Init( dsw ); /* Allocate native buffer. */ maxChannels = ( past->past_NumOutputChannels > past->past_NumInputChannels ) ? past->past_NumOutputChannels : past->past_NumInputChannels; pahsc->pahsc_BytesPerBuffer = past->past_FramesPerUserBuffer * maxChannels * sizeof(short); if( maxChannels > 0 ) { pahsc->pahsc_NativeBuffer = (short *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerBuffer); /* MEM */ if( pahsc->pahsc_NativeBuffer == NULL ) { result = paInsufficientMemory; goto error; } } else { result = paInvalidChannelCount; goto error; } DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; numBytes = pahsc->pahsc_BytesPerBuffer * past->past_NumUserBuffers; if( numBytes < DSBSIZE_MIN ) { result = paBufferTooSmall; goto error; } if( numBytes > DSBSIZE_MAX ) { result = paBufferTooBig; goto error; } pahsc->pahsc_FramesPerDSBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers; { int msecLatency = (int) ((pahsc->pahsc_FramesPerDSBuffer * 1000) / past->past_SampleRate); PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", pahsc->pahsc_FramesPerDSBuffer, msecLatency )); } /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID >= 0) && (past->past_NumOutputChannels > 0) ) { DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); /* If this fails, then try each output device until we find one that works. */ if( hr != DS_OK ) { int i; ERR_RPT(("Creation of requested Audio Output device '%s' failed.\n", ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) )); for( i=0; i<Pa_CountDevices(); i++ ) { pad = Pa_GetInternalDevice( i ); if( pad->pad_Info.maxOutputChannels >= past->past_NumOutputChannels ) { DBUG(("Try device '%s' instead.\n", pad->pad_Info.name )); hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); if( hr == DS_OK ) { ERR_RPT(("Using device '%s' instead.\n", pad->pad_Info.name )); break; } } } } if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n")); result = paHostError; sPaHostError = hr; goto error; } hr = DSW_InitOutputBuffer( dsw, (unsigned long) (past->past_SampleRate + 0.5), past->past_NumOutputChannels, numBytes ); DBUG(("DSW_InitOutputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { result = paHostError; sPaHostError = hr; goto error; } past->past_FrameCount = pahsc->pahsc_DSoundWrapper.dsw_FramesWritten; }#if SUPPORT_AUDIO_CAPTURE /* ------------------ INPUT */ if( (past->past_InputDeviceID >= 0) && (past->past_NumInputChannels > 0) ) { pad = Pa_GetInternalDevice( past->past_InputDeviceID ); hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); /* If this fails, then try each input device until we find one that works. */ if( hr != DS_OK )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -