From owner-freebsd-multimedia@FreeBSD.ORG Sat Mar 12 19:44:39 2005 Return-Path: Delivered-To: freebsd-multimedia@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 11A0816A4CE for ; Sat, 12 Mar 2005 19:44:39 +0000 (GMT) Received: from drizzle.CC.McGill.CA (drizzle.cc.mcgill.ca [132.206.27.48]) by mx1.FreeBSD.org (Postfix) with ESMTP id 487DC43D2D for ; Sat, 12 Mar 2005 19:44:38 +0000 (GMT) (envelope-from mat@cnd.mcgill.ca) Received: from mailscan2.cc.mcgill.ca (mailscan2.CC.McGill.CA [132.216.77.249])j2CJiY5k011551; Sat, 12 Mar 2005 14:44:35 -0500 Received: from cube.cnd.mcgill.ca (cube.CND.McGill.CA [132.216.25.196]) j2CJiIAh015104; Sat, 12 Mar 2005 14:44:19 -0500 (EST) Received: from localhost.localdomain (acid.cnd.mcgill.ca [132.216.11.151]) by cube.cnd.mcgill.ca (8.12.11/8.12.11) with ESMTP id j2CJi46x020119; Sat, 12 Mar 2005 14:44:05 -0500 Received: from localhost.localdomain (acid [127.0.0.1]) j2CJi4Va023008; Sat, 12 Mar 2005 14:44:04 -0500 Received: (from mat@localhost) by localhost.localdomain (8.12.11/8.12.11/Submit) id j2CJi2TK023007; Sat, 12 Mar 2005 14:44:02 -0500 Date: Sat, 12 Mar 2005 14:44:01 -0500 From: Mathew Kanner To: Kazuhito HONDA Message-ID: <20050312194401.GH2944@cnd.mcgill.ca> References: <20050312010248.GG2944@cnd.mcgill.ca> <20050313.031425.343188571.kazuhito@ph.noda.tus.ac.jp> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="KFztAG8eRSV9hGtP" Content-Disposition: inline In-Reply-To: <20050313.031425.343188571.kazuhito@ph.noda.tus.ac.jp> User-Agent: Mutt/1.4.2i Organization: I speak for myself, operating in Montreal, CANADA cc: freebsd-multimedia@freebsd.org cc: mat@cnd.mcgill.ca Subject: Re: uaudio patch, capabilities X-BeenThere: freebsd-multimedia@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Multimedia discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 12 Mar 2005 19:44:39 -0000 --KFztAG8eRSV9hGtP Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Mar 12, Kazuhito HONDA wrote: > From: Mathew Kanner > 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--