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 + -
显示快捷键?