shithub: drawterm

Download patch

ref: ccfb14a8dae242d76e6c8985611e1410e15e7ec7
parent: f6c5c276b6938f83cadafb7e1887027ddc722eb1
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Tue Jan 18 19:40:21 EST 2022

kern: fix pipewire audio backend

--- a/kern/devaudio-pipewire.c
+++ b/kern/devaudio-pipewire.c
@@ -12,12 +12,12 @@
 
 static struct {
 	Lock lk;
-	Rendez z;
+	Rendez w;
 	int init;
 	struct pw_main_loop *loop;
 	struct pw_stream *output;
 
-	char buf[8192];
+	char buf[2*2*44100/10]; /* 1/10th sec */
 	int written; /* 0 means empty buffer */
 } pwstate;
 
@@ -30,26 +30,34 @@
 	struct pw_buffer *b;
 	struct spa_buffer *buf;
 	int16_t *dst;
+	int n;
 
 	lock(&pwstate.lk);
+	if(pwstate.written == sizeof(pwstate.buf))
+		wakeup(&pwstate.w);
 	if(pwstate.written == 0){
 		unlock(&pwstate.lk);
 		return;
 	}
-	b = pw_stream_dequeue_buffer(pwstate.output);
 
+	if((b = pw_stream_dequeue_buffer(pwstate.output)) == nil)
+		return;
 	buf = b->buffer;
 	dst = buf->datas[0].data;
 
-	memcpy(dst, pwstate.buf, pwstate.written);
+	n = pwstate.written;
+	if(n > buf->datas[0].maxsize)
+		n = buf->datas[0].maxsize;
+	memcpy(dst, pwstate.buf, n);
 	buf->datas[0].chunk->offset = 0;
 	buf->datas[0].chunk->stride = sizeof(int16_t) * 2;
-	buf->datas[0].chunk->size = pwstate.written;
+	buf->datas[0].chunk->size = n;
+	pwstate.written -= n;
+	if(pwstate.written > 0)
+		memmove(pwstate.buf, pwstate.buf+n, pwstate.written);
 
 	pw_stream_queue_buffer(pwstate.output, b);
-	pwstate.written = 0;
 	unlock(&pwstate.lk);
-	wakeup(&pwstate.z);
 }
 
 static const struct pw_stream_events stream_events = {
@@ -64,6 +72,7 @@
 
 	loop = arg;
 	pw_main_loop_run(loop);
+	pexit("", 0);
 }
 
 void
@@ -74,6 +83,7 @@
 	int err;
 
 	lock(&pwstate.lk);
+	pwstate.written = 0;
 	if(pwstate.init > 0){
 		kproc("pipewire main loop", pwproc, pwstate.loop);
 		unlock(&pwstate.lk);
@@ -127,9 +137,7 @@
 void
 audiodevclose(void)
 {
-	lock(&pwstate.lk);
 	pw_main_loop_quit(pwstate.loop);
-	unlock(&pwstate.lk);
 }
 
 int
@@ -142,26 +150,30 @@
 static int
 canwrite(void *arg)
 {
-	return pwstate.written == 0;
+	return pwstate.written < sizeof(pwstate.buf);
 }
 
 int
 audiodevwrite(void *a, int n)
 {
-	if(n > sizeof(pwstate.buf)){
-		error("write too large");
-		return -1;
-	}
-	lock(&pwstate.lk);
-	if(pwstate.written != 0){
-		unlock(&pwstate.lk);
-		sleep(&pwstate.z, canwrite, 0);
+	int w, x, max;
+	char *p;
+
+	w = n;
+	for(p = a; n > 0; p += x, n -= x){
 		lock(&pwstate.lk);
+		max = sizeof(pwstate.buf) - pwstate.written;
+		x = n > max ? max : n;
+		if(x < 1){
+			unlock(&pwstate.lk);
+			sleep(&pwstate.w, canwrite, 0);
+		}else{
+			memmove(pwstate.buf+pwstate.written, p, x);
+			pwstate.written += x;
+			unlock(&pwstate.lk);
+		}
 	}
-	memcpy(pwstate.buf, a, n);
-	pwstate.written = n;
-	unlock(&pwstate.lk);
-	return n;
+	return w;
 }
 
 void