pa_linux_alsa.c
来自「基于sip协议的网络电话源码」· C语言 代码 · 共 1,692 行 · 第 1/5 页
C
1,692 行
error: goto end;}/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate * wether input/output is available) */static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo ){ deviceInfo->structVersion = -1; deviceInfo->name = NULL; deviceInfo->hostApi = -1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->defaultLowInputLatency = -1.; deviceInfo->defaultLowOutputLatency = -1.; deviceInfo->defaultHighInputLatency = -1.; deviceInfo->defaultHighOutputLatency = -1.; deviceInfo->defaultSampleRate = -1.;}/* Helper struct */typedef struct{ char *alsaName; char *name; int isPlug; int hasPlayback; int hasCapture;} DeviceNames;static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi, char **dst, const char *src){ PaError result = paNoError; int len = strlen( src ) + 1; /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */ PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), paInsufficientMemory ); strncpy( *dst, src, len );error: return result;}/* Disregard standard plugins * XXX: Might want to make the "default" plugin available, if we can make it work */static int IgnorePlugin( const char *pluginId ){#define numIgnored 10 static const char *ignoredPlugins[numIgnored] = {"hw", "plughw", "plug", "default", "dsnoop", "dmix", "tee", "file", "null", "shm"}; int i; for( i = 0; i < numIgnored; ++i ) { if( !strcmp( pluginId, ignoredPlugins[i] ) ) { return 1; } } return 0;}/* 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 cardIdx = -1, devIdx = 0; snd_ctl_card_info_t *cardInfo; PaError result = paNoError; size_t numDeviceNames = 0, maxDeviceNames = 1, i; DeviceNames *deviceNames = NULL; snd_config_t *topNode = NULL; snd_pcm_info_t *pcmInfo; int res; int blocking = SND_PCM_NONBLOCK; char alsaCardName[50]; 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. */ cardIdx = -1; snd_ctl_card_info_alloca( &cardInfo ); snd_pcm_info_alloca( &pcmInfo ); while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) { char *cardName; int devIdx = -1; snd_ctl_t *ctl; char buf[50]; snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx ); /* Acquire name of card */ if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 ) continue; /* Unable to open card :( */ snd_ctl_card_info( ctl, cardInfo ); PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) ); while( snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 ) { char *alsaDeviceName, *deviceName; size_t len; int hasPlayback = 0, hasCapture = 0; snprintf( buf, sizeof (buf), "%s:%d,%d", "hw", cardIdx, devIdx ); /* Obtain info about this particular device */ snd_pcm_info_set_device( pcmInfo, devIdx ); snd_pcm_info_set_subdevice( pcmInfo, 0 ); snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE ); if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) hasCapture = 1; snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK ); if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 ) hasPlayback = 1; if( !hasPlayback && !hasCapture ) { continue; /* Error */ } /* The length of the string written by snprintf plus terminating 0 */ len = snprintf( NULL, 0, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ) + 1; PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), paInsufficientMemory ); snprintf( deviceName, len, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ); ++numDeviceNames; if( !deviceNames || numDeviceNames > maxDeviceNames ) { maxDeviceNames *= 2; PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ), paInsufficientMemory ); } PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) ); deviceNames[ numDeviceNames - 1 ].alsaName = alsaDeviceName; deviceNames[ numDeviceNames - 1 ].name = deviceName; deviceNames[ numDeviceNames - 1 ].isPlug = 0; deviceNames[ numDeviceNames - 1 ].hasPlayback = hasPlayback; deviceNames[ numDeviceNames - 1 ].hasCapture = hasCapture; } snd_ctl_close( ctl ); } /* Iterate over plugin devices */ snd_config_update(); if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 ) { snd_config_iterator_t i, next; snd_config_for_each( i, next, topNode ) { const char *tpStr = NULL, *idStr = NULL; char *alsaDeviceName, *deviceName; snd_config_t *n = snd_config_iterator_entry( i ), *tp = NULL; if( snd_config_get_type( n ) != SND_CONFIG_TYPE_COMPOUND ) continue; ENSURE_( snd_config_search( n, "type", &tp ), paUnanticipatedHostError ); ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError ); ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError ); if( IgnorePlugin( idStr ) ) { PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr )); continue; } PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr )); PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, strlen(idStr) + 6 ), paInsufficientMemory ); strcpy( alsaDeviceName, idStr ); PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations, strlen(idStr) + 1 ), paInsufficientMemory ); strcpy( deviceName, idStr ); ++numDeviceNames; if( !deviceNames || numDeviceNames > maxDeviceNames ) { maxDeviceNames *= 2; PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ), paInsufficientMemory ); } deviceNames[numDeviceNames - 1].alsaName = alsaDeviceName; deviceNames[numDeviceNames - 1].name = deviceName; deviceNames[numDeviceNames - 1].isPlug = 1; deviceNames[numDeviceNames - 1].hasPlayback = 1; deviceNames[numDeviceNames - 1].hasCapture = 1; } } else PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) )); /* allocate deviceInfo memory based on the number of devices */ PA_UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory ); /* allocate all device info structs in a contiguous block */ PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory( alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory ); /* Loop over list of cards, filling in info, if a device is deemed unavailable (can't get name), * it's ignored. */ /* while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) */ for( i = 0, devIdx = 0; i < numDeviceNames; ++i ) { snd_pcm_t *pcm; PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx]; PaDeviceInfo *commonDeviceInfo = &deviceInfo->commonDeviceInfo; /* Zero fields */ InitializeDeviceInfo( commonDeviceInfo ); /* to determine device capabilities, we must open the device and query the * hardware parameter configuration space */ /* Query capture */ if( deviceNames[i].hasCapture && snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 ) { if( GropeDevice( pcm, &deviceInfo->minInputChannels, &commonDeviceInfo->maxInputChannels, &commonDeviceInfo->defaultLowInputLatency, &commonDeviceInfo->defaultHighInputLatency, &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError ) continue; /* Error */ } /* Query playback */ if( deviceNames[i].hasPlayback && snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 ) { if( GropeDevice( pcm, &deviceInfo->minOutputChannels, &commonDeviceInfo->maxOutputChannels, &commonDeviceInfo->defaultLowOutputLatency, &commonDeviceInfo->defaultHighOutputLatency, &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError ) continue; /* Error */ } commonDeviceInfo->structVersion = 2; commonDeviceInfo->hostApi = alsaApi->hostApiIndex; commonDeviceInfo->name = deviceNames[i].name; deviceInfo->alsaName = deviceNames[i].alsaName; deviceInfo->isPlug = deviceNames[i].isPlug; /* 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 > 0 || commonDeviceInfo->maxOutputChannels > 0 ) { if( commonApi->info.defaultInputDevice == paNoDevice && commonDeviceInfo->maxInputChannels > 0 ) commonApi->info.defaultInputDevice = devIdx; if( commonApi->info.defaultOutputDevice == paNoDevice && commonDeviceInfo->maxOutputChannels > 0 ) commonApi->info.defaultOutputDevice = devIdx; commonApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo; } } free( deviceNames ); commonApi->info.deviceCount = devIdx; /* Number of successfully queried devices */end: return result;error: goto end; /* No particular action */}/* Check against known device capabilities */static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode ){ PaError result = paNoError; int maxChans; const PaAlsaDeviceInfo *deviceInfo = NULL; assert( parameters ); if( parameters->device != paUseHostApiSpecificDeviceSpecification ) { assert( parameters->device < hostApi->info.deviceCount ); PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination ); deviceInfo = GetDeviceInfo( hostApi, parameters->device ); } else { const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo; PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice ); PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1, paIncompatibleHostApiSpecificStreamInfo ); 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?