code: plan9front

Download patch

ref: 6e33b8e40b38bd288768b8c854805e76fec51858
parent: e6f85e3ec81936834c24b958df143fd3a895b8f9
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Apr 6 19:07:48 EDT 2024

audio/mixfs: resample based on audio dev output format, not just the rate

This is pleminary work of replacing "speed" with "fmtout"/"fmtin"
through the entire system.
Switching between output devices with different PCM formats
back and forth now works as expected.

--- a/sys/src/cmd/audio/mixfs/mixfs.c
+++ b/sys/src/cmd/audio/mixfs/mixfs.c
@@ -4,6 +4,7 @@
 #include <thread.h>
 #include <9p.h>
 #include <pcm.h>
+#pragma varargck type "!" Pcmdesc
 
 enum {
 	NBUF = 8*1024,
@@ -45,8 +46,11 @@
 
 int	volume[2] = {100, 100};
 int	vol64k[2] = {65536, 65536};
-int	newrate;
 
+Pcmdesc	fmt;
+Lock	fmtlock;
+int	fmtchanged;
+
 int
 s16(uchar *p)
 {
@@ -79,20 +83,36 @@
 }
 
 void
-updrate(void)
+updfmt(void)
 {
 	static char svol[4*1024];
-	int n, rate;
-	char *s;
+	char *s, *e;
+	int n, ok;
 
-	rate = pcmdescdef.rate;
+	ok = 0;
 	if(volfd >= 0 && (n = pread(volfd, svol+1, sizeof(svol)-2, 0)) > 8){
 		svol[0] = '\n';
 		svol[1+n] = 0;
-		if((s = strstr(svol, "\nspeed ")) != nil && (n = strtol(s+6, &s, 10)) > 0)
-			rate = n;
+		if((s = strstr(svol, "\nfmtout ")) != nil && (e = strchr(s+12, '\n')) != nil){
+			*e = 0;
+			lock(&fmtlock);
+			ok = fmtchanged = mkpcmdesc(s+8, &fmt) == 0;
+			unlock(&fmtlock);
+		}
+		if(!ok && (s = strstr(svol, "\nspeed ")) != nil && (n = strtol(s+6, &s, 10)) > 0){
+			lock(&fmtlock);
+			fmt = pcmdescdef;
+			fmt.rate = n;
+			ok = fmtchanged = fmt.rate > 0;
+			unlock(&fmtlock);
+		}
 	}
-	newrate = rate;
+	if(!ok){
+		lock(&fmtlock);
+		fmt = pcmdescdef;
+		fmtchanged = 1;
+		unlock(&fmtlock);
+	}
 }
 
 int
@@ -164,7 +184,7 @@
 		name = smprint("%.*svolume%s", (int)(p - name), name, p+5);
 		volfd = open(name, ORDWR);
 		free(name);
-		updrate();
+		updfmt();
 	}
 	return 0;
 }
@@ -222,12 +242,22 @@
 	f->aux = nil;
 }
 
+int
+eqfmt(Pcmdesc *a, Pcmdesc *b)
+{
+	return
+		a->rate == b->rate
+		&& a->bits == b->bits
+		&& a->channels == b->channels
+		&& a->framesz == b->framesz
+		&& a->fmt == b->fmt;
+}
+
 void
 audioproc(void *)
 {
 	static uchar buf[ABUF];
-	static Pcmdesc desc;
-	int sweep, i, j, n, m, v;
+	int sweep, i, j, n, m, v, rate;
 	ulong rp;
 	Stream *s;
 	uchar *p, *bufconv;
@@ -234,10 +264,10 @@
 	Pcmconv	*conv;
 
 	threadsetname("audioproc");
-	desc = pcmdescdef;
 	conv = nil;
 	bufconv = nil;
 	sweep = 0;
+	rate = fmt.rate;
 
 	for(;;){
 		m = NBUF;
@@ -275,7 +305,7 @@
 					/* attempt to sleep just shortly before buffer underrun */
 					ms = seek(audiofd, 0, 2);
 					ms *= 800;
-					ms /= desc.rate*NCHAN*2;
+					ms /= rate*NCHAN*2;
 				}
 				sweep = 1;
 			}
@@ -310,12 +340,15 @@
 		mixrp = rp;
 		unlock(&rplock);
 
-		if(desc.rate != newrate){
-			desc.rate = newrate;
+		lock(&fmtlock);
+		if(fmtchanged){
+			fmtchanged = 0;
 			free(bufconv);
 			bufconv = nil;
 			freepcmconv(conv);
-			if((conv = allocpcmconv(&pcmdescdef, &desc)) == nil ||
+			conv = nil;
+			if(!eqfmt(&fmt, &pcmdescdef))
+			if((conv = allocpcmconv(&pcmdescdef, &fmt)) == nil ||
 			   (n = pcmratio(conv, ABUF)) < 0 ||
 			   (bufconv = malloc(n)) == nil){
 				fprint(2, "%s: %r\n", devaudio);
@@ -322,7 +355,9 @@
 				freepcmconv(conv);
 				conv = nil;
 			}
+			rate = fmt.rate;
 		}
+		unlock(&fmtlock);
 
 		n = p - buf;
 		p = buf;
@@ -340,6 +375,7 @@
 {
 	Srv *srv;
 	int i, j, n, m, v;
+	char *f, *e;
 	Stream *s;
 	uchar *p;
 
@@ -346,11 +382,23 @@
 	if(r->fid->file->aux == &volfd){
 		static char svol[4096];
 		if(r->ifcall.offset == 0){
-			m = snprint(svol, sizeof(svol), "dev %s\nmix %d %d\n",
+			m = snprint(svol, sizeof(svol), "dev %s\nmix %d %d\nfmtout %!\nspeed %d\n",
 				devaudio?devaudio:"",
-				volume[0], volume[1]);
-			if(volfd >= 0 && (n = pread(volfd, svol+m, sizeof(svol)-m-1, 0)) > 0)
+				volume[0], volume[1],
+				pcmdescdef,
+				pcmdescdef.rate);
+			if(volfd >= 0 && (n = pread(volfd, svol+m, sizeof(svol)-m-1, 0)) > 0){
 				svol[m+n] = 0;
+				/* device's fmtout and speed are removed */
+				if((f = strstr(svol+m-1, "\nfmtout ")) != nil && (e = strchr(f+8, '\n')) != nil){
+					n -= e-f;
+					memmove(f, e, n+1);
+				}
+				if((f = strstr(svol+m-1, "\nspeed ")) != nil && (e = strchr(f+7, '\n')) != nil){
+					n -= e-f;
+					memmove(f, e, n+1);
+				}
+			}
 		}
 		readstr(r, svol);
 		respond(r, nil);
@@ -574,7 +622,7 @@
 	if(argc > 1)
 		usage();
 
-	newrate = pcmdescdef.rate;
+	fmtinstall('!', pcmdescfmt);
 	reopendevs(argv[0]);
 	closeaudiodev();