pa_linux_alsa.c

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

C
1,692
字号
            static const struct sched_param defaultSpm = { 0 };            PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));            pthread_getschedparam( th->callbackThread, &policy, &spm );            if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )            {                throttled = 1;            }            else                PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));            /* Give other processes a go, before raising priority again */            PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));            Pa_Sleep( th->throttledSleepTime );            /* Reset callback priority */            if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )            {                PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));            }            if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )                intervalMsec = 50;            else                intervalMsec = 100;            /*            lowpassCoeff = .97;            lowpassCoeff1 = .99999 - lowpassCoeff;            */        }        else if( throttled && avgCpuLoad < .8 )        {            intervalMsec = 500;            throttled = 0;            /*            lowpassCoeff = .9;            lowpassCoeff1 = .99999 - lowpassCoeff;            */        }    }    pthread_cleanup_pop( 1 );   /* Execute cleanup on exit */error:    /* Shouldn't get here in the normal case */    /* Pass on error code */    pres = malloc( sizeof (PaError) );    *pres = result;        pthread_exit( pres );}static PaError CreateCallbackThread( PaAlsaThreading *th, void *(*callbackThreadFunc)( void * ), PaStream *s ){    PaError result = paNoError;    pthread_attr_t attr;    int started = 0;#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)    if( th->rtSched )    {        if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )        {            int savedErrno = errno;             /* In case errno gets overwritten */            assert( savedErrno != EINVAL );     /* Most likely a programmer error */            PA_UNLESS( (savedErrno == EPERM), paInternalError );            PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));        }        else            PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));    }#endif    PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );    /* Priority relative to other processes */    PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );       PA_UNLESS( !pthread_create( &th->callbackThread, &attr, callbackThreadFunc, s ), paInternalError );    started = 1;    if( th->rtSched )    {        if( th->useWatchdog )        {            int err;            struct sched_param wdSpm = { 0 };            /* Launch watchdog, watchdog sets callback thread priority */            int prio = PA_MIN( th->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );            wdSpm.sched_priority = prio;            PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );            PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );            PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );            PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );            PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );            if( (err = pthread_create( &th->watchdogThread, &attr, &WatchdogFunc, th )) )            {                PA_UNLESS( err == EPERM, paInternalError );                /* Permission error, go on without realtime privileges */                PA_DEBUG(( "Failed bumping priority\n" ));            }            else            {                int policy;                th->watchdogRunning = 1;                ASSERT_CALL_( pthread_getschedparam( th->watchdogThread, &policy, &wdSpm ), 0 );                /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */                if( wdSpm.sched_priority != prio )                {                    PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));                    PA_ENSURE( paInternalError );                }            }        }        else            PA_ENSURE( BoostPriority( th ) );    }end:    return result;error:    if( started )        KillCallbackThread( th, 0, NULL, NULL );    goto end;}static void CallbackUpdate( PaAlsaThreading *th ){    th->callbackTime = PaUtil_GetTime();    th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );}/* prototypes for functions declared in this file */static void Terminate( struct PaUtilHostApiRepresentation *hostApi );static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,                                  const PaStreamParameters *inputParameters,                                  const PaStreamParameters *outputParameters,                                  double sampleRate );static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,                           PaStream** s,                           const PaStreamParameters *inputParameters,                           const PaStreamParameters *outputParameters,                           double sampleRate,                           unsigned long framesPerBuffer,                           PaStreamFlags streamFlags,                           PaStreamCallback *callback,                           void *userData );static PaError CloseStream( PaStream* stream );static PaError StartStream( PaStream *stream );static PaError StopStream( PaStream *stream );static PaError AbortStream( PaStream *stream );static PaError IsStreamStopped( PaStream *s );static PaError IsStreamActive( PaStream *stream );static PaTime GetStreamTime( PaStream *stream );static double GetStreamCpuLoad( PaStream* stream );static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );/* Callback prototypes */static void *CallbackThreadFunc( void *userData );/* Blocking prototypes */static signed long GetStreamReadAvailable( PaStream* s );static signed long GetStreamWriteAvailable( PaStream* s );static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device ){    return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];}PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){    PaError result = paNoError;    PaAlsaHostApiRepresentation *alsaHostApi = NULL;    PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory(                sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory );    PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );    alsaHostApi->hostApiIndex = hostApiIndex;    *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;    (*hostApi)->info.structVersion = 1;    (*hostApi)->info.type = paALSA;    (*hostApi)->info.name = "ALSA";    (*hostApi)->Terminate = Terminate;    (*hostApi)->OpenStream = OpenStream;    (*hostApi)->IsFormatSupported = IsFormatSupported;    PA_ENSURE( BuildDeviceList( alsaHostApi ) );    PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,                                      CloseStream, StartStream,                                      StopStream, AbortStream,                                      IsStreamStopped, IsStreamActive,                                      GetStreamTime, GetStreamCpuLoad,                                      PaUtil_DummyRead, PaUtil_DummyWrite,                                      PaUtil_DummyGetReadAvailable,                                      PaUtil_DummyGetWriteAvailable );    PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface,                                      CloseStream, StartStream,                                      StopStream, AbortStream,                                      IsStreamStopped, IsStreamActive,                                      GetStreamTime, PaUtil_DummyGetCpuLoad,                                      ReadStream, WriteStream,                                      GetStreamReadAvailable,                                      GetStreamWriteAvailable );    return result;error:    if( alsaHostApi )    {        if( alsaHostApi->allocations )        {            PaUtil_FreeAllAllocations( alsaHostApi->allocations );            PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );        }        PaUtil_FreeMemory( alsaHostApi );    }    return result;}static void Terminate( struct PaUtilHostApiRepresentation *hostApi ){    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;    assert( hostApi );    if( alsaHostApi->allocations )    {        PaUtil_FreeAllAllocations( alsaHostApi->allocations );        PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );    }    PaUtil_FreeMemory( alsaHostApi );    snd_config_update_free_global();}/*! Determine max channels and default latencies. * * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for  * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero, * and a suitable result returned. The device is closed before returning. */static PaError GropeDevice( snd_pcm_t *pcm, int *minChannels, int *maxChannels, double *defaultLowLatency,        double *defaultHighLatency, double *defaultSampleRate, int isPlug ){    PaError result = paNoError;    snd_pcm_hw_params_t *hwParams;    snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;    unsigned int minChans, maxChans;    double defaultSr = *defaultSampleRate;    assert( pcm );    ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );    snd_pcm_hw_params_alloca( &hwParams );    snd_pcm_hw_params_any( pcm, hwParams );    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 */        ENSURE_( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ), paUnanticipatedHostError );        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;

⌨️ 快捷键说明

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