📄 pa_linux_alsa.c
字号:
return paNoError; /* Skip further checking */
}
assert( deviceInfo );
assert( parameters->hostApiSpecificStreamInfo == NULL );
maxChans = (StreamDirection_In == mode ? deviceInfo->commonDeviceInfo.maxInputChannels :
deviceInfo->commonDeviceInfo.maxOutputChannels);
PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );
error:
return result;
}
/* Given an open stream, what sample formats are available? */
static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )
{
PaSampleFormat available = 0;
snd_pcm_hw_params_t *hwParams;
snd_pcm_hw_params_alloca( &hwParams );
snd_pcm_hw_params_any( pcm, hwParams );
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
available |= paFloat32;
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
available |= paInt32;
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0)
available |= paInt24;
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
available |= paInt16;
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
available |= paUInt8;
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
available |= paInt8;
return available;
}
static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat )
{
switch( paFormat )
{
case paFloat32:
return SND_PCM_FORMAT_FLOAT;
case paInt16:
return SND_PCM_FORMAT_S16;
case paInt24:
return SND_PCM_FORMAT_S24;
case paInt32:
return SND_PCM_FORMAT_S32;
case paInt8:
return SND_PCM_FORMAT_S8;
case paUInt8:
return SND_PCM_FORMAT_U8;
default:
return SND_PCM_FORMAT_UNKNOWN;
}
}
/** Open an ALSA pcm handle.
*
* The device to be open can be specified in a custom PaAlsaStreamInfo struct, or it will be a device number. In case of a
* device number, it maybe specified through an env variable (PA_ALSA_PLUGHW) that we should open the corresponding plugin
* device.
*/
static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection
streamDir, snd_pcm_t **pcm )
{
PaError result = paNoError;
int ret;
const char *deviceName = alloca( 50 );
const PaAlsaDeviceInfo *deviceInfo = NULL;
PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;
if( !streamInfo )
{
int usePlug = 0;
deviceInfo = GetDeviceInfo( hostApi, params->device );
/* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */
if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) )
usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) );
if( usePlug )
snprintf( (char *) deviceName, 50, "plug%s", deviceInfo->alsaName );
else
deviceName = deviceInfo->alsaName;
}
else
deviceName = streamInfo->deviceString;
if( (ret = snd_pcm_open( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK )) < 0 )
{
*pcm = NULL; /* Not to be closed */
ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paBadIODeviceCombination );
}
ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
end:
return result;
error:
goto end;
}
static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,
double sampleRate, StreamDirection streamDir )
{
PaError result = paNoError;
snd_pcm_t *pcm = NULL;
PaSampleFormat availableFormats;
/* We are able to adapt to a number of channels less than what the device supports */
unsigned int numHostChannels;
PaSampleFormat hostFormat;
snd_pcm_hw_params_t *hwParams;
snd_pcm_hw_params_alloca( &hwParams );
if( !parameters->hostApiSpecificStreamInfo )
{
const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );
numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?
devInfo->minInputChannels : devInfo->minOutputChannels );
}
else
numHostChannels = parameters->channelCount;
PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );
snd_pcm_hw_params_any( pcm, hwParams );
if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )
{
result = paInvalidSampleRate;
goto error;
}
if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )
{
result = paInvalidChannelCount;
goto error;
}
/* See if we can find a best possible match */
availableFormats = GetAvailableFormats( pcm );
PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );
ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );
ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );
end:
if( pcm )
snd_pcm_close( pcm );
return result;
error:
goto end;
}
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters,
double sampleRate )
{
int inputChannelCount = 0, outputChannelCount = 0;
PaSampleFormat inputSampleFormat, outputSampleFormat;
PaError result = paFormatIsSupported;
if( inputParameters )
{
PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
inputChannelCount = inputParameters->channelCount;
inputSampleFormat = inputParameters->sampleFormat;
}
if( outputParameters )
{
PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
outputChannelCount = outputParameters->channelCount;
outputSampleFormat = outputParameters->sampleFormat;
}
if( inputChannelCount )
{
if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ))
!= paNoError )
goto error;
}
if ( outputChannelCount )
{
if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ))
!= paNoError )
goto error;
}
return paFormatIsSupported;
error:
return result;
}
static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,
const PaStreamParameters *params, StreamDirection streamDir, int callbackMode )
{
PaError result = paNoError;
PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat;
assert( params->channelCount > 0 );
/* Make sure things have an initial value */
memset( self, 0, sizeof (PaAlsaStreamComponent) );
if( NULL == params->hostApiSpecificStreamInfo )
{
const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->commonHostApiRep, params->device );
self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels
: devInfo->minOutputChannels );
}
else
{
/* We're blissfully unaware of the minimum channelCount */
self->numHostChannels = params->channelCount;
}
PA_ENSURE( AlsaOpen( &alsaApi->commonHostApiRep, params, streamDir, &self->pcm ) );
self->nfds = snd_pcm_poll_descriptors_count( self->pcm );
hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );
self->hostSampleFormat = hostSampleFormat;
self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );
self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);
self->numUserChannels = params->channelCount;
self->streamDir = streamDir;
if( !callbackMode && !self->userInterleaved )
{
/* Pre-allocate non-interleaved user provided buffers */
PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),
paInsufficientMemory );
}
error:
return result;
}
static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
{
snd_pcm_close( self->pcm );
if( self->userBuffers )
PaUtil_FreeMemory( self->userBuffers );
}
/** Configure the associated ALSA pcm.
*
*/
static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, const PaStreamParameters *params, unsigned long
framesPerHostBuffer, int primeBuffers, int callbackMode, double *sampleRate, PaTime *returnedLatency )
{
/*
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;
unsigned int numPeriods, minPeriods = 2;
int dir = 0;
snd_pcm_t *pcm = self->pcm;
PaTime latency = params->suggestedLatency;
double sr = *sampleRate;
*returnedLatency = -1.;
snd_pcm_hw_params_alloca( &hwParams );
snd_pcm_sw_params_alloca( &swParams );
self->framesPerBuffer = framesPerHostBuffer;
/* ... fill up the configuration space with all possibile
* combinations of parameters this device will accept */
ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );
if( self->userInterleaved )
{
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 );
/* Flip mode */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -