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

📄 pa_linux_alsa.c

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 C
📖 第 1 页 / 共 5 页
字号:
                snd_pcm_hw_params_alloca( &hwParamsPlayback );                snd_pcm_hw_params_alloca( &hwParamsCapture );                /* Come up with a common desired latency */                pcm = stream->pcm_playback;                snd_pcm_hw_params_any( pcm, hwParamsPlayback );                ENSURE( SetApproximateSampleRate( pcm, hwParamsPlayback, sampleRate ), paBadIODeviceCombination );                ENSURE( snd_pcm_hw_params_set_channels( pcm, hwParamsPlayback, outputParameters->channelCount ),                        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_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );                ENSURE( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );                pcm = stream->pcm_capture;                ENSURE( snd_pcm_hw_params_any( pcm, hwParamsCapture ), paUnanticipatedHostError );                ENSURE( SetApproximateSampleRate( pcm, hwParamsCapture, sampleRate ), paBadIODeviceCombination );                ENSURE( snd_pcm_hw_params_set_channels( pcm, hwParamsCapture, inputParameters->channelCount ),                        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_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );                ENSURE( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );                minPeriodSize = MAX( minPlayback, minCapture );                maxPeriodSize = MIN( maxPlayback, maxCapture );                desiredLatency = (snd_pcm_uframes_t) (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, &tmp ), paUnanticipatedHostError );                    maxBufferSize = MIN( maxBufferSize, tmp );                    ENSURE( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &tmp ), paUnanticipatedHostError );                    maxBufferSize = MIN( maxBufferSize, tmp );                    desiredLatency = 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->pcm_playback, hwParamsPlayback, periodSize, 0 ) >= 0 &&                            snd_pcm_hw_params_test_period_size( stream->pcm_capture, hwParamsCapture, periodSize, 0 ) >= 0 )                        break;  /* Ok! */                    periodSize *= 2;                }                /* 4 periods considered optimal */                optimalPeriodSize = MAX( desiredLatency / 4, minPeriodSize );                optimalPeriodSize = 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->pcm_playback;                    if( snd_pcm_hw_params_test_period_size( pcm, hwParamsPlayback, optimalPeriodSize, 0 ) < 0 )                        continue;                    pcm = stream->pcm_capture;                    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 */                    framesPerHostBuffer = periodSize;                }                else    /* XXX: Some more descriptive error code might be appropriate */                    PA_ENSURE( paBadIODeviceCombination );            }            else            {                /* half-duplex is a slightly simpler case */                unsigned long desiredLatency, channels;                snd_pcm_uframes_t minPeriodSize;                unsigned int numPeriods;                snd_pcm_t *pcm;                snd_pcm_hw_params_t *hwParams;                snd_pcm_hw_params_alloca( &hwParams );                if( stream->pcm_capture )                {                    pcm = stream->pcm_capture;                    desiredLatency = inputParameters->suggestedLatency * sampleRate;                    channels = inputParameters->channelCount;                }                else                {                    pcm = stream->pcm_playback;                    desiredLatency = outputParameters->suggestedLatency * sampleRate;                    channels = outputParameters->channelCount;                }                ENSURE( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );                ENSURE( SetApproximateSampleRate( pcm, hwParams, sampleRate ), paBadIODeviceCombination );                ENSURE( snd_pcm_hw_params_set_channels( pcm, hwParams, channels ), paBadIODeviceCombination );                ENSURE( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );                ENSURE( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );                /* Using 5 as a base number of buffers, we try to approximate the suggested latency (+1 period),                   finding a period size which best fits these constraints */                ENSURE( snd_pcm_hw_params_get_period_size_min( hwParams, &minPeriodSize, 0 ), paUnanticipatedHostError );                numPeriods = MIN( desiredLatency / minPeriodSize, 4 ) + 1;                ENSURE( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, 0 ), paUnanticipatedHostError );                framesPerHostBuffer = desiredLatency / (numPeriods - 1);                ENSURE( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &framesPerHostBuffer, 0 ), paUnanticipatedHostError );            }        }    }    else    {        framesPerHostBuffer = framesPerBuffer;    }    /* Will fill in correct values later */    stream->streamRepresentation.streamInfo.inputLatency = 0.;    stream->streamRepresentation.streamInfo.outputLatency = 0.;    if( numInputChannels > 0 )    {        int interleaved = !(inputSampleFormat & paNonInterleaved);        PaSampleFormat plain_format = hostInputSampleFormat & ~paNonInterleaved;        inputLatency = inputParameters->suggestedLatency; /* Real latency in seconds returned from ConfigureStream */        PA_ENSURE( ConfigureStream( stream->pcm_capture, numInputChannels, &interleaved,                             &sampleRate, plain_format, framesPerHostBuffer, &stream->captureBufferSize,                             &inputLatency, 0, stream->callback_mode ) );        stream->capture_interleaved = interleaved;    }    if( numOutputChannels > 0 )    {        int interleaved = !(outputSampleFormat & paNonInterleaved);        PaSampleFormat plain_format = hostOutputSampleFormat & ~paNonInterleaved;        int primeBuffers = streamFlags & paPrimeOutputBuffersUsingStreamCallback;        outputLatency = outputParameters->suggestedLatency; /* Real latency in seconds returned from ConfigureStream */        PA_ENSURE( ConfigureStream( stream->pcm_playback, numOutputChannels, &interleaved,                             &sampleRate, plain_format, framesPerHostBuffer, &stream->playbackBufferSize,                             &outputLatency, primeBuffers, stream->callback_mode ) );        /* If the user wants to prime the buffer before stream start, the start threshold will equal buffer size */        if( primeBuffers )            stream->startThreshold = stream->playbackBufferSize;        stream->playback_interleaved = interleaved;    }    /* Should be exact now */    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,                    numInputChannels, inputSampleFormat, hostInputSampleFormat,                    numOutputChannels, outputSampleFormat, hostOutputSampleFormat,                    sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer,                    paUtilFixedHostBufferSize, callback, userData ) );    /* Ok, buffer processor is initialized, now we can deduce it's latency */    if( numInputChannels > 0 )        stream->streamRepresentation.streamInfo.inputLatency = inputLatency + PaUtil_GetBufferProcessorInputLatency(                &stream->bufferProcessor );    if( numOutputChannels > 0 )        stream->streamRepresentation.streamInfo.outputLatency = outputLatency + PaUtil_GetBufferProcessorOutputLatency(                &stream->bufferProcessor );    /* 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( stream->callback_mode && stream->pcm_capture && stream->pcm_playback &&             snd_pcm_link( stream->pcm_capture, stream->pcm_playback ) >= 0 )            stream->pcmsSynced = 1;    UNLESS( stream->pfds = (struct pollfd*)PaUtil_AllocateMemory( (stream->capture_nfds +                    stream->playback_nfds) * sizeof(struct pollfd) ), paInsufficientMemory );    stream->frames_per_period = framesPerHostBuffer;    stream->capture_channels = numInputChannels;    stream->playback_channels = numOutputChannels;    stream->pollTimeout = (int) ceil( 1000 * stream->frames_per_period/sampleRate );    /* Period in msecs, rounded up */    *s = (PaStream*)stream;    return result;error:    if( stream )        CleanUpStream( stream );    return result;}/*    When CloseStream() is called, the multi-api layer ensures that    the stream has already been stopped or aborted.*/static PaError CloseStream( PaStream* s ){    PaError result = paNoError;    PaAlsaStream *stream = (PaAlsaStream*)s;    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );    CleanUpStream( stream );    return result;}static void SilenceBuffer( PaAlsaStream *stream ){    const snd_pcm_channel_area_t *areas;    snd_pcm_uframes_t frames = snd_pcm_avail_update( stream->pcm_playback );    snd_pcm_mmap_begin( stream->pcm_playback, &areas, &stream->playback_offset, &frames );    snd_pcm_areas_silence( areas, stream->playback_offset, stream->playback_channels, frames, stream->playbackNativeFormat );    snd_pcm_mmap_commit( stream->pcm_playback, stream->playback_offset, frames );}/*! \brief Start/prepare pcm(s) for streaming * * Depending on wether the stream is in callback or blocking mode, we will respectively start or simply * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will * be started automatically as the user writes to output.  * * The capture pcm, however, will simply be prepared and started. * * PaAlsaStream::startMtx makes sure access is synchronized (useful in callback mode) */static PaError AlsaStart( PaAlsaStream *stream, int priming ){    PaError result = paNoError;    if( stream->pcm_playback )    {        if( stream->callback_mode )        {            /* We're not priming buffer, so prepare and silence */            if( !priming )            {                ENSURE( snd_pcm_prepare( stream->pcm_playback ), paUnanticipatedHostError );                SilenceBuffer( stream );            }            ENSURE( snd_pcm_start( stream->pcm_playback ), paUnanticipatedHostError );        }        else            ENSURE( snd_pcm_prepare( stream->pcm_playback ), paUnanticipatedHostError );    }    if( stream->pcm_capture && !stream->pcmsSynced )    {        ENSURE( snd_pcm_prepare( stream->pcm_capture ), paUnanticipatedHostError );        /* We want to start capture for a blocking stream as well, since nothing will happen otherwise */        ENSURE( snd_pcm_start( stream->pcm_capture ), paUnanticipatedHostError );    }end:    return result;error:    goto end;}/*! \brief Utility function for determining if pcms are in running state * */static int IsRunning( PaAlsaStream *stream ){    int result = 0;    pthread_mutex_lock( &stream->stateMtx ); /* Synchronize access to pcm state */    if( stream->pcm_capture )    {        snd_pcm_state_t capture_state = snd_pcm_state( stream->pcm_capture );        if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN                || capture_state == SND_PCM_STATE_DRAINING )        {            result = 1;            goto end;        }    }    if( stream->pcm_playback )    {        snd_pcm_state_t playback_state = snd_pcm_state( stream->pcm_playback );        if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN                || playback_state == SND_PCM_STATE_DRAINING )        {            result = 1;            goto end;        }    }end:    pthread_mutex_unlock( &stream->stateMtx );    return result;}static PaError StartStream( PaStream *s ){    PaError result = paNoError;    PaAlsaStream *stream = (PaAlsaStream*)s;    /* Ready the processor */    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );    /* Set now, so we can test for activity further down */    stream->isActive = 1;    if( stream->callback_mode )    {        int res = 0;        PaTime pt = PaUtil_GetTime();        struct timespec ts;        pthread_attr_t attr;        UNLESS( !pthread_attr_init( &attr ), paInternalError );        /* Priority relative to other processes */        UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );           UNLESS( !pthread_create( &stream->callback_thread, &attr, &CallbackThread, stream ), paInternalError );

⌨️ 快捷键说明

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