All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: Clemens Ladisch <clemens@ladisch.de>
Cc: Jean-Marc Valin <jean-marc.valin@hermes.usherb.ca>,
	alsa-devel@lists.sourceforge.net
Subject: Re: [Alsa-user] No sound on Extigy
Date: Thu, 23 Jan 2003 14:23:44 +0100	[thread overview]
Message-ID: <s5h65sgyp7j.wl@alsa2.suse.de> (raw)
In-Reply-To: <s5hbs28yx2p.wl@alsa2.suse.de>

[-- Attachment #1: Type: text/plain, Size: 663 bytes --]

(moved to alsa-devel up to now...)

At Thu, 23 Jan 2003 11:33:50 +0100,
I wrote:
> 
> At Thu, 23 Jan 2003 11:26:02 +0100 (MET),
> Clemens Ladisch wrote:
> > 
> > The default output device used by aplay is "hw:0", which doesn't
> > automatically convert sample rates. Try "aplay -D plughw:0 something.wav".
> 
> i'm afraid that it doesn't work, too, because this configuration is
> not handled well.  anyway please try once.
> 
> it's tough to solve...

if the original usb-audio driver doesn't work with plughw like above,
please try the attached patch.

it will show many debug messages.  you can suppress it by undefining
HW_CONST_DEBUG at line 1167.


Takashi

[-- Attachment #2: usb-const.dif --]
[-- Type: application/octet-stream, Size: 8361 bytes --]

Index: alsa-kernel/usb/usbaudio.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/usb/usbaudio.c,v
retrieving revision 1.38
diff -u -r1.38 usbaudio.c
--- alsa-kernel/usb/usbaudio.c	22 Jan 2003 15:46:51 -0000	1.38
+++ alsa-kernel/usb/usbaudio.c	23 Jan 2003 13:19:44 -0000
@@ -36,7 +36,7 @@
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
-#include <sound/seq_device.h>
+#include <sound/pcm_params.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
 
@@ -1161,12 +1161,243 @@
 };
 
 /*
+ * h/w constraints
+ */
+
+#define HW_CONST_DEBUG
+
+static int hw_check_valid_format(snd_pcm_hw_params_t *params, struct audioformat *fp)
+{
+	snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	snd_interval_t *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	snd_mask_t *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+	/* check the format */
+	if (! snd_mask_test(fmts, fp->format))
+		return 0;
+	/* check the channels */
+	if (fp->channels < ct->min || fp->channels > ct->max)
+		return 0;
+	/* check the rate is within the range */
+	if (fp->rate_min > it->max || (fp->rate_min == it->max && !it->openmax))
+		return 0;
+	if (fp->rate_max < it->min || (fp->rate_max == it->min && !it->openmin))
+		return 0;
+	return 1;
+}
+
+static int hw_rule_rate(snd_pcm_hw_params_t *params,
+			snd_pcm_hw_rule_t *rule)
+{
+	snd_usb_substream_t *subs = rule->private;
+	struct list_head *p;
+	snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	int rmin, rmax, changed;
+	
+#ifdef HW_CONST_DEBUG
+	printk(KERN_DEBUG "hw_rule_rate: (%d,%d)\n", it->min, it->max);
+#endif
+	changed = 0;
+	rmin = rmax = 0;
+	list_for_each(p, &subs->fmt_list) {
+		struct audioformat *fp;
+		fp = list_entry(p, struct audioformat, list);
+		if (! hw_check_valid_format(params, fp))
+			continue;
+		if (changed++) {
+			if (rmin > fp->rate_min)
+				rmin = fp->rate_min;
+			if (rmax < fp->rate_max)
+				rmax = fp->rate_max;
+		} else {
+			rmin = fp->rate_min;
+			rmax = fp->rate_max;
+		}
+	}
+
+	if (! changed) {
+#ifdef HW_CONST_DEBUG
+		printk(KERN_DEBUG "  --> get empty\n");
+#endif
+		it->empty = 1;
+		return -EINVAL;
+	}
+
+	changed = 0;
+	if (it->min < rmin) {
+		it->min = rmin;
+		it->openmin = 0;
+		changed = 1;
+	}
+	if (it->max > rmax) {
+		it->max = rmax;
+		it->openmax = 0;
+		changed = 1;
+	}
+	if (snd_interval_checkempty(it)) {
+		it->empty = 1;
+		return -EINVAL;
+	}
+#ifdef HW_CONST_DEBUG
+	printk(KERN_DEBUG "  --> (%d, %d) (changed = %d)\n", it->min, it->max, changed);
+#endif
+	return changed;
+}
+
+
+static int hw_rule_channels(snd_pcm_hw_params_t *params,
+			    snd_pcm_hw_rule_t *rule)
+{
+	snd_usb_substream_t *subs = rule->private;
+	struct list_head *p;
+	snd_interval_t *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	int rmin, rmax, changed;
+	
+#ifdef HW_CONST_DEBUG
+	printk(KERN_DEBUG "hw_rule_channels: (%d,%d)\n", it->min, it->max);
+#endif
+	changed = 0;
+	rmin = rmax = 0;
+	list_for_each(p, &subs->fmt_list) {
+		struct audioformat *fp;
+		fp = list_entry(p, struct audioformat, list);
+		if (! hw_check_valid_format(params, fp))
+			continue;
+		if (changed++) {
+			if (rmin > fp->channels)
+				rmin = fp->channels;
+			if (rmax < fp->channels)
+				rmax = fp->channels;
+		} else {
+			rmin = fp->channels;
+			rmax = fp->channels;
+		}
+	}
+
+	if (! changed) {
+#ifdef HW_CONST_DEBUG
+		printk(KERN_DEBUG "  --> get empty\n");
+#endif
+		it->empty = 1;
+		return -EINVAL;
+	}
+
+	changed = 0;
+	if (it->min < rmin) {
+		it->min = rmin;
+		it->openmin = 0;
+		changed = 1;
+	}
+	if (it->max > rmax) {
+		it->max = rmax;
+		it->openmax = 0;
+		changed = 1;
+	}
+	if (snd_interval_checkempty(it)) {
+		it->empty = 1;
+		return -EINVAL;
+	}
+#ifdef HW_CONST_DEBUG
+	printk(KERN_DEBUG "  --> (%d, %d) (changed = %d)\n", it->min, it->max, changed);
+#endif
+	return changed;
+}
+
+static int hw_rule_format(snd_pcm_hw_params_t *params,
+			  snd_pcm_hw_rule_t *rule)
+{
+	snd_usb_substream_t *subs = rule->private;
+	struct list_head *p;
+	snd_mask_t *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+	u64 fbits;
+	u32 oldbits[2];
+	int changed;
+	
+#ifdef HW_CONST_DEBUG
+	printk(KERN_DEBUG "hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]);
+#endif
+	fbits = 0;
+	list_for_each(p, &subs->fmt_list) {
+		struct audioformat *fp;
+		fp = list_entry(p, struct audioformat, list);
+		if (! hw_check_valid_format(params, fp))
+			continue;
+		fbits |= (1UL << fp->format);
+	}
+
+	oldbits[0] = fmt->bits[0];
+	oldbits[1] = fmt->bits[1];
+	fmt->bits[0] &= (u32)fbits;
+	fmt->bits[1] &= (u32)(fbits >> 32);
+	if (! fmt->bits[0] && ! fmt->bits[1]) {
+#ifdef HW_CONST_DEBUG
+		printk(KERN_DEBUG "  --> get empty\n");
+#endif
+		return -EINVAL;
+	}
+	changed = (oldbits[0] != fmt->bits[0] || oldbits[1] != fmt->bits[1]);
+#ifdef HW_CONST_DEBUG
+	printk(KERN_DEBUG "  --> %x:%x (changed = %d)\n", fmt->bits[0], fmt->bits[1], changed);
+#endif
+	return changed;
+}
+
+/*
+ * check whether the registered audio formats need special hw-constraints
+ */
+static int check_hw_params_convention(snd_usb_substream_t *subs)
+{
+	int i;
+	u32 channels[64];
+	u32 rates[64];
+	u32 cmaster, rmaster;
+	struct list_head *p;
+
+	memset(channels, 0, sizeof(channels));
+	memset(rates, 0, sizeof(rates));
+
+	list_for_each(p, &subs->fmt_list) {
+		struct audioformat *f;
+		f = list_entry(p, struct audioformat, list);
+		/* uncoventional rates? */
+		if (f->channels > 32 || (f->rates & SNDRV_PCM_RATE_KNOT))
+			return 1;
+		/* combination of continuous rates and fixed rates? */
+		if (rates[f->format] & SNDRV_PCM_RATE_CONTINUOUS) {
+			if (f->rates != rates[f->format])
+				return 1;
+		}
+		if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) {
+			if (rates[f->format] && rates[f->format] != f->rates)
+				return 1;
+		}
+		channels[f->format] |= (1 << f->channels);
+		rates[f->format] |= f->rates;
+	}
+	/* check whether channels and rates match for all formats */
+	cmaster = rmaster = 0;
+	for (i = 0; i < 64; i++) {
+		if (cmaster != channels[i] && cmaster && channels[i])
+			return 1;
+		if (rmaster != rates[i] && rmaster && rates[i])
+			return 1;
+		if (channels[i])
+			cmaster = channels[i];
+		if (rates[i])
+			rmaster = rates[i];
+	}
+	return 0;
+}
+
+
+/*
  * set up the runtime hardware information.
  */
 
-static void setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
+static int setup_hw_info(snd_pcm_runtime_t *runtime, snd_usb_substream_t *subs)
 {
 	struct list_head *p;
+	int err;
 
 	runtime->hw.formats = subs->formats;
 
@@ -1195,9 +1426,30 @@
 				     1000 * MIN_PACKS_URB,
 				     /*(NRPACKS * MAX_URBS) * 1000*/ UINT_MAX);
 
-	/* FIXME: we need more constraints to restrict the format type,
-	 * channels and rates according to the audioformat list!
-	 */
+	if (check_hw_params_convention(subs)) {
+#ifdef HW_CONST_DEBUG
+		printk(KERN_DEBUG "setting extra hw constraints...\n");
+#endif
+		if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 
+					       hw_rule_rate, subs,
+					       SNDRV_PCM_HW_PARAM_FORMAT,
+					       SNDRV_PCM_HW_PARAM_CHANNELS,
+					       -1)) < 0)
+			return err;
+		if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 
+					       hw_rule_channels, subs,
+					       SNDRV_PCM_HW_PARAM_FORMAT,
+					       SNDRV_PCM_HW_PARAM_RATE,
+					       -1)) < 0)
+			return err;
+		if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
+					       hw_rule_format, subs,
+					       SNDRV_PCM_HW_PARAM_RATE,
+					       SNDRV_PCM_HW_PARAM_CHANNELS,
+					       -1)) < 0)
+			return err;
+	}
+	return 0;
 }
 
 static int snd_usb_pcm_open(snd_pcm_substream_t *substream, int direction,
@@ -1212,8 +1464,7 @@
 	runtime->hw = *hw;
 	runtime->private_data = subs;
 	subs->pcm_substream = substream;
-	setup_hw_info(runtime, subs);
-	return 0;
+	return setup_hw_info(runtime, subs);
 }
 
 static int snd_usb_pcm_close(snd_pcm_substream_t *substream, int direction)
@@ -1821,10 +2072,8 @@
 						break;
 					}
 				}
-#if 0 // FIXME - we need to define constraint
-				if (c >= 13)
-					fp->rates |= SNDRV_PCM_KNOT; /* unconventional rate */
-#endif
+				if (c >= 13)  /* unconventional rate */
+					fp->rates |= SNDRV_PCM_RATE_KNOT;
 			}
 
 		} else {

       reply	other threads:[~2003-01-23 13:23 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <s5hel74yya8.wl@alsa2.suse.de>
     [not found] ` <Pine.HPX.4.33n.0301231122530.18209-100000@studcom.urz.uni-halle.de>
     [not found]   ` <s5hbs28yx2p.wl@alsa2.suse.de>
2003-01-23 13:23     ` Takashi Iwai [this message]
     [not found]       ` <1043385385.1964.3.camel@idefix.homelinux.org>
2003-01-24 14:37         ` [Alsa-user] No sound on Extigy Takashi Iwai
2003-01-27 15:25         ` Takashi Iwai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=s5h65sgyp7j.wl@alsa2.suse.de \
    --to=tiwai@suse.de \
    --cc=alsa-devel@lists.sourceforge.net \
    --cc=clemens@ladisch.de \
    --cc=jean-marc.valin@hermes.usherb.ca \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.