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

📄 pa_linux_alsa.c

📁 一个开源的sip源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds +                    self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory );    PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );    ASSERT_CALL_( PaUnixMutex_Initialize( &self->stateMtx ), paNoError );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_( PaUnixMutex_Terminate( &self->stateMtx ), paNoError );    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 );}/** Determine size per host buffer. * * During this method call, the component's framesPerBuffer attribute gets computed, and the corresponding period size * gets configured for the device. * @param accurate: If the configured period size is non-integer, this will be set to 0. */static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamComponent* self, const PaStreamParameters* params,        unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate ){    PaError result = paNoError;    unsigned long bufferSize = params->suggestedLatency * sampleRate, framesPerHostBuffer;    int dir = 0;        {        snd_pcm_uframes_t tmp;        snd_pcm_hw_params_get_buffer_size_min( hwParams, &tmp );        bufferSize = PA_MAX( bufferSize, tmp );        snd_pcm_hw_params_get_buffer_size_max( hwParams, &tmp );        bufferSize = PA_MIN( bufferSize, tmp );    }    assert( bufferSize > 0 );    if( framesPerUserBuffer != paFramesPerBufferUnspecified )    {        /* Preferably the host buffer size should be a multiple of the user buffer size */        if( bufferSize > framesPerUserBuffer )        {            snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer;            if( remainder > framesPerUserBuffer / 2. )                bufferSize += framesPerUserBuffer - remainder;            else                bufferSize -= remainder;            assert( bufferSize % framesPerUserBuffer == 0 );        }        else if( framesPerUserBuffer % bufferSize != 0 )        {            /*  Find a good compromise between user specified latency and buffer size */            if( bufferSize > framesPerUserBuffer * .75 )            {                bufferSize = framesPerUserBuffer;            }            else            {                snd_pcm_uframes_t newSz = framesPerUserBuffer;                while( newSz / 2 >= bufferSize )                {                    if( framesPerUserBuffer % (newSz / 2) != 0 )                    {                        /* No use dividing any further */                        break;                    }                    newSz /= 2;                }                bufferSize = newSz;            }            assert( framesPerUserBuffer % bufferSize == 0 );        }    }    /* Using 5 as a base number of periods, we try to approximate the suggested latency (+1 period),       finding a combination of period/buffer size which best fits these constraints */    {        unsigned numPeriods = 4, maxPeriods = 0;        /* It may be that the device only supports 2 periods for instance */        dir = 0;        ENSURE_( snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError );        assert( maxPeriods > 1 );        /* One period is not counted as latency */        maxPeriods -= 1;        numPeriods = PA_MIN( maxPeriods, numPeriods );        if( framesPerUserBuffer != paFramesPerBufferUnspecified )        {            framesPerHostBuffer = framesPerUserBuffer;            if( framesPerHostBuffer < bufferSize )            {                while( bufferSize / framesPerHostBuffer > numPeriods )                {                    framesPerHostBuffer *= 2;                }            }            else            {                while( bufferSize / framesPerHostBuffer < numPeriods )                {                    if( framesPerUserBuffer % (framesPerHostBuffer / 2) != 0 )                    {                        /* Can't be divided any further */                        break;                    }                    framesPerHostBuffer /= 2;                }            }            if( framesPerHostBuffer < framesPerUserBuffer )            {                assert( framesPerUserBuffer % framesPerHostBuffer == 0 );                if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )                {                    if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )                        framesPerHostBuffer *= 2;                    else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )                        framesPerHostBuffer /= 2;                }            }            else            {                assert( framesPerHostBuffer % framesPerUserBuffer == 0 );                if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )                {                    if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )                        framesPerHostBuffer += framesPerUserBuffer;                    else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )                        framesPerHostBuffer -= framesPerUserBuffer;                }            }        }        else        {            framesPerHostBuffer = bufferSize / numPeriods;        }    }    assert( framesPerHostBuffer > 0 );    {        snd_pcm_uframes_t min = 0, max = 0;        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError );        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError );        if( framesPerHostBuffer < min )        {            PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__,                        framesPerHostBuffer, min ));            framesPerHostBuffer = min;        }        else if( framesPerHostBuffer > max )        {            PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__,                        framesPerHostBuffer, max ));            framesPerHostBuffer = max;        }        assert( framesPerHostBuffer >= min && framesPerHostBuffer <= max );        dir = 0;        ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ),                paUnanticipatedHostError );        if( dir != 0 )        {            PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir ));            *accurate = 0;        }    }    self->framesPerBuffer = framesPerHostBuffer;error:    return result;}/* We need to determine how many frames per host buffer (period) to use.  Our * goals are to provide the best possible performance, but also to * honor the requested latency settings as closely as we can. 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 method will determine suitable period sizes for capture and playback handles, and report the maximum number of * frames per host buffer. The latter is relevant, in case we should be so unfortunate that the period size differs * between capture and playback. If this should happen, the stream's hostBufferSizeMode attribute will be set to * paUtilBoundedHostBufferSize, because the best we can do is limit the size of individual host buffers to the upper * bound. The size of host buffers scheduled for processing should only matter if the user has specified a buffer size, * but when he/she does we must strive for an optimal configuration. By default we'll opt for a fixed host buffer size, * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size. * * The framesPerBuffer attributes of the individual capture and playback components of the stream are set to corresponding * values determined here. Since these should be reported as  * * 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? * * @param determinedFramesPerHostBuffer: The determined host buffer size. */static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double sampleRate, const PaStreamParameters* inputParameters,        const PaStreamParameters* outputParameters, unsigned long framesPerUserBuffer, snd_pcm_hw_params_t* hwParamsCapture,        snd_pcm_hw_params_t* hwParamsPlayback, PaUtilHostBufferSizeMode* hostBufferSizeMode ){    PaError result = paNoError;    unsigned long framesPerHostBuffer = 0;    int dir = 0;    int accurate = 1;    if( self->capture.pcm && self->playback.pcm )    {        if( framesPerUserBuffer == paFramesPerBufferUnspecified )        {            snd_pcm_uframes_t desiredLatency, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize,                              minCapture, minPlayback, maxCapture, maxPlayback;            /* Come up with a common desired latency */            dir = 0;            ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );            dir = 0;            ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );            dir = 0;            ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );            dir = 0;            ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );            minPeriodSize = PA_MAX( minPlayback, minCapture );            maxPeriodSize = PA_MIN( maxPlayback, maxCapture );            PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination );            desiredLatency = (snd_pcm_uframes_t)(PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )                    * sampleRate);            /* Clamp desiredLatency */            {                snd_pcm_uframes_t maxBufferSize;                snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback;                ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError );                ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError );                maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback );                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( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&                        snd_pcm_hw_params_test_period_size( self->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 )            {                if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) < 0 )                    continue;                if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, optimalPeriodSize, 0 ) >= 0 )                    break;                optimalPeriodSize /= 2;            }            if( optimalPeriodSize > periodSize )                periodSize = optimalPeriodSize;            if( periodSize <= maxPeriodSize )            {                /* Looks good, the periodSize _should_ be acceptable by both devices */                ENSURE_( snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ),                        paUnanticipatedHostError );                ENSURE_( snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),                        paUnanticipatedHostError );                self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize;                framesPerHostBuffer = periodSize;            }            else            {                /* Unable to find a common period size, oh well */                optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );                optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );                self->capture.framesPerBuffer = optimalPeriodSize;                dir = 0;                ENSURE_( snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ),                        paUnanticipatedHostError );                self->playback.framesPerBuffer = optimalPeriodSize;                dir = 0;                ENSURE_( snd_pcm_hw_params_set_period_size_

⌨️ 快捷键说明

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