pa_linux_alsa.c

来自「基于sip协议的网络电话源码」· C语言 代码 · 共 1,692 行 · 第 1/5 页

C
1,692
字号
    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;    }}/** 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( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection        streamDir, snd_pcm_t **pcm ){    PaError result = paNoError;    int ret;    const char *deviceName = alloca( 50 );    const PaAlsaDeviceInfo *deviceInfo = NULL;    PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;    if( !streamInfo )    {        int usePlug = 0;        deviceInfo = GetDeviceInfo( hostApi, params->device );                /* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */        if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) )            usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) );        if( usePlug )            snprintf( (char *) deviceName, 50, "plug%s", deviceInfo->alsaName );        else            deviceName = deviceInfo->alsaName;    }    else        deviceName = streamInfo->deviceString;    if( (ret = snd_pcm_open( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,                    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 PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,        double sampleRate, StreamDirection streamDir ){    PaError result = paNoError;    snd_pcm_t *pcm = NULL;    PaSampleFormat availableFormats;    /* We are able to adapt to a number of channels less than what the device supports */    unsigned int numHostChannels;    PaSampleFormat hostFormat;    snd_pcm_hw_params_t *hwParams;    snd_pcm_hw_params_alloca( &hwParams );        if( !parameters->hostApiSpecificStreamInfo )    {        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );        numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?                devInfo->minInputChannels : devInfo->minOutputChannels );    }    else        numHostChannels = parameters->channelCount;    PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );    snd_pcm_hw_params_any( pcm, hwParams );    if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )    {        result = paInvalidSampleRate;        goto error;    }    if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )    {        result = paInvalidChannelCount;        goto error;    }    /* See if we can find a best possible match */    availableFormats = GetAvailableFormats( pcm );    PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );    ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );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;    if( inputParameters )    {        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );        inputChannelCount = inputParameters->channelCount;        inputSampleFormat = inputParameters->sampleFormat;    }    if( outputParameters )    {        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );        outputChannelCount = outputParameters->channelCount;        outputSampleFormat = outputParameters->sampleFormat;    }    if( inputChannelCount )    {        if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ))                != paNoError )            goto error;    }    if ( outputChannelCount )    {        if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ))                != paNoError )            goto error;    }    return paFormatIsSupported;error:    return result;}static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,        const PaStreamParameters *params, StreamDirection streamDir, int callbackMode ){    PaError result = paNoError;    PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat;    assert( params->channelCount > 0 );    /* Make sure things have an initial value */    memset( self, 0, sizeof (PaAlsaStreamComponent) );    if( NULL == params->hostApiSpecificStreamInfo )    {        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->commonHostApiRep, params->device );        self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels                : devInfo->minOutputChannels );    }    else    {        /* We're blissfully unaware of the minimum channelCount */        self->numHostChannels = params->channelCount;    }    PA_ENSURE( AlsaOpen( &alsaApi->commonHostApiRep, params, streamDir, &self->pcm ) );    self->nfds = snd_pcm_poll_descriptors_count( self->pcm );    hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );    self->hostSampleFormat = hostSampleFormat;    self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );    self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);    self->numUserChannels = params->channelCount;    self->streamDir = streamDir;    if( !callbackMode && !self->userInterleaved )    {        /* Pre-allocate non-interleaved user provided buffers */        PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),                paInsufficientMemory );    }error:    return result;}static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self ){    snd_pcm_close( self->pcm );    if( self->userBuffers )        PaUtil_FreeMemory( self->userBuffers );}/** Configure the associated ALSA pcm. * */static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, const PaStreamParameters *params, unsigned long        framesPerHostBuffer, int primeBuffers, int callbackMode, double *sampleRate, PaTime *returnedLatency ){    /*    int numPeriods;    if( getenv("PA_NUMPERIODS") != NULL )        numPeriods = atoi( getenv("PA_NUMPERIODS") );    else        numPeriods = ( (latency * sampleRate) / *framesPerBuffer ) + 1;    PA_DEBUG(( "latency: %f, rate: %f, framesPerBuffer: %d\n", latency, sampleRate, *framesPerBuffer ));    if( numPeriods <= 1 )        numPeriods = 2;    */    /* Configuration consists of setting all of ALSA's parameters.     * These parameters come in two flavors: hardware parameters     * and software paramters.  Hardware parameters will affect     * the way the device is initialized, software parameters     * affect the way ALSA interacts with me, the user-level client.     */    snd_pcm_hw_params_t *hwParams;    snd_pcm_sw_params_t *swParams;    PaError result = paNoError;    snd_pcm_access_t accessMode, alternateAccessMode;    unsigned int numPeriods, minPeriods = 2;    int dir = 0;    snd_pcm_t *pcm = self->pcm;    PaTime latency = params->suggestedLatency;    double sr = *sampleRate;    *returnedLatency = -1.;    snd_pcm_hw_params_alloca( &hwParams );    snd_pcm_sw_params_alloca( &swParams );    self->framesPerBuffer = framesPerHostBuffer;    /* ... fill up the configuration space with all possibile     * combinations of parameters this device will accept */    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );    ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );    ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );    if( self->userInterleaved )    {        accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;        alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;    }    else    {        accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;        alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;    }    /* If requested access mode fails, try alternate mode */    if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )    {        ENSURE_( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ), paUnanticipatedHostError );        /* Flip mode */        self->hostInterleaved = !self->userInterleaved;    }    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );    ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate );    ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError );    /* reject if there's no sample rate within 1% of the one requested */    if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 )    {        PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));                         PA_ENSURE( paInvalidSampleRate );    }    ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );    /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */    dir = 0;    ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );    dir = 0;    ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &self->framesPerBuffer, &dir ), paUnanticipatedHostError );        /* Find an acceptable number of periods */    numPeriods = (latency * sr) / self->framesPerBuffer + 1;    dir = 0;    ENSURE_( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, &dir ), paUnanticipatedHostError );    /* Minimum of periods should already be 2 */    PA_UNLESS( numPeriods >= 2, paInternalError );    /* Set the parameters! */    ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );    ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );    /* Latency in seconds, one period is not counted as latency */    latency = (numPeriods - 1) * self->framesPerBuffer / sr;

⌨️ 快捷键说明

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