On Mon, 13 Feb 2023, Steve Taylor wrote: > From: Steve Taylor > Hello adr, > > I saw your note on the Plan 9 mailing list about USB audio on the RPi 4 with 9legacy. By USB audio device, do you mean something like a USB DAC? If so, I have spent several hours on this recently. Whenever I play audio through my USB DAC connected to my RPi4, using either 9legacy or 9front, I hear pops and other small noises like static. I think it is from dropped frames. If I use OpenBSD on the same hardware, these issues do not occur. The audio plays perfectly. > > Are you seeing issues like this? > > I am curious if using a USB DAC which is USB 1.0 would work properly. I identified a couple I could try, but they are about 20 years old and difficult to find for a decent price. The USB DAC I have now uses xhci. > > Thanks, > > Steve Hi Steve, I'm using this cheap one: https://aliexpress.com/item/1005001394902427.html ep6.0 enabled control rw speed full maxpkt 8 pollival 0 samplesz 0 hz 0 hub 3 port 4 rootport 1 addr 4 busy audio csp 0x000101 csp 0x000201 csp 0x000201 csp 0x000003 vid 0x1b3f did 0x2008 GeneralPlus 'USB Audio Device' xhci ep6.5 enabled iso w speed full maxpkt 180 pollival 1 samplesz 4 hz 44100 hub 3 port 4 rootport 1 addr 4 busy ep6.6 enabled iso r speed full maxpkt 96 pollival 1 samplesz 2 hz 48000 hub 3 port 4 rootport 1 addr 4 idle ep6.3 enabled interrupt r speed full maxpkt 8 pollival 32 samplesz 0 hz 0 hub 3 port 4 rootport 1 addr 4 busy It works ok with 9front. If you just need decent audio output from your pi, I recommend it. Now about 9legacy. Richard Miller imported the xhci driver from 9front, so I compared them. The only real difference appart from IN isochronous transfers support is the addition of sample delay for buffering. This patch makes the already present control in usb/audio Delay_control an internal one to set this delay. I used the same default as 9front, 40ms. I can play audio perfectly now. Also you can change now the sample rate (speed), the code was reopening the endpoint with openep() every time setspeed() was called. More work has to be done, but for now I hope this is helpful for you. Try increasing the delay with your device. I'm sharing this with the list. P.S. The patch is against the repo at github.com/0intro/plan9-contrib. Regards, adr --- /n/downloads/devusb.c Tue Feb 14 20:42:27 2023 +++ /sys/src/9/bcm/devusb.c Tue Feb 14 11:31:28 2023 @@ -88,6 +88,7 @@ CMdebugep, /* debug n (set/clear debug for this ep) */ CMname, /* name str (show up as #u/name as well) */ CMtmout, /* timeout n (activate timeouts for ep) */ + CMsampledelay, /* maximum delay introduced by buffering (iso) */ CMpreset, /* reset the port */ /* Hub feature selectors */ @@ -128,6 +129,7 @@ {CMclrhalt, "clrhalt", 1}, {CMname, "name", 2}, {CMtmout, "timeout", 2}, + {CMsampledelay, "sampledelay", 2}, {CMpreset, "reset", 1}, }; @@ -1387,6 +1389,11 @@ ep->tmout = strtoul(cb->f[1], nil, 0); if(ep->tmout != 0 && ep->tmout < Xfertmout) ep->tmout = Xfertmout; + break; + case CMsampledelay: + if(ep->ttype != Tiso) + error("ctl ignored for this endpoint type"); + ep->sampledelay = strtoul(cb->f[1], nil, 0); break; case CMpreset: deprint("usb epctl %s\n", cb->f[0]); --- /n/downloads/usbxhci.c Tue Feb 14 20:41:33 2023 +++ /sys/src/9/bcm/usbxhci.c Tue Feb 14 11:24:53 2023 @@ -194,6 +194,7 @@ int stopped; + int *residue; Wait *pending; Lock; }; @@ -277,6 +278,10 @@ u32int incr; u32int tdsz; + /* isoread */ + u32int rp0; + u32int frame0; + int nleft; }; @@ -1100,10 +1105,17 @@ { if(io->ring == nil) return; - io->frame = 0; - io->period = ep->pollival<<3*(ep->dev->speed == Fullspeed); - io->incr = (ep->hz*io->period<<8)/8000; - io->tdsz = (io->incr+255>>8)*ep->samplesz; + io->rp0 = io->ring->wp; + io->frame0 = io->frame = 0; + io->period = ep->pollival << 3*(ep->dev->speed == Fullspeed || ep->dev->speed == Lowspeed); + if(io->ring->id & 1){ + io->ring->residue = smalloc((io->ring->mask+1)*sizeof(io->ring->residue[0])); + io->incr = 0; + io->tdsz = ep->maxpkt*ep->ntds; + } else { + io->incr = ((vlong)ep->hz*ep->pollival<<8)/1000; + io->tdsz = (io->incr+255>>8)*ep->samplesz; + } io->b = allocb((io->ring->mask+1)*io->tdsz); } @@ -1336,10 +1348,10 @@ } ?? = io->period; ctlr = ep->hp->aux; - if(needrecover(ctlr)) - error(Erecover); for(i = io->frame;; i++){ for(;;){ + if(needrecover(ctlr)) + error(Erecover); m = (int)(io->ring->wp - io->ring->rp); if(m <= 0) i = (80 + ??frame(ctlr))/??; @@ -1367,11 +1379,13 @@ io->frame = i; while(io->ring->rp != io->ring->wp){ int d = (int)(i*?? - ??frame(ctlr))/8; - //d -= ep->sampledelay*1000 / ep->hz; + d -= ep->sampledelay*1000 / ep->hz; if(d < 5) break; *io->ring->doorbell = io->ring->id; tsleep(&up->sleep, return0, nil, d); + if(needrecover(ctlr)) + error(Erecover); } qunlock(io); poperror(); --- /n/downloads/audio.h Tue Feb 14 23:52:55 2023 +++ /sys/src/cmd/usb/audio/audio.h Tue Feb 14 23:29:03 2023 @@ -39,6 +39,11 @@ #define SAMPLING_FREQ_CONTROL 0x01 +#define DSPEEDPLAY 44100 +#define DSPEEDREC 44100 +/* 40ms */ +#define DDELAY 1764 + typedef struct Audioalt Audioalt; struct Audioalt { --- /n/downloads/audio.c Tue Feb 14 23:52:36 2023 +++ /sys/src/cmd/usb/audio/audio.c Wed Feb 15 01:00:51 2023 @@ -25,7 +25,7 @@ int verbose; int setrec = 0; -int defaultspeed[2] = {44100, 44100}; +int defaultspeed[2]= { DSPEEDPLAY, DSPEEDREC}; Dev *buttondev; Dev *epdev[2]; @@ -372,6 +372,8 @@ value[0] = defaultspeed[Record]; if(endpt[Record] >= 0 && setcontrol(Record, "speed", value) < 0) fprint(2, "%s: can't set record speed\n", argv0); + value[0] = DDELAY; + setcontrol(Play, "delay", value); value[0] = 0; setcontrol(Play, "mute", value); --- /n/downloads/audioctl.c Tue Feb 14 20:43:26 2023 +++ /sys/src/cmd/usb/audio/audioctl.c Wed Feb 15 01:13:48 2023 @@ -18,7 +18,7 @@ Audiocontrol controls[2][Ncontrol] = { { - [Speed_control] = { "speed", 0, {0}, 0, 44100, Undef}, + [Speed_control] = { "speed", 0, {0}, 0, DSPEEDPLAY, Undef}, [Mute_control] = { "mute", 0, {0}, 0, 0, Undef}, [Volume_control] = { "volume", 0, {0}, 0, 0, Undef}, [Bass_control] = { "bass", 0, {0}, 0, 0, Undef}, @@ -26,14 +26,14 @@ [Treble_control] = { "treble", 0, {0}, 0, 0, Undef}, [Equalizer_control] = { "equalizer", 0, {0}, 0, 0, Undef}, [Agc_control] = { "agc", 0, {0}, 0, 0, Undef}, - [Delay_control] = { "delay", 0, {0}, 0, 0, Undef}, + [Delay_control] = { "delay", 1, {1}, 0, DDELAY, Undef}, [Bassboost_control] = { "bassboost", 0, {0}, 0, 0, Undef}, [Loudness_control] = { "loudness", 0, {0}, 0, 0, Undef}, [Channel_control] = { "channels", 0, {0}, 0, 2, Undef}, [Resolution_control] = { "resolution", 0, {0}, 0, 16, Undef}, // [Selector_control] = { "selector", 0, {0}, 0, 0, Undef}, }, { - [Speed_control] = { "speed", 0, {0}, 0, 44100, Undef}, + [Speed_control] = { "speed", 0, {0}, 0, DSPEEDREC, Undef}, [Mute_control] = { "mute", 0, {0}, 0, 0, Undef}, [Volume_control] = { "volume", 0, {0}, 0, 0, Undef}, [Bass_control] = { "bass", 0, {0}, 0, 0, Undef}, @@ -129,6 +129,15 @@ } int +setdelay(int rec, int delay) +{ + if(rec == Record && !setrec) + return Undef; + devctl(epdev[rec], "sampledelay %ld", delay); + return delay; +} + +int setspeed(int rec, int speed) { int ps, n, no, dist, i; @@ -226,10 +235,11 @@ } dprint(2, "Configuring %s endpoint for %d Hz\n", rec?"record":"playback", speed); - epdev[rec] = openep(ad, endpt[rec]); - if(epdev[rec] == nil) - sysfatal("openep rec %d: %r", rec); - + if(epdev[rec] == nil){ + epdev[rec] = openep(ad, endpt[rec]); + if(epdev[rec] == nil) + sysfatal("openep rec %d: %r", rec); + } devctl(epdev[rec], "pollival %d", da->interval); devctl(epdev[rec], "samplesz %ld", controls[rec][Channel_control].value[0] * controls[rec][Resolution_control].value[0]/8); @@ -391,8 +401,11 @@ c->value[0] = value[0]; controls[rec][Speed_control].value[0] = defaultspeed[rec]; return 0; - case Volume_control: case Delay_control: + setdelay(rec, value[0]); + c->value[0] = value[0]; + return 0; + case Volume_control: count = 2; /* fall through */ case Mute_control: @@ -480,8 +493,12 @@ if(req == Rgetcur) value[0] = controls[rec][ctl].value[0]; return 0; - case Volume_control: case Delay_control: + if(req != Rgetcur) + return Undef; + value[0] = controls[rec][ctl].value[0]; + return 0; + case Volume_control: count = 2; /* fall through */ case Bass_control: ------------------------------------------ 9fans: 9fans Permalink: https://9fans.topicbox.com/groups/9fans/Tf6820d74b730765b-M6771d495bc597d497acef054 Delivery options: https://9fans.topicbox.com/groups/9fans/subscription