⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pa_linux_alsa.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
     *         config time.
     */
    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError );

    /* Have to reset hwParams, to set new buffer size */
    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); 
    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError );

    *minChannels = (int)minChans;
    *maxChannels = (int)maxChans;
    *defaultSampleRate = defaultSr;
    *defaultLowLatency = (double) lowLatency / *defaultSampleRate;
    *defaultHighLatency = (double) highLatency / *defaultSampleRate;

end:
    snd_pcm_close( pcm );
    return result;

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 );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -