shithub: zuke

Download patch

ref: 5d2537db828012ebd648101443a24cee3cbd7158
parent: 3cbd8d28f0b43229ada32916236208d38bca116a
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Fri Feb 19 19:14:08 EST 2016

rewrite

--- a/zuke.c
+++ b/zuke.c
@@ -6,21 +6,37 @@
 #include <bio.h>
 #include <thread.h>
 
-static int plen;
-static struct {
+typedef struct Player Player;
+
+enum
+{
+	Cstart = 1,
+	Cstop,
+	Ctoggle,
+};
+
+static struct
+{
 	char *file;
 	char *name;
 }*plist;
+static int plen;
 
-static int pid, pcur, pcurplaying;
-static int scroll, scrollsz, pause;
-static Image *cola, *colb;
-static Font *f;
-static Channel ctl;
-static int audio;
+struct Player
+{
+	Channel *ctl, *ev;
+	int pcur;
+};
 
 int mainstacksize = 32768;
 
+static int audio;
+static int pcur, pcurplaying;
+static int scroll, scrollsz;
+static Image *cola, *colb;
+static Font *f;
+static Channel *ev;
+
 static void
 redraw(Image *screen, int new)
 {
@@ -63,153 +79,117 @@
 	flushimage(display, 1);
 }
 
-typedef struct Relayctx Relayctx;
-struct Relayctx {
-	int     in, out;
-	Channel *ev;
-};
-
-typedef struct Decctx Decctx;
-struct Decctx {
-	int     in, out;
-	Channel *quit, *wait;
-};
-
 static void
-relay(void *v)
+playerthread(void *player_)
 {
-	int n;
 	char *buf;
 	Ioproc *io;
-	Relayctx *ctx;
+	Player *player;
+	ulong c;
+	int p[2], pid, n, noinit;
 
-	ctx = v;
-	io = ioproc();
-	buf = malloc(65536);
-	sendp(ctx->ev, nil);
-	while((n = ioread(io, ctx->in, buf, 65536)) > 0){
-		if(iowrite(io, ctx->out, buf, n) != n)
-			break;
+	player = player_;
+	noinit = 0;
+	io = nil;
+	buf = nil;
+
+next:
+	pipe(p);
+	if((pid = rfork(RFPROC|RFFDG|RFREND|RFNOTEG)) == 0){
+		dup(p[0], 1);
+		close(p[0]);
+		close(p[1]);
+		close(0);
+		close(2);
+		execl("/bin/play", "/bin/play", "-o", "/fd/1", plist[player->pcur].file, nil);
+		sysfatal("execl: %r");
 	}
-	free(buf);
-	closeioproc(io);
-	sendp(ctx->ev, nil);
-}
+	if(pid < 0)
+		sysfatal("rfork: %r");
+	close(p[0]);
 
-typedef struct Playctx Playctx;
-struct Playctx {
-	Channel *quit;
-	Channel *wait;
-	int     p[4];
-};
+	if(!noinit){
+		threadsetname("player");
+		sendp(player->ev, nil); /* "ready to start" */
+		c = recvul(player->ctl);
+		if(c != Cstart)
+			return;
+		io = ioproc();
+		buf = malloc(8192);
+	}
 
-static void
-player(void *dec_)
-{
-	Decctx *dec;
-	static Relayctx rel[2];
-	Alt a[3];
+	pcurplaying = player->pcur;
+	redraw(screen, 1);
 
-	dec = dec_;
-	threadsetname("player");
-
-	if(rel[0].ev == nil){
-		rel[0].ev = chancreate(sizeof(void*), 0);
-		rel[1].ev = chancreate(sizeof(void*), 0);
+	while((n = ioread(io, p[1], buf, 8192)) > 0){
+		c = nbrecvul(player->ctl);
+		if(c == Cstop)
+			goto stop;
+		if(c == Ctoggle){
+			c = recvul(player->ctl);
+			if(c == Cstop)
+				goto stop;
+		}
+		if(iowrite(io, audio, buf, n) != n)
+			break;
 	}
 
-	audio = open("/dev/audio", OWRITE);
-	pcurplaying = pcur;
-
-again:
-	rel[0].in = open(plist[pcurplaying].file, OREAD);
-	rel[0].out = dec->in;
-	rel[1].in = dec->out;
-	rel[1].out = audio;
-
-	if(audio < 0 || rel[0].in < 0){
-		close(audio);
-		close(rel[0].in);
-		fprint(2, "%r\n");
-		threadexits(nil);
+	if(n == 0){ /* end of the song, need to skip to the next one */
+		close(p[1]);
+		player->pcur++;
+		noinit = 1;
+		goto next;
 	}
 
-	threadcreate(relay, &rel[0], 4096); recvp(rel[0].ev);
-	threadcreate(relay, &rel[1], 4096); recvp(rel[1].ev);
+stop:
+	close(p[1]);
+	postnote(PNGROUP, pid, "interrupt");
+	free(buf);
+	closeioproc(io);
+	sendp(player->ev, nil); /* "finished" */
+}
 
-	memset(a, 0, sizeof(a));
-	a[0].op = a[1].op = CHANRCV;
-	a[0].c = dec->quit;
-	a[1].c = rel[0].ev;
-	a[2].op = CHANEND;
-	while(1){
-		int r;
+static Player *
+newplayer(int pcur)
+{
+	Player *player;
 
-		r = alt(a);
-		close(rel[0].in);
+	player = malloc(sizeof(*player));
+	player->ctl = chancreate(sizeof(ulong), 0);
+	player->ev = chancreate(sizeof(void*), 0);
+	player->pcur = pcur;
 
-		if(r == 1){
-			if(++pcurplaying >= plen)
-				pcurplaying = 0;
-			redraw(screen, 1);
-			goto again;
-		}
-		else{
-			close(rel[1].in);
-			close(rel[0].out);
-			recvp(rel[0].ev);
-			recvp(rel[1].ev);
-			close(audio);
-			sendp(dec->wait, nil);
-			break;
-		}
-	}
+	proccreate(playerthread, player, mainstacksize);
+	recvp(player->ev); /* wait for it to become ready */
 
-	threadexits(nil);
+	return player;
 }
 
 static void
-play(void)
+stop(Player *player)
 {
-	static Decctx ctx;
-	int p[4];
-
-	if(ctx.quit == nil){
-		ctx.quit = chancreate(sizeof(void*), 0);
-		ctx.wait = chancreate(sizeof(void*), 0);
-	}
-
-	if(pcur == pcurplaying)
+	if(player == nil)
 		return;
-	if(pid != 0){
-		sendp(ctx.quit, nil);
-		recvp(ctx.wait);
-	}
-	pid = 0;
-	pcurplaying = -1;
 
-	if(pcur < 0)
-		return;
+	sendul(player->ctl, Cstop);
+	recvp(player->ev); /* wait until it dies */
+	chanclose(player->ev);
+	chanclose(player->ctl);
+	free(player);
+}
 
-	if(ctx.quit == nil)
-		ctx.quit = chancreate(sizeof(void*), 0);
+static void
+start(Player *player)
+{
+	if(player != nil)
+		sendul(player->ctl, Cstart);
+}
 
-	pipe(&p[0]);
-	pipe(&p[2]);
-	if((pid = rfork(RFFDG|RFREND|RFPROC)) == 0){
-		close(p[1]); dup(p[0], 0);
-		close(p[2]); dup(p[3], 1);
-		close(2); open("/dev/null", OWRITE);
-		execl("/bin/rc", "-c", "play", "-o", "/fd/1", "/fd/0", nil);
-	}
-	if(pid < 0)
-		sysfatal("%r");
-	close(p[0]);
-	close(p[3]);
-	ctx.in = p[1];
-	ctx.out = p[2];
-	pid = proccreate(player, &ctx, 4096);
-	pcurplaying = pcur;
+static void
+toggle(Player *player)
+{
+	if(player != nil)
+		sendul(player->ctl, Ctoggle);
 }
 
 static void
@@ -256,6 +236,7 @@
 threadmain(int argc, char **argv)
 {
 	int inv;
+	Player *player;
 
 	inv = 0;
 	ARGBEGIN{
@@ -266,11 +247,14 @@
 		usage();
 	}ARGEND
 
-	readplist();
+	audio = open("/dev/audio", OWRITE);
+	if(audio < 0)
+		sysfatal("audio: %r");
 
+	readplist();
 	if(plen < 1){
 		fprint(2, "empty playlist\n");
-		exits("empty");
+		sysfatal("empty");
 	}
 
 	if(initdraw(0, 0, "zuke") < 0)
@@ -282,14 +266,15 @@
 	einit(Emouse | Ekeyboard);
 	srand(time(0));
 	pcurplaying = -1;
+	player = nil;
+	threadsetname("zuke");
 
 	redraw(screen, 1);
 
 	for(;;){
-		int oldpcur, oldpcurplaying, key;
+		int oldpcur, key;
 		Event e;
 
-		oldpcurplaying = pcurplaying;
 		oldpcur = pcur;
 		key = event(&e);
 
@@ -296,48 +281,59 @@
 		if(key == Emouse){
 			if(e.mouse.buttons > 0){
 				pcur = scroll + (e.mouse.xy.y - screen->r.min.y)/f->height;
-				if(e.mouse.buttons == 4)
-					play();
+				if(e.mouse.buttons == 4){
+					stop(player);
+					player = newplayer(pcur);
+					start(player);
+				}
 			}
 		}
 		else if(key == Ekeyboard){
-			if(e.kbdc == Kup)
+			if(e.kbdc == Kup){
 				pcur--;
-			else if(e.kbdc == Kpgup)
+			}else if(e.kbdc == Kpgup){
 				pcur -= scrollsz;
-			else if(e.kbdc == Kdown)
+			}else if(e.kbdc == Kdown){
 				pcur++;
-			else if(e.kbdc == Kpgdown)
+			}else if(e.kbdc == Kpgdown){
 				pcur += scrollsz;
-			else if(e.kbdc == Kend)
+			}else if(e.kbdc == Kend){
 				pcur = plen-1;
-			else if(e.kbdc == Khome)
+			}else if(e.kbdc == Khome){
 				pcur = 0;
-			else if(e.kbdc == 0x0a)
-				play();
-			else if(e.kbdc == 'q' || e.kbdc == Kesc)
+			}else if(e.kbdc == 0x0a){
+				stop(player);
+				player = newplayer(pcur);
+				start(player);
+			}else if(e.kbdc == 'q' || e.kbdc == Kesc){
+				stop(player);
 				break;
-			else if(e.kbdc == 'o')
+			}else if(e.kbdc == 'o'){
 				pcur = pcurplaying;
-			else if(e.kbdc == '>' && pcurplaying >= 0){
+			}else if(e.kbdc == '>' && pcurplaying >= 0){
 				pcur = pcurplaying;
 				if(++pcur >= plen)
 					pcur = 0;
-				play();
-			}
-			else if(e.kbdc == '<' && pcurplaying >= 0){
+				stop(player);
+				player = newplayer(pcur);
+				start(player);
+			}else if(e.kbdc == '<' && pcurplaying >= 0){
 				pcur = pcurplaying;
 				if(--pcur < 0)
 					pcur = plen-1;
-				play();
-			}
-			else if(e.kbdc == 's' && pid > 0){
+				stop(player);
+				player = newplayer(pcur);
+				start(player);
+			}else if(e.kbdc == 's' && player != nil){
 				pcur = -1;
-				play();
+				stop(player);
+				player = nil;
+			}else if(e.kbdc == 'p'){
+				toggle(player);
 			}
 		}
 
-		if(pcur != oldpcur || oldpcurplaying != pcurplaying){
+		if(pcur != oldpcur){
 			if(pcur < 0)
 				pcur = 0;
 			else if(pcur >= plen)
@@ -353,12 +349,10 @@
 			else if(scroll < 0)
 				scroll = 0;
 
-			if(pcur != oldpcur || oldpcurplaying != pcurplaying)
+			if(pcur != oldpcur)
 				redraw(screen, 1);
 		}
 	}
 
-	pcur = -1;
-	play();
 	threadexitsall(nil);
 }