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);
}