changeset 19889:d4bb39d65f87

When the hardware sample format is AC3, do not force using an hardcoded device name. The setting of the non-audio bit is now done by changing the default value of the AES0 parameter in the ALSA configuration structures. This works with user-specified devices, too.
author cladisch
date Mon, 18 Sep 2006 16:58:21 +0000
parents 2ce14efa8917
children 441f1e2d7559
files ChangeLog DOCS/man/en/mplayer.1 libao2/ao_alsa.c
diffstat 3 files changed, 64 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Sep 18 16:48:50 2006 +0000
+++ b/ChangeLog	Mon Sep 18 16:58:21 2006 +0000
@@ -7,6 +7,8 @@
 
     Drivers:
     * IVTV hardware MPEG audio/video decoder output
+    * ALSA audio output: AC3 passthrough now works even when the device name
+      of the digital output port has been set by the user
 
     Decoders:
     * liba52 updated to 0.7.4 (slightly faster)
--- a/DOCS/man/en/mplayer.1	Mon Sep 18 16:48:50 2006 +0000
+++ b/DOCS/man/en/mplayer.1	Mon Sep 18 16:58:21 2006 +0000
@@ -2359,7 +2359,7 @@
 .IPs device=<device>
 Sets the device name.
 Replace any ',' with '.' and any ':' with '=' in the ALSA device name.
-Make sure you do not set this when you want hwac3 output via S/PDIF, unless
+For hwac3 output via S/PDIF, use an "iec958" or "spdif" device, unless
 you really know how to set it correctly.
 .RE
 .PD 1
--- a/libao2/ao_alsa.c	Mon Sep 18 16:48:50 2006 +0000
+++ b/libao2/ao_alsa.c	Mon Sep 18 16:58:21 2006 +0000
@@ -265,6 +265,50 @@
   return 1;
 }
 
+/* change a PCM definition for correct AC-3 playback */
+static void set_non_audio(snd_config_t *root, const char *name_with_args)
+{
+  char *name, *colon, *old_value_str;
+  snd_config_t *config, *args, *aes0, *old_def, *def;
+  int value, err;
+
+  /* strip the parameters from the PCM name */
+  if ((name = strdup(name_with_args)) != NULL) {
+    if ((colon = strchr(name, ':')) != NULL)
+      *colon = '\0';
+    /* search the PCM definition that we'll later use */
+    if (snd_config_search_alias_hooks(root, strchr(name, '.') ? NULL : "pcm",
+				      name, &config) >= 0) {
+      /* does this definition have an "AES0" parameter? */
+      if (snd_config_search(config, "@args", &args) >= 0 &&
+	  snd_config_search(args, "AES0", &aes0) >= 0) {
+	/* read the old default value */
+	value = IEC958_AES0_CON_NOT_COPYRIGHT |
+		IEC958_AES0_CON_EMPHASIS_NONE;
+	if (snd_config_search(aes0, "default", &old_def) >= 0) {
+	  /* don't use snd_config_get_integer() because alsa-lib <= 1.0.12
+	   * parses hex numbers as strings */
+	  if (snd_config_get_ascii(old_def, &old_value_str) >= 0) {
+	    sscanf(old_value_str, "%i", &value);
+	    free(old_value_str);
+	  }
+	} else
+	  old_def = NULL;
+	/* set the non-audio bit */
+	value |= IEC958_AES0_NONAUDIO;
+	/* set the new default value */
+	if (snd_config_imake_integer(&def, "default", value) >= 0) {
+	  if (old_def)
+	    snd_config_substitute(old_def, def);
+	  else
+	    snd_config_add(aes0, def);
+	}
+      }
+    }
+    free(name);
+  }
+}
+
 /*
     open & setup audio device
     return: 1=success 0=fail
@@ -274,6 +318,7 @@
     int err;
     int block;
     strarg_t device;
+    snd_config_t *my_config;
     snd_pcm_uframes_t bufsize;
     snd_pcm_uframes_t boundary;
     opt_t subopts[] = {
@@ -367,20 +412,7 @@
      * 'iec958'
      */
     if (format == AF_FORMAT_AC3) {
-      unsigned char s[4];
-
-	s[0] = IEC958_AES0_NONAUDIO | 
-	  IEC958_AES0_CON_EMPHASIS_NONE;
-	s[1] = IEC958_AES1_CON_ORIGINAL | 
-	  IEC958_AES1_CON_PCM_CODER;
-	s[2] = 0;
-	s[3] = IEC958_AES3_CON_FS_48000;
-
-	snprintf(alsa_device, ALSA_DEVICE_SIZE,
-		"iec958:{CARD 0 AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}", 
- 		s[0], s[1], s[2], s[3]);
-	device.str = alsa_device;
-
+	device.str = "iec958";
 	mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %i channels\n", channels);
     }
   else
@@ -466,12 +498,24 @@
     }
 
     if (!alsa_handler) {
+      if ((err = snd_config_update()) < 0) {
+	mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: cannot read ALSA configuration: %s\n", snd_strerror(err));
+	return 0;
+      }
+      if ((err = snd_config_copy(&my_config, snd_config)) < 0) {
+	mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: cannot copy configuration: %s\n", snd_strerror(err));
+	return 0;
+      }
+      if (format == AF_FORMAT_AC3)
+	set_non_audio(my_config, alsa_device);
       //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
-      if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0)
+      if ((err = snd_pcm_open_lconf(&alsa_handler, alsa_device,
+				    SND_PCM_STREAM_PLAYBACK, open_mode, my_config)) < 0)
 	{
 	  if (err != -EBUSY && ao_noblock) {
 	    mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: open in nonblock-mode failed, trying to open in block-mode\n");
-	    if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+	    if ((err = snd_pcm_open_lconf(&alsa_handler, alsa_device,
+					  SND_PCM_STREAM_PLAYBACK, 0, my_config)) < 0) {
 	      mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: playback open error: %s\n", snd_strerror(err));
 	      return(0);
 	    }
@@ -480,6 +524,7 @@
 	    return(0);
 	  }
 	}
+      snd_config_delete(my_config);
 
       if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) {
          mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: error set block-mode %s\n", snd_strerror(err));