📄 alsa.c
字号:
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 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 ); p_aout->b_die = VLC_TRUE; vlc_thread_join( p_aout ); p_aout->b_die = VLC_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->p_status ); free( p_sys );}/***************************************************************************** * ALSAThread: asynchronous thread used to DMA the data to the device *****************************************************************************/static int ALSAThread( aout_instance_t * p_aout ){ /* Wait for the exact time to start playing (avoids resampling) */ vlc_mutex_lock( &p_aout->output.p_sys->lock ); if( !p_aout->output.p_sys->start_date ) vlc_cond_wait( &p_aout->output.p_sys->wait, &p_aout->output.p_sys->lock ); vlc_mutex_unlock( &p_aout->output.p_sys->lock ); mwait( p_aout->output.p_sys->start_date - AOUT_PTS_TOLERANCE / 4 ); while ( !p_aout->b_die ) { ALSAFill( p_aout ); } return 0;}/***************************************************************************** * 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; snd_timestamp_t ts_next; 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, "unable to get the device's status (%s)", snd_strerror( i_snd_rc ) ); msleep( p_sys->i_period_time >> 1 ); return; } /* Handle buffer underruns and reget the status */ 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 == 0 ) { msg_Warn( p_aout, "recovered from buffer underrun" ); /* Reget the status */ i_snd_rc = snd_pcm_status( p_sys->p_snd_pcm, p_status ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "unable to get the device's status after " "recovery (%s)", snd_strerror( i_snd_rc ) ); msleep( p_sys->i_period_time >> 1 ); return; } } else { msg_Err( p_aout, "unable to recover from buffer underrun" ); msleep( p_sys->i_period_time >> 1 ); return; } /* Underrun, try to recover as quickly as possible */ next_date = mdate(); } else { /* Here the device should be either in the RUNNING state. * p_status is valid. */ snd_pcm_status_get_tstamp( p_status, &ts_next ); next_date = (mtime_t)ts_next.tv_sec * 1000000 + ts_next.tv_usec; if( next_date ) { next_date += (mtime_t)snd_pcm_status_get_delay(p_status) * 1000000 / p_aout->output.output.i_rate; } else { /* With screwed ALSA drivers the timestamp is always zero; * use another method then */ snd_pcm_sframes_t delay; ssize_t i_bytes = 0; if( !snd_pcm_delay( p_sys->p_snd_pcm, &delay ) ) { 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; } } 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 ) { msleep( p_sys->i_period_time >> 1 ); return; } i_snd_rc = snd_pcm_writei( p_sys->p_snd_pcm, p_buffer->p_buffer, p_buffer->i_nb_samples ); if( i_snd_rc < 0 ) { msg_Err( p_aout, "write failed (%s)", snd_strerror( i_snd_rc ) ); } aout_BufferFree( p_buffer ); }}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; 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( p_item->ppsz_list[i] ); free( 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 = VLC_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; } asprintf( &psz_device, "hw:%d,%d", i_card, i_pcm_device ); asprintf( &psz_descr, "%s: %s (%s)", psz_card_name, snd_pcm_info_get_name(p_pcm_info), psz_device ); 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) {// g_warning("snd_next_card() failed: %s", snd_strerror(-err)); return; } while (i_card > -1) { GetDevicesForCard(p_item, i_card); if ((i_err = snd_card_next(&i_card)) != 0) {// g_warning("snd_next_card() failed: %s",// snd_strerror(-err)); break; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -