pa_linux_alsa.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 1,692 行 · 第 1/5 页
C
1,692 行
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 */ self->hostInterleaved = !self->userInterleaved; } ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate ); ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError ); /* reject if there's no sample rate within 1% of the one requested */ if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 ) { PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr )); PA_ENSURE( paInvalidSampleRate ); } ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount ); /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */ dir = 0; ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError ); dir = 0; ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &self->framesPerBuffer, &dir ), paUnanticipatedHostError ); /* Find an acceptable number of periods */ numPeriods = (latency * sr) / self->framesPerBuffer + 1; dir = 0; ENSURE_( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, &dir ), paUnanticipatedHostError ); /* Minimum of periods should already be 2 */ PA_UNLESS( numPeriods >= 2, paInternalError ); /* Set the parameters! */ ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError ); ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError ); /* Latency in seconds, one period is not counted as latency */ latency = (numPeriods - 1) * self->framesPerBuffer / sr;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?