pa_linux_alsa.c

来自「mediastreamer2是开源的网络传输媒体流的库」· C语言 代码 · 共 1,651 行 · 第 1/5 页

C
1,651
字号
    snd_pcm_hw_params_any( pcm, hwParams );    *canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED ) >= 0 ||            snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED ) >= 0;    if( defaultSr >= 0 )    {        /* Could be that the device opened in one mode supports samplerates that the other mode wont have,         * so try again .. */        if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 )        {            defaultSr = -1.;            PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ ));        }    }    if( defaultSr < 0. )           /* Default sample rate not set */    {        unsigned int sampleRate = 44100;        /* Will contain approximate rate returned by alsa-lib */        if( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0)        {            result = paUnanticipatedHostError;            goto error;        }        ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );    }        ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );    ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );    assert( maxChans <= INT_MAX );    assert( maxChans > 0 );    /* Weird linking issue could cause wrong version of ALSA symbols to be called,                                   resulting in zeroed values */    /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */    if( isPlug && maxChans > 128 )    {        maxChans = 128;        PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));    }    /* TWEAKME:     *     * Giving values for default min and max latency is not     * straightforward.  Here are our objectives:     *     *         * for low latency, we want to give the lowest value     *         that will work reliably.  This varies based on the     *         sound card, kernel, CPU, etc.  I think it is better     *         to give sub-optimal latency than to give a number     *         too low and cause dropouts.  My conservative     *         estimate at this point is to base it on 4096-sample     *         latency at 44.1 kHz, which gives a latency of 23ms.     *         * for high latency we want to give a large enough     *         value that dropouts are basically impossible.  This     *         doesn't really require as much tweaking, since     *         providing too large a number will just cause us to     *         select the nearest setting that will work at stream     *         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 some standard plugins */static int IgnorePlugin( const char *pluginId ){    /* XXX: dmix and default ignored because after opening and closing, they seem to keep hogging resources.     */    static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee",        "file", "null", "shm", "cards", "dmix", "default", NULL};    int i = 0;    while( ignoredPlugins[i] )    {        if( !strcmp( pluginId, ignoredPlugins[i] ) )        {            return 1;        }        ++i;    }    return 0;}/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ){    PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;    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 */    baseApi->info.defaultInputDevice = paNoDevice;    baseApi->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 )        {            /* Unable to open card :( */            PA_DEBUG(( "%s: Unable to open device %s\n", __FUNCTION__, alsaCardName ));            continue;        }        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 */    if( NULL == snd_config )    {        /* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */        ENSURE_( snd_config_update(), paUnanticipatedHostError );        PA_DEBUG(( "Updating snd_config\n" ));    }    assert( snd_config );    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 = "unknown", *idStr = NULL;            int err = 0;            char *alsaDeviceName, *deviceName;            snd_config_t *n = snd_config_iterator_entry( i ), * tp = NULL;;            if( (err = snd_config_search( n, "type", &tp )) < 0 )            {                if( -ENOENT != err )                {                    ENSURE_(err, paUnanticipatedHostError);                }            }            else             {                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( baseApi->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 *baseDeviceInfo = &deviceInfo->baseDeviceInfo;        int canMmap = -1;

⌨️ 快捷键说明

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