pa_linux_alsa.c

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

C
1,692
字号
    /* Now software parameters... */    ENSURE_( snd_pcm_sw_params_current( pcm, swParams ), paUnanticipatedHostError );    ENSURE_( snd_pcm_sw_params_set_start_threshold( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );    ENSURE_( snd_pcm_sw_params_set_stop_threshold( pcm, swParams, self->bufferSize ), paUnanticipatedHostError );    /* Silence buffer in the case of underrun */    if( !primeBuffers ) /* XXX: Make sense? */    {        snd_pcm_uframes_t boundary;        ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );        ENSURE_( snd_pcm_sw_params_set_silence_threshold( pcm, swParams, 0 ), paUnanticipatedHostError );        ENSURE_( snd_pcm_sw_params_set_silence_size( pcm, swParams, boundary ), paUnanticipatedHostError );    }            ENSURE_( snd_pcm_sw_params_set_avail_min( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );    ENSURE_( snd_pcm_sw_params_set_xfer_align( pcm, swParams, 1 ), paUnanticipatedHostError );    ENSURE_( snd_pcm_sw_params_set_tstamp_mode( pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );    /* Set the parameters! */    ENSURE_( snd_pcm_sw_params( pcm, swParams ), paUnanticipatedHostError );    *sampleRate = sr;    *returnedLatency = latency;end:    return result;error:    goto end;   /* No particular action */}static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,        const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback,        PaStreamFlags streamFlags, void *userData ){    PaError result = paNoError;    assert( self );    memset( self, 0, sizeof (PaAlsaStream) );    if( NULL != callback )    {        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,                                               &alsaApi->callbackStreamInterface,                                               callback, userData );        self->callbackMode = 1;    }    else    {        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,                                               &alsaApi->blockingStreamInterface,                                               NULL, userData );    }    self->framesPerUserBuffer = framesPerUserBuffer;    self->neverDropInput = streamFlags & paNeverDropInput;    /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */    /*    if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback )        self->primeBuffers = 1;        */    memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) );    memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) );    if( inParams )        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) );    if( outParams )        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) );    assert( self->capture.nfds || self->playback.nfds );    PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds +                    self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory );    PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );    InitializeThreading( &self->threading, &self->cpuLoadMeasurer );    ASSERT_CALL_( pthread_mutex_init( &self->stateMtx, NULL ), 0 );    ASSERT_CALL_( pthread_mutex_init( &self->startMtx, NULL ), 0 );    ASSERT_CALL_( pthread_cond_init( &self->startCond, NULL ), 0 );error:    return result;}/** Free resources associated with stream, and eventually stream itself. * * Frees allocated memory, and terminates individual StreamComponents. */static void PaAlsaStream_Terminate( PaAlsaStream *self ){    assert( self );    if( self->capture.pcm )    {        PaAlsaStreamComponent_Terminate( &self->capture );    }    if( self->playback.pcm )    {        PaAlsaStreamComponent_Terminate( &self->playback );    }    PaUtil_FreeMemory( self->pfds );    ASSERT_CALL_( pthread_mutex_destroy( &self->stateMtx ), 0 );    ASSERT_CALL_( pthread_mutex_destroy( &self->startMtx ), 0 );    ASSERT_CALL_( pthread_cond_destroy( &self->startCond ), 0 );    PaUtil_FreeMemory( self );}/** Calculate polling timeout * * @param frames Time to wait * @return Polling timeout in milliseconds */static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames ){    assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 );    /* Period in msecs, rounded up */    return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );}/** Set up ALSA stream parameters. * */static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters        *outParams, double sampleRate, unsigned long framesPerHostBuffer, double *inputLatency, double *outputLatency,        unsigned long *maxHostBufferSize ){    PaError result = paNoError;    double realSr = sampleRate;    if( self->capture.pcm )        PA_ENSURE( PaAlsaStreamComponent_Configure( &self->capture, inParams, framesPerHostBuffer, self->primeBuffers,                    self->callbackMode, &realSr, inputLatency ) );    if( self->playback.pcm )        PA_ENSURE( PaAlsaStreamComponent_Configure( &self->playback, outParams, framesPerHostBuffer, self->primeBuffers,                    self->callbackMode, &realSr, outputLatency ) );    /* Should be exact now */    self->streamRepresentation.streamInfo.sampleRate = realSr;    /* this will cause the two streams to automatically start/stop/prepare in sync.     * We only need to execute these operations on one of the pair.     * A: We don't want to do this on a blocking stream.     */    if( self->callbackMode && self->capture.pcm && self->playback.pcm )    {        int err = snd_pcm_link( self->capture.pcm, self->playback.pcm );        if( err >= 0 )            self->pcmsSynced = 1;        else            PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) ));    }    /* Frames per host buffer for the stream is set as a compromise between the two directions */    framesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,            self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );    self->pollTimeout = CalculatePollTimeout( self, framesPerHostBuffer );    /* Period in msecs, rounded up */    *maxHostBufferSize = PA_MAX( self->capture.pcm ? self->capture.bufferSize : 0,            self->playback.pcm ? self->playback.bufferSize : 0 );    /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */    self->threading.throttledSleepTime = (unsigned long) (framesPerHostBuffer / sampleRate / 4 * 1000);    if( self->callbackMode )    {        /* If the user expects a certain number of frames per callback we will either have to rely on block adaption         * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number         * of host buffer frames with what the user specified */        if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )        {            /* self->alignFrames = 1; */            /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely             * on block adaption */        /*            if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&                        self->capture.framesPerBuffer != self->playback.framesPerBuffer) )                self->useBlockAdaption = 1;            else                self->alignFrames = 1;        */        }    }error:    return result;}/* We need to determine how many frames per host buffer to use.  Our * goals are to provide the best possible performance, but also to * most closely honor the requested latency settings.  Therefore this * decision is based on: * *   - the period sizes that playback and/or capture support.  The *     host buffer size has to be one of these. *   - the number of periods that playback and/or capture support. * * We want to make period_size*(num_periods-1) to be as close as possible * to latency*rate for both playback and capture. * * This is one of those blocks of code that will just take a lot of * refinement to be any good. * * In the full-duplex case it is possible that the routine was unable * to find a number of frames per buffer acceptable to both devices * TODO: Implement an algorithm to find the value closest to acceptance * by both devices, to minimize difference between period sizes? */static PaError DetermineFramesPerBuffer( const PaAlsaStream *stream, double sampleRate, const PaStreamParameters *inputParameters,        const PaStreamParameters *outputParameters, unsigned long *determinedFrames, const PaUtilHostApiRepresentation *hostApi ){    PaError result = paNoError;    unsigned long framesPerBuffer = 0;    int numHostInputChannels = 0, numHostOutputChannels = 0;    /* XXX: Clean this up */    if( stream->capture.pcm )    {        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, inputParameters->device );        numHostInputChannels = PA_MAX( inputParameters->channelCount, devInfo->minInputChannels );    }    if( stream->playback.pcm )    {        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, outputParameters->device );        numHostOutputChannels = PA_MAX( outputParameters->channelCount, devInfo->minOutputChannels );    }    if( stream->capture.pcm && stream->playback.pcm )    {        snd_pcm_uframes_t desiredLatency, e;        snd_pcm_uframes_t minPeriodSize, minPlayback, minCapture, maxPeriodSize, maxPlayback, maxCapture,                          optimalPeriodSize, periodSize;        int dir = 0;        unsigned int minPeriods = 2;        snd_pcm_t *pcm;        snd_pcm_hw_params_t *hwParamsPlayback, *hwParamsCapture;        snd_pcm_hw_params_alloca( &hwParamsPlayback );        snd_pcm_hw_params_alloca( &hwParamsCapture );        /* Come up with a common desired latency */        pcm = stream->playback.pcm;        snd_pcm_hw_params_any( pcm, hwParamsPlayback );        ENSURE_( SetApproximateSampleRate( pcm, hwParamsPlayback, sampleRate ), paInvalidSampleRate );        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsPlayback, numHostOutputChannels ),                paBadIODeviceCombination );        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsPlayback, &minPeriods, &dir ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );        pcm = stream->capture.pcm;        ENSURE_( snd_pcm_hw_params_any( pcm, hwParamsCapture ), paUnanticipatedHostError );        ENSURE_( SetApproximateSampleRate( pcm, hwParamsCapture, sampleRate ), paBadIODeviceCombination );        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsCapture, numHostInputChannels ),                paBadIODeviceCombination );        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsCapture, &minPeriods, &dir ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );        minPeriodSize = PA_MAX( minPlayback, minCapture );        maxPeriodSize = PA_MIN( maxPlayback, maxCapture );        desiredLatency = (snd_pcm_uframes_t) (PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )                * sampleRate);        /* Clamp desiredLatency */        {            snd_pcm_uframes_t tmp, maxBufferSize = ULONG_MAX;            ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSize ), paUnanticipatedHostError );            ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &tmp ), paUnanticipatedHostError );            maxBufferSize = PA_MIN( maxBufferSize, tmp );            desiredLatency = PA_MIN( desiredLatency, maxBufferSize );        }        /* Find the closest power of 2 */        e = ilogb( minPeriodSize );        if( minPeriodSize & (minPeriodSize - 1) )            e += 1;        periodSize = (snd_pcm_uframes_t) pow( 2, e );        while( periodSize <= maxPeriodSize )        {            if( snd_pcm_hw_params_test_period_size( stream->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&                    snd_pcm_hw_params_test_period_size( stream->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )                break;  /* Ok! */            periodSize *= 2;        }        /* 4 periods considered optimal */        optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );        optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );        /* Find the closest power of 2 */        e = ilogb( optimalPeriodSize );        if( optimalPeriodSize & (optimalPeriodSize - 1) )            e += 1;        optimalPeriodSize = (snd_pcm_uframes_t) pow( 2, e );        while( optimalPeriodSize >= periodSize )        {            pcm = stream->playback.pcm;            if( snd_pcm_hw_params_test_period_size( pcm, hwParamsPlayback, optimalPeriodSize, 0 ) < 0 )                continue;            pcm = stream->capture.pcm;            if( snd_pcm_hw_params_test_period_size( pcm, hwParamsCapture, optimalPeriodSize, 0 ) >= 0 )                break;            optimalPeriodSize /= 2;        }        if( optimalPeriodSize > periodSize )            periodSize = optimalPeriodSize;        if( periodSize <= maxPeriodSize )        {            /* Looks good */            framesPerBuffer = periodSize;        }        else        {            /* Unable to find a common period size, oh well */            optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );            optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );            /* ConfigureStream should find individual period siz

⌨️ 快捷键说明

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