📄 pa_linux_alsa.c
字号:
{ if( outputParameters->device != paUseHostApiSpecificDeviceSpecification ) { assert( outputParameters->device < hostApi->info.deviceCount ); outputDeviceInfo = (PaAlsaDeviceInfo *)hostApi->deviceInfos[ outputParameters->device ]; } else outputStreamInfo = outputParameters->hostApiSpecificStreamInfo; PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, streamOut, outputStreamInfo ) ); outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; } /* IMPLEMENT ME: - if a full duplex stream is requested, check that the combination of input and output parameters is supported if necessary - check that the device supports sampleRate Because the buffer adapter handles conversion between all standard sample formats, the following checks are only required if paCustomFormat is implemented, or under some other unusual conditions. - 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( inputChannelCount ) { PA_ENSURE( TestParameters( inputParameters, inputDeviceInfo, inputStreamInfo, sampleRate, SND_PCM_STREAM_CAPTURE ) ); } if ( outputChannelCount ) { PA_ENSURE( TestParameters( outputParameters, outputDeviceInfo, outputStreamInfo, sampleRate, SND_PCM_STREAM_PLAYBACK ) ); } return paFormatIsSupported;error: return result;}/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */static PaError ConfigureStream( snd_pcm_t *pcm, int channels, int *interleaved, double *sampleRate, PaSampleFormat paFormat, unsigned long framesPerBuffer, snd_pcm_uframes_t *bufferSize, PaTime *latency, int primeBuffers, int callbackMode ){ /* int numPeriods; if( getenv("PA_NUMPERIODS") != NULL ) numPeriods = atoi( getenv("PA_NUMPERIODS") ); else numPeriods = ( (*latency * sampleRate) / *framesPerBuffer ) + 1; PA_DEBUG(( "latency: %f, rate: %f, framesPerBuffer: %d\n", *latency, sampleRate, *framesPerBuffer )); if( numPeriods <= 1 ) numPeriods = 2; */ /* configuration consists of setting all of ALSA's parameters. * These parameters come in two flavors: hardware parameters * and software paramters. Hardware parameters will affect * the way the device is initialized, software parameters * affect the way ALSA interacts with me, the user-level client. */ snd_pcm_hw_params_t *hwParams; snd_pcm_sw_params_t *swParams; PaError result = paNoError; snd_pcm_access_t accessMode, alternateAccessMode; snd_pcm_format_t alsaFormat; unsigned int numPeriods; snd_pcm_hw_params_alloca( &hwParams ); snd_pcm_sw_params_alloca( &swParams ); /* ... fill up the configuration space with all possibile * combinations of parameters this device will accept */ ENSURE( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); if( *interleaved ) { accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; } else { accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED; alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED; } /* If requested access mode fails, try alternate mode */ if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) { ENSURE( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ), paUnanticipatedHostError ); *interleaved = !(*interleaved); /* Flip mode */ } /* set the format based on what the user selected */ alsaFormat = Pa2AlsaFormat( paFormat ); assert( alsaFormat != SND_PCM_FORMAT_UNKNOWN ); ENSURE( snd_pcm_hw_params_set_format( pcm, hwParams, alsaFormat ), paUnanticipatedHostError ); /* ... set the sample rate */ ENSURE( SetApproximateSampleRate( pcm, hwParams, *sampleRate ), paInvalidSampleRate ); ENSURE( GetExactSampleRate( hwParams, sampleRate ), paUnanticipatedHostError ); /* ... set the number of channels */ ENSURE( snd_pcm_hw_params_set_channels( pcm, hwParams, channels ), paInvalidChannelCount ); /* Set buffer size */ ENSURE( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError ); ENSURE( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError ); ENSURE( snd_pcm_hw_params_set_period_size( pcm, hwParams, framesPerBuffer, 0 ), paUnanticipatedHostError ); /* Find an acceptable number of periods */ numPeriods = (*latency * *sampleRate) / framesPerBuffer + 1; numPeriods = MAX( numPeriods, 2 ); /* Should be at least 2 periods I think? */ ENSURE( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, NULL ), paUnanticipatedHostError ); /* PA_DEBUG(( "numperiods: %d\n", numPeriods )); if( snd_pcm_hw_params_set_periods ( pcm, hwParams, numPeriods, 0 ) < 0 ) { int i; for( i = numPeriods; i >= 2; i-- ) { if( snd_pcm_hw_params_set_periods( pcm, hwParams, i, 0 ) >= 0 ) { PA_DEBUG(( "settled on %d periods\n", i )); break; } } } */ /* Set the parameters! */ ENSURE( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError ); ENSURE( snd_pcm_hw_params_get_buffer_size( hwParams, bufferSize ), paUnanticipatedHostError ); /* Latency in seconds, one period is not counted as latency */ *latency = (numPeriods - 1) * framesPerBuffer / *sampleRate; /* Now software parameters... */ ENSURE( snd_pcm_sw_params_current( pcm, swParams ), paUnanticipatedHostError ); ENSURE( snd_pcm_sw_params_set_start_threshold( pcm, swParams, framesPerBuffer ), paUnanticipatedHostError ); ENSURE( snd_pcm_sw_params_set_stop_threshold( pcm, swParams, *bufferSize ), paUnanticipatedHostError ); /* Silence buffer in the case of underrun */ if( !primeBuffers ) { ENSURE( snd_pcm_sw_params_set_silence_threshold( pcm, swParams, 0 ), paUnanticipatedHostError ); ENSURE( snd_pcm_sw_params_set_silence_size( pcm, swParams, INT_MAX ), paUnanticipatedHostError ); } ENSURE( snd_pcm_sw_params_set_avail_min( pcm, swParams, framesPerBuffer ), paUnanticipatedHostError ); ENSURE( snd_pcm_sw_params_set_xfer_align( pcm, swParams, 1 ), paUnanticipatedHostError ); ENSURE( snd_pcm_sw_params_set_tstamp_mode( pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError ); /* Set the parameters! */ ENSURE( snd_pcm_sw_params( pcm, swParams ), paUnanticipatedHostError );end: return result;error: goto end; /* No particular action */}static void InitializeStream( PaAlsaStream *stream, int callback, PaStreamFlags streamFlags ){ assert( stream ); stream->pcm_capture = NULL; stream->pcm_playback = NULL; stream->callback_finished = 0; stream->callback_mode = callback; stream->capture_nfds = 0; stream->playback_nfds = 0; stream->pfds = NULL; stream->pollTimeout = 0; stream->pcmsSynced = 0; stream->callbackAbort = 0; stream->isActive = 0; stream->startThreshold = 0; pthread_mutex_init( &stream->stateMtx, NULL ); pthread_mutex_init( &stream->startMtx, NULL ); pthread_cond_init( &stream->startCond, NULL ); stream->neverDropInput = 0; stream->underrun = stream->overrun = 0.0;}static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *callback, void *userData ){ PaError result = paNoError; PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; const PaAlsaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0; PaAlsaStream *stream = 0; PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0; int numInputChannels = 0, numOutputChannels = 0; PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; unsigned long framesPerHostBuffer = framesPerBuffer; PaAlsaStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL; PaTime inputLatency, outputLatency; if( inputParameters ) { if( inputParameters->device != paUseHostApiSpecificDeviceSpecification ) { assert( inputParameters->device < hostApi->info.deviceCount ); inputDeviceInfo = (PaAlsaDeviceInfo*)hostApi->deviceInfos[ inputParameters->device ]; } else inputStreamInfo = inputParameters->hostApiSpecificStreamInfo; PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, streamIn, inputStreamInfo ) ); numInputChannels = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; } if( outputParameters ) { if( outputParameters->device != paUseHostApiSpecificDeviceSpecification ) { assert( outputParameters->device < hostApi->info.deviceCount ); outputDeviceInfo = (PaAlsaDeviceInfo*)hostApi->deviceInfos[ outputParameters->device ]; } else outputStreamInfo = outputParameters->hostApiSpecificStreamInfo; PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, streamOut, outputStreamInfo ) ); /* outputDeviceInfo = (PaAlsaDeviceInfo*)hostApi->deviceInfos[ outputParameters->device ]; PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo->commonDeviceInfo.maxOutputChannels ) ); */ numOutputChannels = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; } /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ /* allocate and do basic initialization of the stream structure */ UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory ); InitializeStream( stream, (int) callback, streamFlags ); /* Initialize structure */ if( callback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &alsaHostApi->callbackStreamInterface, callback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &alsaHostApi->blockingStreamInterface, callback, userData ); } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); /* open the devices now, so we can obtain info about the available formats */ if( numInputChannels > 0 ) { PA_ENSURE( AlsaOpen( &stream->pcm_capture, inputDeviceInfo, inputStreamInfo, SND_PCM_STREAM_CAPTURE ) ); stream->capture_nfds = snd_pcm_poll_descriptors_count( stream->pcm_capture ); hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( stream->pcm_capture ), inputSampleFormat ); } if( numOutputChannels > 0 ) { PA_ENSURE( AlsaOpen( &stream->pcm_playback, outputDeviceInfo, outputStreamInfo, SND_PCM_STREAM_PLAYBACK ) ); stream->playback_nfds = snd_pcm_poll_descriptors_count( stream->pcm_playback ); hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( stream->pcm_playback ), outputSampleFormat ); stream->playbackNativeFormat = Pa2AlsaFormat( hostOutputSampleFormat ); } /* If the number of frames per buffer is unspecified, we have to come up with * one. This is both a blessing and a curse: a blessing because we can optimize * the number to best meet the requirements, but a curse because that's really * hard to do well. For this reason we also support an interface where the user * specifies these by setting environment variables. */ if( framesPerBuffer == paFramesPerBufferUnspecified ) { if( getenv("PA_ALSA_PERIODSIZE") != NULL ) framesPerHostBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") ); else { /* We need to determine how many frames per host buffer to use. Our * goals are to provide the best possible performance, but also to * most closely honor the requested latency settings. Therefore this * decision is based on: * * - the period sizes that playback and/or capture support. The * host buffer size has to be one of these. * - the number of periods that playback and/or capture support. * * We want to make period_size*(num_periods-1) to be as close as possible * to latency*rate for both playback and capture. * * This is one of those blocks of code that will just take a lot of * refinement to be any good. */ if( stream->pcm_capture && stream->pcm_playback ) { snd_pcm_uframes_t desiredLatency, e; snd_pcm_uframes_t minPeriodSize, minPlayback, minCapture, maxPeriodSize, maxPlayback, maxCapture, optimalPeriodSize, periodSize; int dir; snd_pcm_t *pcm; snd_pcm_hw_params_t *hwParamsPlayback, *hwParamsCapture;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -