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

📄 pa_linux_alsa.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 5 页
字号:
        if( getenv( "PA_ALSA_REALTIME" ) && atoi( getenv( "PA_ALSA_REALTIME" ) ) )        {            struct sched_param spm = { 0 };            int maxPri = sched_get_priority_max( SCHED_FIFO ), minPri = sched_get_priority_min( SCHED_FIFO );            spm.sched_priority = (maxPri - minPri) / 2 + minPri;            if( pthread_setschedparam( stream->callback_thread, SCHED_FIFO, &spm ) != 0 )                PA_DEBUG(( "Failed bumping priority\n" ));        }        /*! Wait for stream to be started */        ts.tv_sec = (__time_t) pt + 1;        ts.tv_nsec = (long) pt * 1000000000;        /* Since we'll be holding a lock on the startMtx (when not waiting on the condition), IsRunning won't be checking         * stream state at the same time as the callback thread affects it. We also check IsStreamActive, in the unlikely         * case the callback thread exits in the meantime (the stream will be considered inactive after the thread exits) */        UNLESS( !pthread_mutex_lock( &stream->startMtx ), paInternalError );        while( !IsRunning( stream ) && res != ETIMEDOUT && IsStreamActive( s ) )            res = pthread_cond_timedwait( &stream->startCond, &stream->startMtx, &ts );        UNLESS( !pthread_mutex_unlock( &stream->startMtx ), paInternalError );        PA_DEBUG(( "StartStream: Waited for %g seconds for stream to start\n", PaUtil_GetTime() - pt ));        if( res == ETIMEDOUT )        {            pthread_cancel( stream->callback_thread );            pthread_join( stream->callback_thread, NULL );            PA_ENSURE( paTimedOut );        }    }    else        PA_ENSURE( AlsaStart( stream, 0 ) );end:    return result;error:    stream->isActive = 0;    goto end;}static PaError AlsaStop( PaAlsaStream *stream, int abort ){    PaError result = paNoError;    if( abort )    {        if( stream->pcm_playback )            ENSURE( snd_pcm_drop( stream->pcm_playback ), paUnanticipatedHostError );        if( stream->pcm_capture && !stream->pcmsSynced )            ENSURE( snd_pcm_drop( stream->pcm_capture ), paUnanticipatedHostError );        PA_DEBUG(( "Dropped frames\n" ));    }    else    {        if( stream->pcm_playback )            ENSURE( snd_pcm_drain( stream->pcm_playback ), paUnanticipatedHostError );        if( stream->pcm_capture && !stream->pcmsSynced )            ENSURE( snd_pcm_drain( stream->pcm_capture ), paUnanticipatedHostError );    }end:    return result;error:    goto end;}/*! \brief Stop or abort stream * * If a stream is in callback mode we will have to inspect wether the background thread has * finished, or we will have to take it out. In either case we join the thread before * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish * buffers (drain) * * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function */static PaError RealStop( PaStream *s, int abort ){    PaError result = paNoError;    PaAlsaStream *stream = (PaAlsaStream*)s;    /* These two are used to obtain return value when joining thread */    void *pret;    int retVal;    /* First deal with the callback thread, cancelling and/or joining     * it if necessary     */    if( stream->callback_mode )    {        int res = 0;        if( stream->callback_finished )        {            res = pthread_join( stream->callback_thread, &pret );  /* Just wait for it to die */                        if( pret )  /* Message from dying thread */            {                retVal = *(PaError *) pret;                free( pret );                PA_ENSURE( retVal );            }        }        else        {            /* We are running in callback mode, and the callback thread             * is still running.  Cancel it and wait for it to be done. */            PA_DEBUG(( "RealStop: Canceling thread\n" ));            pthread_cancel( stream->callback_thread );      /* Snuff it! */            res = pthread_join( stream->callback_thread, NULL );            /* XXX: Some way to obtain return value from cancelled thread? */        }        stream->callback_finished = 0;        if( res != 0 )  /* Pthread call went wrong */            PA_ENSURE( paInternalError );    }    else    {        PA_ENSURE( AlsaStop( stream, abort ) );    }    stream->isActive = 0;end:    return result;error:    goto end;}static PaError StopStream( PaStream *s ){    ((PaAlsaStream *) s)->callbackAbort = 0;    /* In case abort has been called earlier */    return RealStop( s, 0);}static PaError AbortStream( PaStream *s ){    ((PaAlsaStream *) s)->callbackAbort = 1;    return RealStop( s, 1);}/*! * The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback * returning !paContinue is not considered) */static PaError IsStreamStopped( PaStream *s ){    PaAlsaStream *stream = (PaAlsaStream *)s;    PaError res;    /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */    res = !IsStreamActive( s ) && !stream->callback_finished;    return res;}static PaError IsStreamActive( PaStream *s ){    PaAlsaStream *stream = (PaAlsaStream*)s;    return stream->isActive;}static PaTime GetStreamTime( PaStream *s ){    PaAlsaStream *stream = (PaAlsaStream*)s;    snd_timestamp_t timestamp;    snd_pcm_status_t *status;    snd_pcm_status_alloca( &status );    /* TODO: what if we have both?  does it really matter? */    /* TODO: if running in callback mode, this will mean     * libasound routines are being called form multiple threads.     * need to verify that libasound is thread-safe. */    if( stream->pcm_capture )    {        snd_pcm_status( stream->pcm_capture, status );    }    else if( stream->pcm_playback )    {        snd_pcm_status( stream->pcm_playback, status );    }    snd_pcm_status_get_tstamp( status, &timestamp );    PA_DEBUG(( "Time in secs: %d\n", timestamp.tv_sec ));    return timestamp.tv_sec + (PaTime) timestamp.tv_usec/1000000;}static double GetStreamCpuLoad( PaStream* s ){    PaAlsaStream *stream = (PaAlsaStream*)s;    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );}/*! * \brief Free resources associated with stream, and eventually stream itself * * Frees allocated memory, and closes opened pcms. */void CleanUpStream( PaAlsaStream *stream ){    assert( stream );    if( stream->pcm_capture )    {        snd_pcm_close( stream->pcm_capture );    }    if( stream->pcm_playback )    {        snd_pcm_close( stream->pcm_playback );    }    PaUtil_FreeMemory( stream->pfds );    pthread_mutex_destroy( &stream->stateMtx );    pthread_mutex_destroy( &stream->startMtx );    pthread_cond_destroy( &stream->startCond );    PaUtil_FreeMemory( stream );}int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ){    unsigned long approx = (unsigned long) sampleRate;    int dir = 0;    double fraction = sampleRate - approx;    assert( pcm && hwParams );    if( fraction > 0.0 )    {        if( fraction > 0.5 )        {            ++approx;            dir = -1;        }        else            dir = 1;    }    return snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir );}/* Return exact sample rate in param sampleRate */int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ){    unsigned int num, den;    int err;     assert( hwParams );    err = snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den );    *sampleRate = (double) num / den;    return err;}/* Utility functions for blocking/callback interfaces *//* Atomic restart of stream (we don't want the intermediate state visible) */static PaError AlsaRestart( PaAlsaStream *stream ){    PaError result = paNoError;    PA_DEBUG(( "Restarting audio\n" ));    UNLESS( !pthread_mutex_lock( &stream->stateMtx ), paInternalError );    PA_ENSURE( AlsaStop( stream, 0 ) );    PA_ENSURE( AlsaStart( stream, 0 ) );    PA_DEBUG(( "Restarted audio\n" ));end:    if( pthread_mutex_unlock( &stream->stateMtx ) != 0 )        result = paInternalError;    return result;error:   goto end;}static PaError HandleXrun( PaAlsaStream *stream ){    PaError result = paNoError;    snd_pcm_status_t *st;    PaTime now = PaUtil_GetTime();    snd_timestamp_t t;    snd_pcm_status_alloca( &st );    if( stream->pcm_playback )    {        snd_pcm_status( stream->pcm_playback, st );        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )        {            snd_pcm_status_get_trigger_tstamp( st, &t );            stream->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);        }    }    if( stream->pcm_capture )    {        snd_pcm_status( stream->pcm_capture, st );        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )        {            snd_pcm_status_get_trigger_tstamp( st, &t );            stream->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);        }    }    PA_ENSURE( AlsaRestart( stream ) );end:    return result;error:    goto end;}/*!  \brief Poll on I/O filedescriptors  Poll till we've determined there's data for read or write. In the full-duplex case,  we don't want to hang around forever waiting for either input or output frames, so  whenever we have a timed out filedescriptor we check if we're nearing under/overrun  for the other pcm (critical limit set at one buffer). If so, we exit the waiting state,  and go on with what we got.  */static PaError Wait( PaAlsaStream *stream, snd_pcm_uframes_t *frames ){    PaError result = paNoError;    int pollPlayback = 0, pollCapture = 0;    snd_pcm_sframes_t captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail;    int xrun = 0;   /* Under/overrun? */    assert( stream && frames && stream->pollTimeout > 0 );    if( stream->pcm_capture )        pollCapture = 1;    if( stream->pcm_playback )        poll

⌨️ 快捷键说明

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