Commit 119c3fc9 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

ALSA: add configuration item for channels, remove broken autodetection

There is no reliable way to determine the channel configuration of a
certain ALSA device. The ALSA operates at too low level for that.
So add a configuration option with default to stereo (as in previous
VLC versions). However, the user will not need to re-enable 5.1 every
time.

This commit also removes all the fancy device choices. The static
choices are overriden dynamically by the UI anyway. So the only use of
the list was in vlc --help.
parent 75977c87
...@@ -47,33 +47,32 @@ struct aout_sys_t ...@@ -47,33 +47,32 @@ struct aout_sys_t
#define A52_FRAME_NB 1536 #define A52_FRAME_NB 1536
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Open (vlc_object_t *); static int Open (vlc_object_t *);
static void Close (vlc_object_t *); static void Close (vlc_object_t *);
static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name, static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
vlc_value_t newval, vlc_value_t oldval, void *p_unused ); vlc_value_t newval, vlc_value_t oldval, void *p_unused );
static void GetDevices (vlc_object_t *, module_config_t *, const char *); static void GetDevices (vlc_object_t *, module_config_t *, const char *);
/***************************************************************************** #define AUDIO_DEV_TEXT N_("Audio output device")
* Module descriptor #define AUDIO_DEV_LONGTEXT N_("Audio output device (using ALSA syntax).")
*****************************************************************************/ static const char *const devices[] = {
static const char *const ppsz_devices[] = { "default",
"default", "plug:front", };
"plug:side", "plug:rear", "plug:center_lfe", static const char *const devices_text[] = {
"plug:surround40", "plug:surround41", N_("Default"),
"plug:surround50", "plug:surround51",
"plug:surround71",
"hdmi", "iec958",
}; };
static const char *const ppsz_devices_text[] = {
N_("Default"), N_("Front speakers"), #define AUDIO_CHAN_TEXT N_("Audio output channels")
N_("Side speakers"), N_("Rear speakers"), N_("Center and subwoofer"), #define AUDIO_CHAN_LONGTEXT N_("Channels available for audio output." \
N_("Surround 4.0"), N_("Surround 4.1"), "If the input has more channels than the output, it will be down-mixed." \
"This parameter is ignored when digital pass-through is active.")
static const int channels[] = {
AOUT_CHAN_CENTER, AOUT_CHANS_STEREO, AOUT_CHANS_4_0, AOUT_CHANS_4_1,
AOUT_CHANS_5_0, AOUT_CHANS_5_1,
};
static const char *const channels_text[] = {
N_("Mono"), N_("Stereo"), N_("Surround 4.0"), N_("Surround 4.1"),
N_("Surround 5.0"), N_("Surround 5.1"), N_("Surround 5.0"), N_("Surround 5.1"),
N_("Surround 7.1"),
N_("HDMI"), N_("S/PDIF"),
}; };
vlc_module_begin () vlc_module_begin ()
...@@ -81,10 +80,13 @@ vlc_module_begin () ...@@ -81,10 +80,13 @@ vlc_module_begin ()
set_description( N_("ALSA audio output") ) set_description( N_("ALSA audio output") )
set_category( CAT_AUDIO ) set_category( CAT_AUDIO )
set_subcategory( SUBCAT_AUDIO_AOUT ) set_subcategory( SUBCAT_AUDIO_AOUT )
add_string ("alsa-audio-device", "default", N_("ALSA device"), NULL, false) add_string ("alsa-audio-device", "default",
change_string_list( ppsz_devices, ppsz_devices_text, FindDevicesCallback ) AUDIO_DEV_TEXT, AUDIO_DEV_LONGTEXT, false)
change_string_list( devices, devices_text, FindDevicesCallback )
change_action_add( FindDevicesCallback, N_("Refresh list") ) change_action_add( FindDevicesCallback, N_("Refresh list") )
add_integer ("alsa-audio-channels", AOUT_CHANS_FRONT,
AUDIO_CHAN_TEXT, AUDIO_CHAN_LONGTEXT, false)
change_integer_list (channels, channels_text)
set_capability( "audio output", 150 ) set_capability( "audio output", 150 )
set_callbacks( Open, Close ) set_callbacks( Open, Close )
vlc_module_end () vlc_module_end ()
...@@ -244,6 +246,12 @@ static int Open (vlc_object_t *obj) ...@@ -244,6 +246,12 @@ static int Open (vlc_object_t *obj)
default: default:
if (AOUT_FMT_SPDIF(&aout->format)) if (AOUT_FMT_SPDIF(&aout->format))
spdif = var_InheritBool (aout, "spdif"); spdif = var_InheritBool (aout, "spdif");
if (spdif)
{
fourcc = VLC_CODEC_SPDIFL;
pcm_format = SND_PCM_FORMAT_S16;
}
else
if (HAVE_FPU) if (HAVE_FPU)
{ {
fourcc = VLC_CODEC_FL32; fourcc = VLC_CODEC_FL32;
...@@ -256,6 +264,20 @@ static int Open (vlc_object_t *obj) ...@@ -256,6 +264,20 @@ static int Open (vlc_object_t *obj)
} }
} }
/* ALSA channels */
/* XXX: maybe this should be shared with other dumb outputs */
uint32_t map = var_InheritInteger (aout, "alsa-audio-channels");
map &= aout->format.i_physical_channels;
if (unlikely(map == 0)) /* WTH? */
map = AOUT_CHANS_STEREO;
unsigned channels = popcount (map);
if (channels < aout_FormatNbChannels (&aout->format))
msg_Dbg (aout, "downmixing from %u to %u channels",
aout_FormatNbChannels (&aout->format), channels);
else
msg_Dbg (aout, "keeping %u channels", channels);
/* Choose the IEC device for S/PDIF output: /* Choose the IEC device for S/PDIF output:
if the device is overridden by the user then it will be the one. if the device is overridden by the user then it will be the one.
Otherwise we compute the default device based on the output format. */ Otherwise we compute the default device based on the output format. */
...@@ -299,8 +321,6 @@ static int Open (vlc_object_t *obj) ...@@ -299,8 +321,6 @@ static int Open (vlc_object_t *obj)
snd_pcm_t *pcm; snd_pcm_t *pcm;
/* VLC always has a resampler. No need for ALSA's. */ /* VLC always has a resampler. No need for ALSA's. */
const int mode = SND_PCM_NO_AUTO_RESAMPLE const int mode = SND_PCM_NO_AUTO_RESAMPLE
/* ALSA discards extra channels (by default). This is not good. */
| SND_PCM_NO_AUTO_CHANNELS
/* VLC is currently unable to leverage ALSA softvol. No need for it. */ /* VLC is currently unable to leverage ALSA softvol. No need for it. */
| SND_PCM_NO_SOFTVOL; | SND_PCM_NO_SOFTVOL;
...@@ -344,16 +364,6 @@ static int Open (vlc_object_t *obj) ...@@ -344,16 +364,6 @@ static int Open (vlc_object_t *obj)
msg_Dbg (aout, "using ALSA device: %s", device); msg_Dbg (aout, "using ALSA device: %s", device);
DumpDevice (VLC_OBJECT(aout), pcm); DumpDevice (VLC_OBJECT(aout), pcm);
/* Setup */
unsigned channels = aout_FormatNbChannels (&aout->format);
if (spdif)
{
fourcc = VLC_CODEC_SPDIFL;
pcm_format = SND_PCM_FORMAT_S16;
channels = 2;
}
/* Get Initial hardware parameters */ /* Get Initial hardware parameters */
snd_pcm_hw_params_t *hw; snd_pcm_hw_params_t *hw;
unsigned param; unsigned param;
...@@ -390,45 +400,18 @@ static int Open (vlc_object_t *obj) ...@@ -390,45 +400,18 @@ static int Open (vlc_object_t *obj)
} }
/* Set channels count */ /* Set channels count */
unsigned chans; /* By default, ALSA plug will pad missing channels with zeroes, which is
/* By default, ALSA plug will discard extra channels and zero missing ones * usually fine. However, it will also discard extraneous channels, which
* instead of remixing, so remixing was disabled at snd_pcm_open() above. * is not acceptable. Thus the user must configure the physically
* Then, the configuration space will contain only channels configurations * available channels, and VLC will downmix if needed. */
* supported by the audio device, but not necessarily functional (e.g. val = snd_pcm_hw_params_set_channels (pcm, hw, channels);
* surround-capable card with stereo speakers). */ if (val)
/* If there is only channels configuration, use that one.
* This should deal with "surround40", "surround51" and "surround71". */
if (snd_pcm_hw_params_get_channels (hw, &chans) == 0)
;
/* Otherwise, if we have 5 channels and they are supported, use that.
* This should deal with "surround41" and "surround50" routers.
* This assumes that no real hardware supports exactly 5 channels. */
else if (channels == 5
&& snd_pcm_hw_params_set_channels (pcm, hw, channels))
chans = channels;
/* Otherwise, if stereo is supported, then use that. This deals with
* the "front" device that fails to enforce stereo on Surround cards. */
else if (snd_pcm_hw_params_set_channels (pcm, hw, 2) == 0)
chans = 2;
/* Out of desperation, try the original channels count. */
else if (snd_pcm_hw_params_set_channels (pcm, hw, channels) == 0)
;
/* As last chance, try anything. */
else
{ {
chans = channels; msg_Err (aout, "cannot set %u channels: %s", channels,
val = snd_pcm_hw_params_set_channels_near (pcm, hw, &chans); snd_strerror (val));
if (val) goto error;
{
msg_Err (aout, "cannot set channels count: %s",
snd_strerror (val));
goto error;
}
} }
if (channels != chans)
msg_Dbg (aout, "remixing from %u to %u channels", channels, chans);
/* Set sample rate */ /* Set sample rate */
unsigned rate = aout->format.i_rate; unsigned rate = aout->format.i_rate;
val = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, NULL); val = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, NULL);
...@@ -508,48 +491,6 @@ static int Open (vlc_object_t *obj) ...@@ -508,48 +491,6 @@ static int Open (vlc_object_t *obj)
goto error; goto error;
} }
/* Guess the channel map */
switch (chans)
{
case 1:
chans = AOUT_CHAN_CENTER;
break;
case 2: /* front */
chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
break;
case 4: /* surround40 */
chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
break;
case 5: /* surround50 ... or surround41! Uho! */
#if 1
chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
| AOUT_CHAN_LFE;
#else
chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
| AOUT_CHAN_CENTER;
#endif
break;
case 6: /* surround51 */
chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
| AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
break;
#if 0 /* FIXME reorder */
case 8: /* surround71 */
chans = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
| AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
| AOUT_CHAN_CENTER | AOUT_CHAN_LFE
| AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT;
break;
#endif
default:
msg_Err (aout, "unknown %u channels configuration", chans);
goto error;
}
/* Setup audio_output_t */ /* Setup audio_output_t */
aout->format.i_format = fourcc; aout->format.i_format = fourcc;
aout->format.i_rate = rate; aout->format.i_rate = rate;
...@@ -562,7 +503,7 @@ static int Open (vlc_object_t *obj) ...@@ -562,7 +503,7 @@ static int Open (vlc_object_t *obj)
else else
{ {
aout->format.i_original_channels = aout->format.i_original_channels =
aout->format.i_physical_channels = chans; aout->format.i_physical_channels = map;
aout_VolumeSoftInit (aout); aout_VolumeSoftInit (aout);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment