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

📄 alsa.c

📁 VLC Player Source Code
💻 C
📖 第 1 页 / 共 3 页
字号:
error:    snd_pcm_close( p_sys->p_snd_pcm );#ifdef ALSA_DEBUG    snd_output_close( p_sys->p_snd_stderr );#endif    free( p_sys );    return VLC_EGENERIC;}/***************************************************************************** * Play: nothing to do *****************************************************************************/static void Play( aout_instance_t *p_aout ){    if( !p_aout->output.p_sys->b_playing )    {        p_aout->output.p_sys->b_playing = 1;        /* get the playing date of the first aout buffer */        p_aout->output.p_sys->start_date =            aout_FifoFirstDate( p_aout, &p_aout->output.fifo );        /* wake up the audio output thread */        vlc_mutex_lock( &p_aout->output.p_sys->lock );        vlc_cond_signal( &p_aout->output.p_sys->wait );        vlc_mutex_unlock( &p_aout->output.p_sys->lock );    }}/***************************************************************************** * Close: close the ALSA device *****************************************************************************/static void Close( vlc_object_t *p_this ){    aout_instance_t *p_aout = (aout_instance_t *)p_this;    struct aout_sys_t * p_sys = p_aout->output.p_sys;    int i_snd_rc;    /* Make sure that the thread will stop once it is waken up */    vlc_object_kill( p_aout );    /* make sure the audio output thread is waken up */    vlc_mutex_lock( &p_aout->output.p_sys->lock );    vlc_cond_signal( &p_aout->output.p_sys->wait );    vlc_mutex_unlock( &p_aout->output.p_sys->lock );    /* */    vlc_thread_join( p_aout );    p_aout->b_die = false;    i_snd_rc = snd_pcm_close( p_sys->p_snd_pcm );    if( i_snd_rc > 0 )    {        msg_Err( p_aout, "failed closing ALSA device (%s)",                         snd_strerror( i_snd_rc ) );    }#ifdef ALSA_DEBUG    snd_output_close( p_sys->p_snd_stderr );#endif    free( p_sys );}/***************************************************************************** * ALSAThread: asynchronous thread used to DMA the data to the device *****************************************************************************/static void* ALSAThread( vlc_object_t* p_this ){    aout_instance_t * p_aout = (aout_instance_t*)p_this;    struct aout_sys_t * p_sys = p_aout->output.p_sys;    p_sys->p_status = (snd_pcm_status_t *)malloc(snd_pcm_status_sizeof());    /* Wait for the exact time to start playing (avoids resampling) */    vlc_mutex_lock( &p_sys->lock );    while( !p_sys->start_date && vlc_object_alive (p_aout) )        vlc_cond_wait( &p_sys->wait, &p_sys->lock );    vlc_mutex_unlock( &p_sys->lock );    if( !vlc_object_alive (p_aout) )    	goto cleanup;    mwait( p_sys->start_date - AOUT_PTS_TOLERANCE / 4 );    while ( vlc_object_alive (p_aout) )    {        ALSAFill( p_aout );    }cleanup:    snd_pcm_drop( p_sys->p_snd_pcm );    free( p_aout->output.p_sys->p_status );    return NULL;}/***************************************************************************** * ALSAFill: function used to fill the ALSA buffer as much as possible *****************************************************************************/static void ALSAFill( aout_instance_t * p_aout ){    struct aout_sys_t * p_sys = p_aout->output.p_sys;    aout_buffer_t * p_buffer;    snd_pcm_status_t * p_status = p_sys->p_status;    int i_snd_rc;    mtime_t next_date;    /* Fill in the buffer until space or audio output buffer shortage */    /* Get the status */    i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );    if( i_snd_rc < 0 )    {        msg_Err( p_aout, "cannot get device status" );        goto error;    }    /* Handle buffer underruns and get the status again */    if( snd_pcm_status_get_state( p_status ) == SND_PCM_STATE_XRUN )    {        /* Prepare the device */        i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );        if( i_snd_rc )        {            msg_Err( p_aout, "cannot recover from buffer underrun" );            goto error;        }        msg_Dbg( p_aout, "recovered from buffer underrun" );        /* Get the new status */        i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status );        if( i_snd_rc < 0 )        {            msg_Err( p_aout, "cannot get device status after recovery" );            goto error;        }        /* Underrun, try to recover as quickly as possible */        next_date = mdate();    }    else    {        /* Here the device should be in RUNNING state, p_status is valid. */        snd_pcm_sframes_t delay = snd_pcm_status_get_delay( p_status );        if( delay == 0 ) /* workaround buggy alsa drivers */            if( snd_pcm_delay( p_sys->p_snd_pcm, &delay ) < 0 )                delay = 0; /* FIXME: use a positive minimal delay */        int i_bytes = snd_pcm_frames_to_bytes( p_sys->p_snd_pcm, delay );        next_date = mdate() + ( (mtime_t)i_bytes * 1000000                / p_aout->output.output.i_bytes_per_frame                / p_aout->output.output.i_rate                * p_aout->output.output.i_frame_length );#ifdef ALSA_DEBUG        snd_pcm_state_t state = snd_pcm_status_get_state( p_status );        if( state != SND_PCM_STATE_RUNNING )            msg_Err( p_aout, "pcm status (%d) != RUNNING", state );        msg_Dbg( p_aout, "Delay is %ld frames (%d bytes)", delay, i_bytes );        msg_Dbg( p_aout, "Bytes per frame: %d", p_aout->output.output.i_bytes_per_frame );        msg_Dbg( p_aout, "Rate: %d", p_aout->output.output.i_rate );        msg_Dbg( p_aout, "Frame length: %d", p_aout->output.output.i_frame_length );        msg_Dbg( p_aout, "Next date is in %d microseconds", (int)(next_date - mdate()) );#endif    }    p_buffer = aout_OutputNextBuffer( p_aout, next_date,           (p_aout->output.output.i_format ==  VLC_FOURCC('s','p','d','i')) );    /* Audio output buffer shortage -> stop the fill process and wait */    if( p_buffer == NULL )        goto error;    for (;;)    {        i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer,                                   p_buffer->i_nb_samples );        if( i_snd_rc != -ESTRPIPE )            break;        /* a suspend event occurred         * (stream is suspended and waiting for an application recovery) */        msg_Dbg( p_aout, "entering in suspend mode, trying to resume..." );        while( vlc_object_alive (p_aout) && vlc_object_alive (p_aout->p_libvlc) &&               ( i_snd_rc = snd_pcm_resume( p_sys->p_snd_pcm ) ) == -EAGAIN )        {            msleep( 1000000 );        }        if( i_snd_rc < 0 )            /* Device does not supprot resuming, restart it */            i_snd_rc = snd_pcm_prepare( p_sys->p_snd_pcm );    }    if( i_snd_rc < 0 )        msg_Err( p_aout, "cannot write: %s", snd_strerror( i_snd_rc ) );    aout_BufferFree( p_buffer );    return;error:    if( i_snd_rc < 0 )        msg_Err( p_aout, "ALSA error: %s", snd_strerror( i_snd_rc ) );    msleep( p_sys->i_period_time >> 1 );}static void GetDevicesForCard( module_config_t *p_item, int i_card );static void GetDevices( module_config_t *p_item );/***************************************************************************** * config variable callback *****************************************************************************/static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,                               vlc_value_t newval, vlc_value_t oldval, void *p_unused ){    module_config_t *p_item;    int i;    (void)newval;    (void)oldval;    (void)p_unused;    p_item = config_FindConfig( p_this, psz_name );    if( !p_item ) return VLC_SUCCESS;    /* Clear-up the current list */    if( p_item->i_list )    {        /* Keep the first entrie */        for( i = 1; i < p_item->i_list; i++ )        {            free( (char *)p_item->ppsz_list[i] );            free( (char *)p_item->ppsz_list_text[i] );        }        /* TODO: Remove when no more needed */        p_item->ppsz_list[i] = NULL;        p_item->ppsz_list_text[i] = NULL;    }    p_item->i_list = 1;    GetDevices( p_item );    /* Signal change to the interface */    p_item->b_dirty = true;    return VLC_SUCCESS;}static void GetDevicesForCard( module_config_t *p_item, int i_card ){    int i_pcm_device = -1;    int i_err = 0;    snd_pcm_info_t *p_pcm_info;    snd_ctl_t *p_ctl;    char psz_dev[64];    char *psz_card_name;    sprintf( psz_dev, "hw:%i", i_card );    if( ( i_err = snd_ctl_open( &p_ctl, psz_dev, 0 ) ) < 0 )        return;    if( ( i_err = snd_card_get_name( i_card, &psz_card_name ) ) != 0)        psz_card_name = _("Unknown soundcard");    snd_pcm_info_alloca( &p_pcm_info );    for (;;)    {        char *psz_device, *psz_descr;        if( ( i_err = snd_ctl_pcm_next_device( p_ctl, &i_pcm_device ) ) < 0 )            i_pcm_device = -1;        if( i_pcm_device < 0 )            break;        snd_pcm_info_set_device( p_pcm_info, i_pcm_device );        snd_pcm_info_set_subdevice( p_pcm_info, 0 );        snd_pcm_info_set_stream( p_pcm_info, SND_PCM_STREAM_PLAYBACK );        if( ( i_err = snd_ctl_pcm_info( p_ctl, p_pcm_info ) ) < 0 )        {            if( i_err != -ENOENT )            {                /*printf( "get_devices_for_card(): "                         "snd_ctl_pcm_info() "                         "failed (%d:%d): %s.\n", i_card,                         i_pcm_device, snd_strerror( -i_err ) );*/            }            continue;        }        if( asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ) == -1 )            break;        if( asprintf( &psz_descr, "%s: %s (%s)", psz_card_name,                  snd_pcm_info_get_name(p_pcm_info), psz_device ) == -1 )        {            free( psz_device );            break;        }        p_item->ppsz_list =            (char **)realloc( p_item->ppsz_list,                              (p_item->i_list + 2) * sizeof(char *) );        p_item->ppsz_list_text =            (char **)realloc( p_item->ppsz_list_text,                              (p_item->i_list + 2) * sizeof(char *) );        p_item->ppsz_list[ p_item->i_list ] = psz_device;        p_item->ppsz_list_text[ p_item->i_list ] = psz_descr;        p_item->i_list++;        p_item->ppsz_list[ p_item->i_list ] = NULL;        p_item->ppsz_list_text[ p_item->i_list ] = NULL;    }    snd_ctl_close( p_ctl );}static void GetDevices( module_config_t *p_item ){    int i_card = -1;    int i_err = 0;    if( ( i_err = snd_card_next( &i_card ) ) != 0 )    {        /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/        return;    }    while( i_card > -1 )    {        GetDevicesForCard( p_item, i_card );        if( ( i_err = snd_card_next( &i_card ) ) != 0 )        {            /*printf( "snd_card_next() failed: %s", snd_strerror( -i_err ) );*/            break;        }    }}

⌨️ 快捷键说明

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