📄 alsa.c
字号:
psz_iec_device = psz_default_iec_device; } else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) ) { psz_iec_device = psz_device; } else { psz_iec_device = NULL; } /* Choose the linear PCM format (read the comment above about FPU and float32) */ if( vlc_CPU() & CPU_CAPABILITY_FPU ) { i_vlc_pcm_format = VLC_FOURCC('f','l','3','2'); i_snd_pcm_format = SND_PCM_FORMAT_FLOAT; } else { i_vlc_pcm_format = AOUT_FMT_S16_NE; i_snd_pcm_format = SND_PCM_FORMAT_S16; } /* If the variable doesn't exist then it's the first time we're called and we have to probe the available audio formats and channels */ if ( var_Type( p_aout, "audio-device" ) == 0 ) { Probe( p_aout, psz_device, psz_iec_device, &i_snd_pcm_format ); } if ( var_Get( p_aout, "audio-device", &val ) < 0 ) { free( p_sys ); free( psz_device ); return VLC_EGENERIC; } p_aout->output.output.i_format = i_vlc_pcm_format; if ( val.i_int == AOUT_VAR_5_1 ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; free( psz_device ); psz_device = strdup( "surround51" ); } else if ( val.i_int == AOUT_VAR_2F2R ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; free( psz_device ); psz_device = strdup( "surround40" ); } else if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; } else if( val.i_int != AOUT_VAR_SPDIF ) { /* This should not happen ! */ msg_Err( p_aout, "internal: can't find audio-device (%i)", val.i_int ); free( p_sys ); free( psz_device ); return VLC_EGENERIC; }#ifdef ALSA_DEBUG snd_output_stdio_attach( &p_sys->p_snd_stderr, stderr, 0 );#endif /* Open the device */ if ( val.i_int == AOUT_VAR_SPDIF ) { if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_iec_device, SND_PCM_STREAM_PLAYBACK, 0 ) ) < 0 ) { msg_Err( p_aout, "cannot open ALSA device `%s' (%s)", psz_iec_device, snd_strerror( i_snd_rc ) ); intf_UserFatal( p_aout, false, _("Audio output failed"), _("VLC could not open the ALSA device \"%s\" (%s)."), psz_iec_device, snd_strerror( i_snd_rc ) ); free( p_sys ); free( psz_device ); return VLC_EGENERIC; } i_buffer_size = ALSA_SPDIF_BUFFER_SIZE; i_snd_pcm_format = SND_PCM_FORMAT_S16; i_channels = 2; i_vlc_pcm_format = VLC_FOURCC('s','p','d','i'); p_aout->output.i_nb_samples = i_period_size = ALSA_SPDIF_PERIOD_SIZE; p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->output.output.i_frame_length = A52_FRAME_NB; aout_VolumeNoneInit( p_aout ); } else { int i; msg_Dbg( p_aout, "opening ALSA device `%s'", psz_device ); /* Since it seems snd_pcm_close hasn't really released the device at the time it returns, probe if the device is available in loop for 1s. We cannot use blocking mode since the we would wait indefinitely when switching from a dmx device to surround51. */ for( i = 10; i >= 0; i-- ) { if ( ( i_snd_rc = snd_pcm_open( &p_sys->p_snd_pcm, psz_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK ) ) == -EBUSY ) { if( i ) msleep( 100000 /* 100ms */ ); else { msg_Err( p_aout, "audio device: %s is already in use", psz_device ); intf_UserFatal( p_aout, false, _("Audio output failed"), _("The audio device \"%s\" is already in use."), psz_device ); } continue; } break; } if( i_snd_rc < 0 ) { msg_Err( p_aout, "cannot open ALSA device `%s' (%s)", psz_device, snd_strerror( i_snd_rc ) ); intf_UserFatal( p_aout, false, _("Audio output failed"), _("VLC could not open the ALSA device \"%s\" (%s)."), psz_device, snd_strerror( i_snd_rc ) ); free( p_sys ); free( psz_device ); return VLC_EGENERIC; } /* We want blocking mode */ snd_pcm_nonblock( p_sys->p_snd_pcm, 0 ); i_buffer_size = ALSA_DEFAULT_BUFFER_SIZE; i_channels = aout_FormatNbChannels( &p_aout->output.output ); p_aout->output.i_nb_samples = i_period_size = ALSA_DEFAULT_PERIOD_SIZE; aout_VolumeSoftInit( p_aout ); } /* Free psz_device so that all the remaining data is stack-allocated */ free( psz_device ); p_aout->output.pf_play = Play; snd_pcm_hw_params_alloca(&p_hw); snd_pcm_sw_params_alloca(&p_sw); /* Due to some bugs in alsa with some drivers, we need to retry in s16l if snd_pcm_hw_params fails in fl32 */ while ( b_retry ) { b_retry = false; /* Get Initial hardware parameters */ if ( ( i_snd_rc = snd_pcm_hw_params_any( p_sys->p_snd_pcm, p_hw ) ) < 0 ) { msg_Err( p_aout, "unable to retrieve initial hardware parameters (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Set format. */ if ( ( i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw, i_snd_pcm_format ) ) < 0 ) { if( i_snd_pcm_format != SND_PCM_FORMAT_S16 ) { i_snd_pcm_format = SND_PCM_FORMAT_S16; i_snd_rc = snd_pcm_hw_params_set_format( p_sys->p_snd_pcm, p_hw, i_snd_pcm_format ); } if ( i_snd_rc < 0 ) { msg_Err( p_aout, "unable to set stream sample size and " "word order (%s)", snd_strerror( i_snd_rc ) ); goto error; } } if( i_vlc_pcm_format != VLC_FOURCC('s','p','d','i') ) switch( i_snd_pcm_format ) { case SND_PCM_FORMAT_FLOAT: i_vlc_pcm_format = VLC_FOURCC('f','l','3','2'); break; case SND_PCM_FORMAT_S16: i_vlc_pcm_format = AOUT_FMT_S16_NE; break; } p_aout->output.output.i_format = i_vlc_pcm_format; if ( ( i_snd_rc = snd_pcm_hw_params_set_access( p_sys->p_snd_pcm, p_hw, SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 ) { msg_Err( p_aout, "unable to set interleaved stream format (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Set channels. */ if ( ( i_snd_rc = snd_pcm_hw_params_set_channels( p_sys->p_snd_pcm, p_hw, i_channels ) ) < 0 ) { msg_Err( p_aout, "unable to set number of output channels (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Set rate. */ i_old_rate = p_aout->output.output.i_rate;#ifdef HAVE_ALSA_NEW_API i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw, &p_aout->output.output.i_rate, NULL );#else i_snd_rc = snd_pcm_hw_params_set_rate_near( p_sys->p_snd_pcm, p_hw, p_aout->output.output.i_rate, NULL );#endif if( i_snd_rc < 0 || p_aout->output.output.i_rate != i_old_rate ) { msg_Warn( p_aout, "The rate %d Hz is not supported by your " \ "hardware. Using %d Hz instead.\n", i_old_rate, \ p_aout->output.output.i_rate ); } /* Set period size. */#ifdef HAVE_ALSA_NEW_API if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm, p_hw, &i_period_size, NULL ) ) < 0 )#else if ( ( i_snd_rc = snd_pcm_hw_params_set_period_size_near( p_sys->p_snd_pcm, p_hw, i_period_size, NULL ) ) < 0 )#endif { msg_Err( p_aout, "unable to set period size (%s)", snd_strerror( i_snd_rc ) ); goto error; } p_aout->output.i_nb_samples = i_period_size;/* Set buffer size. */#ifdef HAVE_ALSA_NEW_API if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm, p_hw, &i_buffer_size ) ) < 0 )#else if ( ( i_snd_rc = snd_pcm_hw_params_set_buffer_size_near( p_sys->p_snd_pcm, p_hw, i_buffer_size ) ) < 0 )#endif { msg_Err( p_aout, "unable to set buffer size (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Commit hardware parameters. */ if ( ( i_snd_rc = snd_pcm_hw_params( p_sys->p_snd_pcm, p_hw ) ) < 0 ) { if ( b_retry == false && i_snd_pcm_format == SND_PCM_FORMAT_FLOAT) { b_retry = true; i_snd_pcm_format = SND_PCM_FORMAT_S16; p_aout->output.output.i_format = AOUT_FMT_S16_NE; msg_Warn( p_aout, "unable to commit hardware configuration " "with fl32 samples. Retrying with s16l (%s)", snd_strerror( i_snd_rc ) ); } else { msg_Err( p_aout, "unable to commit hardware configuration (%s)", snd_strerror( i_snd_rc ) ); goto error; } } }#ifdef HAVE_ALSA_NEW_API if( ( i_snd_rc = snd_pcm_hw_params_get_period_time( p_hw, &p_sys->i_period_time, NULL ) ) < 0 )#else if( ( p_sys->i_period_time = (int)snd_pcm_hw_params_get_period_time( p_hw, NULL ) ) < 0 )#endif { msg_Err( p_aout, "unable to get period time (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Get Initial software parameters */ snd_pcm_sw_params_current( p_sys->p_snd_pcm, p_sw ); i_snd_rc = snd_pcm_sw_params_set_sleep_min( p_sys->p_snd_pcm, p_sw, 0 ); i_snd_rc = snd_pcm_sw_params_set_avail_min( p_sys->p_snd_pcm, p_sw, p_aout->output.i_nb_samples ); /* start playing when one period has been written */ i_snd_rc = snd_pcm_sw_params_set_start_threshold( p_sys->p_snd_pcm, p_sw, ALSA_DEFAULT_PERIOD_SIZE); if( i_snd_rc < 0 ) { msg_Err( p_aout, "unable to set start threshold (%s)", snd_strerror( i_snd_rc ) ); goto error; } /* Commit software parameters. */ if ( snd_pcm_sw_params( p_sys->p_snd_pcm, p_sw ) < 0 ) { msg_Err( p_aout, "unable to set software configuration" ); goto error; }#ifdef ALSA_DEBUG snd_output_printf( p_sys->p_snd_stderr, "\nALSA hardware setup:\n\n" ); snd_pcm_dump_hw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr ); snd_output_printf( p_sys->p_snd_stderr, "\nALSA software setup:\n\n" ); snd_pcm_dump_sw_setup( p_sys->p_snd_pcm, p_sys->p_snd_stderr ); snd_output_printf( p_sys->p_snd_stderr, "\n" );#endif /* Create ALSA thread and wait for its readiness. */ if( vlc_thread_create( p_aout, "aout", ALSAThread, VLC_THREAD_PRIORITY_OUTPUT, false ) ) { msg_Err( p_aout, "cannot create ALSA thread (%m)" ); goto error; } return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -