📄 pa_linux_alsa.c
字号:
ENSURE( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError ); *defaultLowLatency = (double) lowLatency / *defaultSampleRate; *defaultHighLatency = (double) highLatency / *defaultSampleRate;end: snd_pcm_close( pcm ); return result;error: *channels = 0; goto end;}/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ){ PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep; PaAlsaDeviceInfo *deviceInfoArray; int deviceCount = 0; int card_idx; int device_idx; snd_ctl_t *ctl; snd_ctl_card_info_t *card_info; PaError result = paNoError; int blocking = SND_PCM_NONBLOCK; if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) ) blocking = 0; /* These two will be set to the first working input and output device, respectively */ commonApi->info.defaultInputDevice = paNoDevice; commonApi->info.defaultOutputDevice = paNoDevice; /* count the devices by enumerating all the card numbers */ /* snd_card_next() modifies the integer passed to it to be: * the index of the first card if the parameter is -1 * the index of the next card if the parameter is the index of a card * -1 if there are no more cards * * The function itself returns 0 if it succeeded. */ card_idx = -1; while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 ) { ++deviceCount; } /* allocate deviceInfo memory based on the number of devices */ UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( alsaApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ), paInsufficientMemory ); /* allocate all device info structs in a contiguous block */ UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory( alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * deviceCount ), paInsufficientMemory ); /* now loop over the list of devices again, filling in the deviceInfo for each * A: If a device is deemed unavailable (can't get name), its not added to list of devices. */ card_idx = -1; device_idx = 0; snd_ctl_card_info_alloca( &card_info ); while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 ) { PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[device_idx]; PaDeviceInfo *commonDeviceInfo = &deviceInfo->commonDeviceInfo; snd_pcm_t *pcm; char *deviceName; char alsaDeviceName[50]; const char *cardName; /* First of all, get name of card */ snprintf( alsaDeviceName, 50, "hw:%d", card_idx ); if( snd_ctl_open( &ctl, alsaDeviceName, 0 ) < 0 ) continue; /* Unable to open card :( */ snd_ctl_card_info( ctl, card_info ); snd_ctl_close( ctl ); cardName = snd_ctl_card_info_get_name( card_info ); /* Zero fields */ memset( commonDeviceInfo, 0, sizeof (PaDeviceInfo) ); UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, strlen(cardName) + 1 ), paInsufficientMemory ); strcpy( deviceName, cardName ); commonDeviceInfo->name = deviceName; deviceInfo->deviceNumber = card_idx; /* ALSA device number */ commonDeviceInfo->structVersion = 2; commonDeviceInfo->hostApi = alsaApi->hostApiIndex; /* to determine device capabilities, we must open the device and query the * hardware parameter configuration space */ /* Query capture */ if( snd_pcm_open( &pcm, alsaDeviceName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 ) { if( GropeDevice( pcm, &commonDeviceInfo->maxInputChannels, &commonDeviceInfo->defaultLowInputLatency, &commonDeviceInfo->defaultHighInputLatency, &commonDeviceInfo->defaultSampleRate ) != paNoError ) continue; /* Error */ } /* Query playback */ if( snd_pcm_open( &pcm, alsaDeviceName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 ) { if( GropeDevice( pcm, &commonDeviceInfo->maxOutputChannels, &commonDeviceInfo->defaultLowOutputLatency, &commonDeviceInfo->defaultHighOutputLatency, &commonDeviceInfo->defaultSampleRate ) != paNoError ) continue; /* Error */ } /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object. * Should now be safe to add device info, unless the device supports neither capture nor playback */ if( commonDeviceInfo->maxInputChannels || commonDeviceInfo->maxOutputChannels ) { if( commonApi->info.defaultInputDevice == paNoDevice ) commonApi->info.defaultInputDevice = device_idx; if( commonApi->info.defaultOutputDevice == paNoDevice ) commonApi->info.defaultOutputDevice = device_idx; commonApi->deviceInfos[ device_idx++ ] = (PaDeviceInfo *) deviceInfo; } } commonApi->info.deviceCount = device_idx; /* Number of successfully queried devices */end: return result;error: goto end; /* No particular action */}static void Terminate( struct PaUtilHostApiRepresentation *hostApi ){ PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; assert( hostApi ); if( alsaHostApi->allocations ) { PaUtil_FreeAllAllocations( alsaHostApi->allocations ); PaUtil_DestroyAllocationGroup( alsaHostApi->allocations ); } PaUtil_FreeMemory( alsaHostApi ); pthread_mutex_destroy( &gmtx );}/* Check against known device capabilities */static PaError ValidateParameters( const PaStreamParameters *parameters, const PaAlsaDeviceInfo *deviceInfo, StreamIO io, const PaAlsaStreamInfo *streamInfo ){ int maxChans; assert( parameters ); if( streamInfo ) { if( streamInfo->size != sizeof (PaAlsaStreamInfo) || streamInfo->version != 1 ) return paIncompatibleHostApiSpecificStreamInfo; if( parameters->device != paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; } if( parameters->device == paUseHostApiSpecificDeviceSpecification ) { if( streamInfo ) return paNoError; /* Skip further checking */ return paInvalidDevice; } maxChans = (io == streamIn ? deviceInfo->commonDeviceInfo.maxInputChannels : deviceInfo->commonDeviceInfo.maxOutputChannels); if( parameters->channelCount > maxChans ) { return paInvalidChannelCount; } return paNoError;}/* 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; }}/* \brief 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(snd_pcm_t **pcm, const PaAlsaDeviceInfo *deviceInfo, const PaAlsaStreamInfo *streamInfo, snd_pcm_stream_t streamType ){ PaError result = paNoError; int ret; char *deviceName = alloca( 50 ); if( !streamInfo ) { int usePlug = 0; char *prefix; if( getenv( "PA_ALSA_PLUGHW" ) ) usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) ); prefix = usePlug ? "plughw" : "hw"; snprintf( deviceName, 50, "%s:%d", prefix, deviceInfo->deviceNumber ); } else deviceName = (char *) streamInfo->deviceString; if( (ret = snd_pcm_open( pcm, deviceName, streamType, 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 PaStreamParameters *parameters, const PaAlsaDeviceInfo *deviceInfo, const PaAlsaStreamInfo *streamInfo, double sampleRate, snd_pcm_stream_t streamType ){ PaError result = paNoError; snd_pcm_t *pcm = NULL; PaSampleFormat availableFormats; PaSampleFormat paFormat; snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca( ¶ms ); PA_ENSURE( AlsaOpen( &pcm, deviceInfo, streamInfo, streamType ) ); snd_pcm_hw_params_any( pcm, params ); ENSURE( SetApproximateSampleRate( pcm, params, sampleRate ), paInvalidSampleRate ); ENSURE( snd_pcm_hw_params_set_channels( pcm, params, parameters->channelCount ), paInvalidChannelCount ); /* See if we can find a best possible match */ availableFormats = GetAvailableFormats( pcm ); PA_ENSURE( paFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );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; const PaAlsaDeviceInfo *inputDeviceInfo = NULL, *outputDeviceInfo = NULL; const PaAlsaStreamInfo *inputStreamInfo = NULL, *outputStreamInfo = NULL; 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 ) ); inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; } if( outputParameters )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -