Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 Mar 2005 14:44:01 -0500
From:      Mathew Kanner <mat@cnd.mcgill.ca>
To:        Kazuhito HONDA <kazuhito@ph.noda.tus.ac.jp>
Cc:        mat@cnd.mcgill.ca
Subject:   Re: uaudio patch, capabilities
Message-ID:  <20050312194401.GH2944@cnd.mcgill.ca>
In-Reply-To: <20050313.031425.343188571.kazuhito@ph.noda.tus.ac.jp>
References:  <20050312010248.GG2944@cnd.mcgill.ca> <20050313.031425.343188571.kazuhito@ph.noda.tus.ac.jp>

next in thread | previous in thread | raw e-mail | index | archive | help

--KFztAG8eRSV9hGtP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Mar 12, Kazuhito HONDA wrote:
> From: Mathew Kanner <mat@cnd.mcgill.ca>
> Subject: uaudio patch, capabilities
> Date: Fri, 11 Mar 2005 20:02:48 -0500
> 
> > 	Please find attached my work in progress to add probing the
> > min/max rate for the uaudio device.  
> 
> Hello,
> 
> Thank you very much for your coding.  
> But it had one problem when I tried it.
> 
> My USB audio device, SB Live! 24-bit External, 
> has three fixed sampling rate, 44100, 48000, and 96000 Hz.
> So min/max speeds of playback caps came to be 44100 Hz and 96000 Hz.
> In this case, sound source of 44100 Hz and 48000 Hz could be played exactly,
> and sound sources whose sampling rate was under 44100 Hz could be played
> with converted, but sound sources whose sampling sate was between 44100 Hz 
> and 48000 Hz couldn't be played.
> 
> I expected that only one sampling rate (when discrete) or 
> one sampling rate range (when continuous) must be set in caps.
> 
> I guess that there are two solutions.
> 1) use only one sampling rate or rage, neglect others.
> 2) select one rate along a speed of a sound source 
>          when the channel is initialized.
> 
> When I challenged it slightly, I aimed at 2).
> It had no problem that I changed the caps at ua_chan_init() in uaudio_pcm.c.

	Hi,
	I'm not sure I know exaclty what you mean, but there were
numerous problems with the first patch.  For instance the min/max was
taken from the record playback channel for no reason.  Please try this
patch.
	Thanks,
	--Mat

--KFztAG8eRSV9hGtP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="uaudio_caps.2.diff"

Index: uaudio.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/usb/uaudio.c,v
retrieving revision 1.13
diff -u -r1.13 uaudio.c
--- uaudio.c	6 Jan 2005 01:43:22 -0000	1.13
+++ uaudio.c	12 Mar 2005 14:47:52 -0000
@@ -3764,83 +3764,131 @@
 	return (0);
 }
 
-void
-uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt)
-{
-	int i, pn=0, rn=0;
-	int prec, dir;
+struct uaudio_convesion {
+	uint8_t uaudio_fmt;
+	uint8_t uaudio_prec;
+	uint32_t freebsd_fmt;
+};
+
+const struct uaudio_convesion const accepted_conversion[] = {
+	{AUDIO_ENCODING_ULINEAR_LE, 8, AFMT_U8},
+	{AUDIO_ENCODING_ULINEAR_LE, 16, AFMT_U16_LE},
+	{AUDIO_ENCODING_SLINEAR_LE, 8, AFMT_S8},
+	{AUDIO_ENCODING_SLINEAR_LE, 16, AFMT_S16_LE},
+	{AUDIO_ENCODING_SLINEAR_BE, 16, AFMT_S16_BE},
+	{AUDIO_ENCODING_ALAW, 8, AFMT_A_LAW},
+	{AUDIO_ENCODING_ULAW, 8, AFMT_MU_LAW},
+	{0,0,0}
+};
+
+unsigned
+uaudio_query_formats(device_t dev, int reqdir, unsigned maxfmt, struct pcmchan_caps *cap)
+{
+	struct uaudio_softc *sc = device_get_softc(dev);
+ 	const struct usb_audio_streaming_type1_descriptor *asf1d;
+	const struct uaudio_convesion *iterator;
+	unsigned fmtcount, foundcount;
 	u_int32_t fmt;
-	struct uaudio_softc *sc;
+	uint8_t format, numchan, subframesize, prec, dir, iscontinuous;
+	int freq, freq_min, freq_max;
+	char *numchannel_descr;
+	char freq_descr[64];
+	int i,r;
 
-	const struct usb_audio_streaming_type1_descriptor *a1d;
+	if ( sc == NULL )
+           return 0;
 
-	sc = device_get_softc(dev);
+	device_printf( dev, "uaudio_query_formats: querying for %s\n",(reqdir==PCMDIR_PLAY)?"playback":"record");
+
+	cap->minspeed = cap->maxspeed = 0;
+        foundcount = fmtcount = 0;
 
 	for (i = 0; i < sc->sc_nalts; i++) {
-		fmt = 0;
-		a1d = sc->sc_alts[i].asf1desc;
-		prec = a1d->bBitResolution;	/* precision */
-
-		switch (sc->sc_alts[i].encoding) {
-		case AUDIO_ENCODING_ULINEAR_LE:
-			if (prec == 8) {
-				fmt = AFMT_U8;
-			} else if (prec == 16) {
-				fmt = AFMT_U16_LE;
-			}
-			break;
-		case AUDIO_ENCODING_SLINEAR_LE:
-			if (prec == 8) {
-				fmt = AFMT_S8;
-			} else if (prec == 16) {
-				fmt = AFMT_S16_LE;
-			}
-			break;
-		case AUDIO_ENCODING_ULINEAR_BE:
-			if (prec == 16) {
-				fmt = AFMT_U16_BE;
-			}
-			break;
-		case AUDIO_ENCODING_SLINEAR_BE:
-			if (prec == 16) {
-				fmt = AFMT_S16_BE;
-			}
-			break;
-		case AUDIO_ENCODING_ALAW:
-			if (prec == 8) {
-				fmt = AFMT_A_LAW;
-			}
-			break;
-		case AUDIO_ENCODING_ULAW:
-			if (prec == 8) {
-				fmt = AFMT_MU_LAW;
-			}
-			break;
-		}
+		dir = UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress);
 
-		if (fmt != 0) {
-			if (a1d->bNrChannels == 2) {	/* stereo/mono */
-				fmt |= AFMT_STEREO;
-			} else if (a1d->bNrChannels != 1) {
-				fmt = 0;
-			}
-		}
+		if ( (dir == UE_DIR_OUT) != (reqdir == PCMDIR_PLAY) )
+			continue;
+
+		asf1d = sc->sc_alts[i].asf1desc;
+		format = sc->sc_alts[i].encoding;
+
+		numchan = asf1d->bNrChannels;
+		subframesize = asf1d->bSubFrameSize;
+		prec = asf1d->bBitResolution;	/* precision */
+		iscontinuous = asf1d->bSamFreqType == UA_SAMP_CONTNUOUS;
+
+		if (iscontinuous)
+			snprintf(freq_descr, 64, "continous min %d max %d", UA_SAMP_LO(asf1d), UA_SAMP_HI(asf1d));
+		else
+			snprintf(freq_descr, 64, "fixed frequency (%d listed formats)", asf1d->bSamFreqType);
+
+		if ( numchan == 1)
+			numchannel_descr = " (mono)";
+		else if ( numchan == 2 )
+			numchannel_descr = " (stereo)";
+		else
+			numchannel_descr = "";
+
+		device_printf( dev, "uaudio_query_formats: found a native %s channel%s %s %dbit %dbytes/subframe X %d channels = %d bytes per sample\n",
+				(dir==UE_DIR_OUT)?"playback":"record",
+				numchannel_descr, freq_descr,
+				prec, subframesize, numchan, subframesize*numchan);
+
+		/*
+		 * Now start rejecting the ones that don't map to FreeBSD
+		 */
+
+		if (numchan != 1 && numchan != 2)
+			continue;
+
+		for ( iterator = accepted_conversion ; iterator->uaudio_fmt != 0 ; iterator++ )
+			if ( iterator->uaudio_fmt == format && iterator->uaudio_prec == prec )
+				break;
+
+		if ( iterator->uaudio_fmt == 0 )
+			continue;
+
+		fmt = iterator->freebsd_fmt;
+
+		if (asf1d->bNrChannels == 2)
+			fmt |= AFMT_STEREO;
+
+		if ( numchan != 1 && numchan == 2 )
 
-		if (fmt != 0) {
-			dir= UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress);
-			if (dir == UE_DIR_OUT) {
-				pfmt[pn++] = fmt;
-			} else if (dir == UE_DIR_IN) {
-				rfmt[rn++] = fmt;
+		foundcount++;
+
+		if (fmtcount >= maxfmt )
+                    continue;
+
+		cap->fmtlist[fmtcount++] = fmt;
+
+		if (iscontinuous) {
+			freq_min = UA_SAMP_LO(asf1d);
+			freq_max = UA_SAMP_HI(asf1d);
+
+			if ( cap->minspeed == 0 || freq_min < cap->minspeed )
+				cap->minspeed = freq_min;
+			if ( cap->maxspeed == 0 )
+				cap->maxspeed = cap->minspeed;
+			if ( freq_max > cap->maxspeed )
+				cap->maxspeed = freq_max;
+		} else {
+			device_printf( dev, "uaudio_query_formats:   accepted for fixed frequencies" );
+			for (r = 0; r < asf1d->bSamFreqType; r++) {
+				freq = UA_GETSAMP(asf1d, r);
+				printf(" %dhz", freq);
+				if (cap->minspeed == 0 || freq < cap->minspeed)
+					cap->minspeed = freq;
+				if (cap->maxspeed == 0)
+					cap->maxspeed = cap->minspeed;
+				if (freq > cap->maxspeed)
+					cap->maxspeed = freq;
 			}
+			printf("\n");
 		}
-
-		if ((pn > 8*2) || (rn > 8*2))
-			break;
 	}
-	pfmt[pn] = 0;
-	rfmt[rn] = 0;
-	return;
+	cap->fmtlist[fmtcount] = 0;
+	return foundcount;
 }
 
 void
@@ -3851,14 +3899,10 @@
 	struct chan *ch;
 
 	sc = device_get_softc(dev);
-#ifndef NO_RECORDING
 	if (dir == PCMDIR_PLAY)
 		ch = &sc->sc_playchan;
 	else
 		ch = &sc->sc_recchan;
-#else
-	ch = &sc->sc_playchan;
-#endif
 
 	ch->start = start;
 	ch->end = end;
@@ -3875,39 +3919,60 @@
 	struct chan *ch;
 
 	sc = device_get_softc(dev);
-#ifndef NO_RECORDING
 	if (dir == PCMDIR_PLAY)
 		ch = &sc->sc_playchan;
 	else
 		ch = &sc->sc_recchan;
-#else
-	ch = &sc->sc_playchan;
-#endif
 
 	ch->blksize = blocksize;
 
 	return;
 }
 
-void
-uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir)
+int
+uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int reqdir)
 {
+	const struct uaudio_convesion *iterator;
 	struct uaudio_softc *sc;
 	struct chan *ch;
+	int i, r;
 
 	sc = device_get_softc(dev);
-#ifndef NO_RECORDING
-	if (dir == PCMDIR_PLAY)
+	if (reqdir == PCMDIR_PLAY)
 		ch = &sc->sc_playchan;
 	else
 		ch = &sc->sc_recchan;
-#else
-	ch = &sc->sc_playchan;
-#endif
 
-	ch->sample_rate = speed;
+	/*
+	 * We are successful if we find an endpoint that matches our selected format and it
+	 * supports the requested speed.
+	 */
+	for (i = 0; i < sc->sc_nalts; i++) {
+		int dir = UE_GET_DIR(sc->sc_alts[i].edesc->bEndpointAddress);
+		int format = sc->sc_alts[i].encoding;
+		const struct usb_audio_streaming_type1_descriptor *asf1d = sc->sc_alts[i].asf1desc;
+		int iscontinuous = asf1d->bSamFreqType == UA_SAMP_CONTNUOUS;
 
-	return;
+		if ( (dir == UE_DIR_OUT) != (reqdir == PCMDIR_PLAY) )
+			continue;
+
+		for ( iterator = accepted_conversion ; iterator->uaudio_fmt != 0 ; iterator++ )
+			if ( iterator->uaudio_fmt == format && iterator->freebsd_fmt == (ch->format&0xfffffff) ) {
+				if (iscontinuous) {
+					if ( speed >= UA_SAMP_LO(asf1d) && speed <= UA_SAMP_HI(asf1d)) {
+						ch->sample_rate = speed;
+						return 1;
+					}
+				} else
+					for (r = 0; r < asf1d->bSamFreqType; r++)
+						if ( speed == UA_GETSAMP(asf1d, r) ) {
+							ch->sample_rate = speed;
+							return 1;
+						}
+			}
+	}
+
+	return 0;
 }
 
 int
@@ -3918,14 +3983,11 @@
 	int ptr;
 
 	sc = device_get_softc(dev);
-#ifndef NO_RECORDING
+
 	if (dir == PCMDIR_PLAY)
 		ch = &sc->sc_playchan;
 	else
 		ch = &sc->sc_recchan;
-#else
-	ch = &sc->sc_playchan;
-#endif
 
 	ptr = ch->cur - ch->start;
 
@@ -3939,15 +4001,10 @@
 	struct chan *ch;
 
 	sc = device_get_softc(dev);
-#ifndef NO_RECORDING
 	if (dir == PCMDIR_PLAY)
 		ch = &sc->sc_playchan;
 	else
 		ch = &sc->sc_recchan;
-#else
-	ch = &sc->sc_playchan;
-#endif
-
 	ch->format = format;
 
 	return;
Index: uaudio.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/usb/uaudio.h,v
retrieving revision 1.5
diff -u -r1.5 uaudio.h
--- uaudio.h	6 Jan 2005 01:43:22 -0000	1.5
+++ uaudio.h	12 Mar 2005 14:21:12 -0000
@@ -41,7 +41,7 @@
 #endif
 void	uaudio_chan_set_param(device_t, u_char *, u_char *);
 void	uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir);
-void	uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir);
+int	uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int reqdir);
 void	uaudio_chan_set_param_format(device_t dev, u_int32_t format,int dir);
 int	uaudio_chan_getptr(device_t dev, int);
 void	uaudio_mixer_set(device_t dev, unsigned type, unsigned left,
@@ -49,4 +49,4 @@
 u_int32_t uaudio_mixer_setrecsrc(device_t dev, u_int32_t src);
 u_int32_t uaudio_query_mix_info(device_t dev);
 u_int32_t uaudio_query_recsrc_info(device_t dev);
-void	uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt);
+unsigned uaudio_query_formats(device_t dev, int dir, unsigned maxfmt, struct pcmchan_caps *fmt);
Index: uaudio_pcm.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/usb/uaudio_pcm.c,v
retrieving revision 1.10
diff -u -r1.10 uaudio_pcm.c
--- uaudio_pcm.c	1 Mar 2005 08:58:06 -0000	1.10
+++ uaudio_pcm.c	12 Mar 2005 14:43:20 -0000
@@ -48,17 +48,13 @@
 	device_t sc_dev;
 	struct ua_chinfo pch, rch;
 	bus_dma_tag_t	parent_dmat;
+	u_int32_t ua_playfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
+	u_int32_t ua_recfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
+	struct pcmchan_caps ua_playcaps;
+	struct pcmchan_caps ua_reccaps;
 };
 
-static u_int32_t ua_playfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
-
-static struct pcmchan_caps ua_playcaps = {8000, 48000, ua_playfmt, 0};
-
-static u_int32_t ua_recfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
-
-static struct pcmchan_caps ua_reccaps = {8000, 48000, ua_recfmt, 0};
-
-#define UAUDIO_PCM_BUFF_SIZE	16*1024
+#define UAUDIO_PCM_BUFF_SIZE	8*1024
 
 /************************************************************/
 static void *
@@ -76,12 +72,6 @@
 	ch->dir = dir;
 
 	pa_dev = device_get_parent(sc->sc_dev);
-     	/* Create ua_playfmt[] & ua_recfmt[] */
-	uaudio_query_formats(pa_dev, (u_int32_t *)&ua_playfmt, (u_int32_t *)&ua_recfmt);
-	if (ua_playfmt[0] == 0) {
-		printf("%s channel supported format list invalid\n", dir == PCMDIR_PLAY? "play" : "record");
-		return NULL;
-	}
 
 	/* allocate PCM side DMA buffer */
 	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, UAUDIO_PCM_BUFF_SIZE) != 0) {
@@ -112,10 +102,14 @@
 
 	struct ua_chinfo *ch = data;
 
+	/*
+	 * At this point, no need to queury as we shouldn't select an unsorted format
+	 */
 	ua = ch->parent;
 	pa_dev = device_get_parent(ua->sc_dev);
 	uaudio_chan_set_param_format(pa_dev, format, ch->dir);
 
+	printf("ua_chan_setformat %u\n", format);
 	ch->fmt = format;
 	return 0;
 }
@@ -123,16 +117,14 @@
 static int
 ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
 {
-	device_t pa_dev;
-	struct ua_info *ua;
-
 	struct ua_chinfo *ch = data;
-	ch->spd = speed;
+	device_t pa_dev = device_get_parent(ch->parent->sc_dev);
+	int res;
 
-	ua = ch->parent;
-	pa_dev = device_get_parent(ua->sc_dev);
-	uaudio_chan_set_param_speed(pa_dev, speed, ch->dir);
+	if ( (res = uaudio_chan_set_param_speed(pa_dev, speed, ch->dir)) )
+		ch->spd = speed;
 
+	printf("ua_chan_setspeed %d %s\n", speed, res?"worked":"failed");
 	return ch->spd;
 }
 
@@ -207,7 +199,7 @@
 {
 	struct ua_chinfo *ch = data;
 
-	return (ch->dir == PCMDIR_PLAY) ? &ua_playcaps : & ua_reccaps;
+	return (ch->dir == PCMDIR_PLAY) ? &(ch->parent->ua_playcaps) : &(ch->parent->ua_reccaps);
 }
 
 static kobj_method_t ua_chan_methods[] = {
@@ -297,8 +289,11 @@
 ua_attach(device_t dev)
 {
 	struct ua_info *ua;
+	device_t pa_dev;
 	char status[SND_STATUSLEN];
 	unsigned int bufsz;
+        u_int32_t nplay, nrec;
+        int i;
 
 	ua = (struct ua_info *)malloc(sizeof *ua, M_DEVBUF, M_NOWAIT);
 	if (!ua)
@@ -307,6 +302,8 @@
 
 	ua->sc_dev = dev;
 
+	pa_dev = device_get_parent(dev);
+
 	bufsz = pcm_getbuffersize(dev, 4096, UAUDIO_PCM_BUFF_SIZE, 65536);
 
 	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
@@ -314,7 +311,7 @@
 				/*highaddr*/BUS_SPACE_MAXADDR,
 				/*filter*/NULL, /*filterarg*/NULL,
 				/*maxsize*/bufsz, /*nsegments*/1,
-				/*maxsegz*/0x3fff, /*flags*/0,
+				/*maxsegz*/65536, /*flags*/0,
 				/*lockfunc*/busdma_lock_mutex,
 				/*lockarg*/&Giant,
 				&ua->parent_dmat) != 0) {
@@ -323,22 +320,37 @@
 	}
 
 	if (mixer_init(dev, &ua_mixer_class, ua)) {
-		return(ENXIO);
+		goto bad;
 	}
 
-	snprintf(status, SND_STATUSLEN, "at addr ?");
+	snprintf(status, SND_STATUSLEN, "%s", PCM_KLDSTRING(snd_uaudio));
+
+	ua->ua_playcaps.fmtlist = ua->ua_playfmt;
+	ua->ua_reccaps.fmtlist = ua->ua_recfmt;
+	nplay = uaudio_query_formats(pa_dev, PCMDIR_PLAY, 8, &ua->ua_playcaps);
+	nrec = uaudio_query_formats(pa_dev, PCMDIR_REC, 8, &ua->ua_reccaps);
+
+	if ( nplay > 1 )
+		nplay = 1;
+	if ( nrec > 1 )
+		nrec = 1;
 
 #ifndef NO_RECORDING
-	if (pcm_register(dev, ua, 1, 1)) {
+	if (pcm_register(dev, ua, nplay, nrec)) {
 #else
-	if (pcm_register(dev, ua, 1, 0)) {
+	if (pcm_register(dev, ua, nplay, 0)) {
 #endif
 		return(ENXIO);
 	}
 
-	pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
+        for (i = 0; i < nplay; i++) {
+		pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
+        }
+
 #ifndef NO_RECORDING
-	pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
+        for (i = 0; i < nplay; i++) {
+		pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
+        }
 #endif
 	pcm_setstatus(dev, status);
 

--KFztAG8eRSV9hGtP--


Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050312194401.GH2944>