📄 pa_linux_asihpi.c
字号:
}error: return result;}/** Display stream component information for debugging purposes. @param streamComp Pointer to stream component (input or output) to query @param stream Pointer to stream struct which contains the component above */static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStream *stream ){ PaAsiHpiStreamInfo streamInfo; assert( streamComp ); assert( stream ); /* Name of soundcard/device used by component */ PA_DEBUG(( "device: %s\n", streamComp->hpiDevice->baseDeviceInfo.name )); /* Unfortunately some overlap between input and output here */ if( streamComp->hpiDevice->streamIsOutput ) { /* Settings on the user side (as experienced by user callback) */ PA_DEBUG(( "user: %d-bit, %d ", 8*stream->bufferProcessor.bytesPerUserOutputSample, stream->bufferProcessor.outputChannelCount)); if( stream->bufferProcessor.userOutputIsInterleaved ) { PA_DEBUG(( "interleaved channels, " )); } else { PA_DEBUG(( "non-interleaved channels, " )); } PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", stream->bufferProcessor.framesPerUserBuffer, 1000*stream->baseStreamRep.streamInfo.outputLatency )); /* Settings on the host side (internal to PortAudio host API) */ PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", 8*stream->bufferProcessor.bytesPerHostOutputSample, stream->bufferProcessor.outputChannelCount, stream->bufferProcessor.framesPerHostBuffer )); } else { /* Settings on the user side (as experienced by user callback) */ PA_DEBUG(( "user: %d-bit, %d ", 8*stream->bufferProcessor.bytesPerUserInputSample, stream->bufferProcessor.inputChannelCount)); if( stream->bufferProcessor.userInputIsInterleaved ) { PA_DEBUG(( "interleaved channels, " )); } else { PA_DEBUG(( "non-interleaved channels, " )); } PA_DEBUG(( "%d frames/buffer, latency = %5.1f ms\n", stream->bufferProcessor.framesPerUserBuffer, 1000*stream->baseStreamRep.streamInfo.inputLatency )); /* Settings on the host side (internal to PortAudio host API) */ PA_DEBUG(( "host: %d-bit, %d interleaved channels, %d frames/buffer ", 8*stream->bufferProcessor.bytesPerHostInputSample, stream->bufferProcessor.inputChannelCount, stream->bufferProcessor.framesPerHostBuffer )); } switch( stream->bufferProcessor.hostBufferSizeMode ) { case paUtilFixedHostBufferSize: PA_DEBUG(( "[fixed] " )); break; case paUtilBoundedHostBufferSize: PA_DEBUG(( "[bounded] " )); break; case paUtilUnknownHostBufferSize: PA_DEBUG(( "[unknown] " )); break; case paUtilVariableHostBufferSizePartialUsageAllowed: PA_DEBUG(( "[variable] " )); break; } PA_DEBUG(( "(%d max)\n", streamComp->tempBufferSize / streamComp->bytesPerFrame )); /* HPI hardware settings */ PA_DEBUG(( "HPI: adapter %d stream %d, %d-bit, %d-channel, %d Hz\n", streamComp->hpiDevice->adapterIndex, streamComp->hpiDevice->streamIndex, 8 * streamComp->bytesPerFrame / streamComp->hpiFormat.wChannels, streamComp->hpiFormat.wChannels, streamComp->hpiFormat.dwSampleRate )); /* Stream state and buffer levels */ PA_DEBUG(( "HPI: " )); PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ); switch( streamInfo.state ) { case HPI_STATE_STOPPED: PA_DEBUG(( "[STOPPED] " )); break; case HPI_STATE_PLAYING: PA_DEBUG(( "[PLAYING] " )); break; case HPI_STATE_RECORDING: PA_DEBUG(( "[RECORDING] " )); break; case HPI_STATE_DRAINED: PA_DEBUG(( "[DRAINED] " )); break; default: PA_DEBUG(( "[unknown state] " )); break; } if( streamComp->hostBufferSize ) { PA_DEBUG(( "host = %d/%d B, ", streamInfo.dataSize, streamComp->hostBufferSize )); PA_DEBUG(( "hw = %d/%d (%d) B, ", streamInfo.auxDataSize, streamComp->hardwareBufferSize, streamComp->outputBufferCap )); } else { PA_DEBUG(( "hw = %d/%d B, ", streamInfo.dataSize, streamComp->hardwareBufferSize )); } PA_DEBUG(( "count = %d", streamInfo.frameCounter )); if( streamInfo.overflow ) { PA_DEBUG(( " [overflow]" )); } else if( streamInfo.underflow ) { PA_DEBUG(( " [underflow]" )); } PA_DEBUG(( "\n" ));}/** Display stream information for debugging purposes. @param stream Pointer to stream to query */static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream ){ assert( stream ); PA_DEBUG(( "\n------------------------- STREAM INFO FOR %p ---------------------------\n", stream )); /* General stream info (input+output) */ if( stream->baseStreamRep.streamCallback ) { PA_DEBUG(( "[callback] " )); } else { PA_DEBUG(( "[blocking] " )); } PA_DEBUG(( "sr=%d Hz, poll=%d ms, max %d frames/buf ", (int)stream->baseStreamRep.streamInfo.sampleRate, stream->pollingInterval, stream->maxFramesPerHostBuffer )); switch( stream->state ) { case paAsiHpiStoppedState: PA_DEBUG(( "[stopped]\n" )); break; case paAsiHpiActiveState: PA_DEBUG(( "[active]\n" )); break; case paAsiHpiCallbackFinishedState: PA_DEBUG(( "[cb fin]\n" )); break; default: PA_DEBUG(( "[unknown state]\n" )); break; } if( stream->callbackMode ) { PA_DEBUG(( "cb info: thread=%p, cbAbort=%d, cbFinished=%d\n", stream->thread.thread, stream->callbackAbort, stream->callbackFinished )); } PA_DEBUG(( "----------------------------------- Input ------------------------------------\n" )); if( stream->input ) { PaAsiHpi_StreamComponentDump( stream->input, stream ); } else { PA_DEBUG(( "*none*\n" )); } PA_DEBUG(( "----------------------------------- Output ------------------------------------\n" )); if( stream->output ) { PaAsiHpi_StreamComponentDump( stream->output, stream ); } else { PA_DEBUG(( "*none*\n" )); } PA_DEBUG(( "-------------------------------------------------------------------------------\n\n" ));}/** Determine buffer sizes and allocate appropriate stream buffers. This attempts to allocate a BBM (host) buffer for the HPI stream component (either input or output, as both have similar buffer needs). Not all AudioScience adapters support BBM, in which case the hardware buffer has to suffice. The size of the HPI host buffer is chosen as a multiple of framesPerPaHostBuffer, and also influenced by the suggested latency and the estimated minimum polling interval. The HPI host and hardware buffer sizes are stored, and an appropriate cap for the hardware buffer is also calculated. Finally, the temporary stream buffer which serves as the PortAudio host buffer for this implementation is allocated. This buffer contains an integer number of user buffers, to simplify buffer adaption in the buffer processor. The function returns paBufferTooBig if the HPI interface cannot allocate an HPI host buffer of the desired size. @param streamComp Pointer to stream component struct @param pollingInterval Polling interval for stream, in milliseconds @param framesPerPaHostBuffer Size of PortAudio host buffer, in frames @param suggestedLatency Suggested latency for stream component, in seconds @return PortAudio error code (possibly paBufferTooBig or paInsufficientMemory) */static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, unsigned long framesPerPaHostBuffer, PaTime suggestedLatency ){ PaError result = paNoError; PaAsiHpiStreamInfo streamInfo; unsigned long hpiBufferSize = 0, paHostBufferSize = 0; assert( streamComp ); assert( streamComp->hpiDevice ); /* Obtain size of hardware buffer of HPI stream, since we will be activating BBM shortly and afterwards the buffer size will refer to the BBM (host-side) buffer. This is necessary to enable reliable detection of xruns. */ PA_ENSURE_( PaAsiHpi_GetStreamInfo( streamComp, &streamInfo ) ); streamComp->hardwareBufferSize = streamInfo.bufferSize; hpiBufferSize = streamInfo.bufferSize; /* Check if BBM (background bus mastering) is to be enabled */ if( PA_ASIHPI_USE_BBM_ ) { HW32 bbmBufferSize = 0, preLatencyBufferSize = 0; HW16 hpiError = 0; PaTime pollingOverhead; /* Check overhead of Pa_Sleep() call (minimum sleep duration in ms -> OS dependent) */ pollingOverhead = PaUtil_GetTime(); Pa_Sleep( 0 ); pollingOverhead = 1000*(PaUtil_GetTime() - pollingOverhead); PA_DEBUG(( "polling overhead = %f ms (length of 0-second sleep)\n", pollingOverhead )); /* Obtain minimum recommended size for host buffer (in bytes) */ PA_ASIHPI_UNLESS_( HPI_StreamEstimateBufferSize( &streamComp->hpiFormat, pollingInterval + (HW32)ceil( pollingOverhead ), &bbmBufferSize ), paUnanticipatedHostError ); /* BBM places more stringent requirements on buffer size (see description */ /* of HPI_StreamEstimateBufferSize in HPI API document) */ bbmBufferSize *= 3; /* Make sure the BBM buffer contains multiple PA host buffers */ if( bbmBufferSize < 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer ) bbmBufferSize = 3 * streamComp->bytesPerFrame * framesPerPaHostBuffer; /* Try to honor latency suggested by user by growing buffer (no decrease possible) */ if( suggestedLatency > 0.0 ) { PaTime bufferDuration = ((PaTime)bbmBufferSize) / streamComp->bytesPerFrame / streamComp->hpiFormat.dwSampleRate; /* Don't decrease buffer */ if( bufferDuration < suggestedLatency ) { /* Save old buffer size, to be retried if new size proves too big */ preLatencyBufferSize = bbmBufferSize; bbmBufferSize = (HW32)ceil( suggestedLatency * streamComp->bytesPerFrame * streamComp->hpiFormat.dwSampleRate ); } } /* Choose closest memory block boundary (HPI API document states that "a buffer size of Nx4096 - 20 makes the best use of memory" (under the entry for HPI_StreamEstimateBufferSize)) */ bbmBufferSize = ((HW32)ceil((bbmBufferSize + 20)/4096.0))*4096 - 20; streamComp->hostBufferSize = bbmBufferSize; /* Allocate BBM host buffer (this enables bus mastering transfers in background) */ if( streamComp->hpiDevice->streamIsOutput ) hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, streamComp->hpiStream, bbmBufferSize ); else hpiError = HPI_InStreamHostBufferAllocate( streamComp->hpiDevice->subSys, streamComp->hpiStream, bbmBufferSize ); if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); /* Indicate that BBM is disabled */ streamComp->hostBufferSize = 0; /* Retry with smaller buffer size (transfers will still work, but not via BBM) */ if( hpiError == HPI_ERROR_INVALID_DATASIZE ) { /* Retry BBM allocation with smaller size if requested latency proved too big */ if( preLatencyBufferSize > 0 ) { PA_DEBUG(( "Retrying BBM allocation with smaller size (%d vs. %d bytes)\n", preLatencyBufferSize, bbmBufferSize )); bbmBufferSize = preLatencyBufferSize; if( streamComp->hpiDevice->streamIsOutput ) hpiError = HPI_OutStreamHostBufferAllocate( streamComp->hpiDevice->subSys, streamComp->hpiStream, bbmBufferSize ); else hpiEr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -