henesyinit from lsubb0c8bdb6 years agoHistory
465 lines · 7.5 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <omero.h>#include <plumb.h>#include <error.h>#include <b.h>  typedef struct Player	Player;typedef struct Evh	Evh; enum {	KF=	0xF000,	/* Rune: beginning of private Unicode space */	Spec=	0xF800,	Kup=	KF|0x0E,	Kdown=	Spec|0x00,}; struct Player{	char*	dir;	char**	songs;	int	nsongs;	int	active;	int	pause;	int	pid;	// of player process 	Panel*	gtag;	Panel*	gsongcol;	Panel*	gsongs;	Panel*	gpause;}; struct Evh {	char*	name;	void	(*f)(Player*, Oev*);};  Player p; static char playbuf[4*1024];static Channel*	plumbc; void update(Player*); voidomerogone(void){	sysfatal("terminated");} static voidplayproc(void *a){	int	fd, afd;	int	n, wn;	int	playing;	Player*	p = a; 	threadsetname("playproc");again:	if (p->active < 0 || p->active >= p->nsongs)		threadexits("bug");	fd = open(p->songs[p->active], OREAD);	afd= open("/devs/audio/audio", OWRITE);	if (fd < 0 || afd < 0){		close(fd);		close(afd);		threadexits("open");	}	playing = p->active;	do{		if (p->pause){			while(p->pause)				sleep(100);			if (playing != p->active){				wn = -1;				n = 0;				break;			}		}		wn = n = read(fd, playbuf, sizeof(playbuf));		if (n > 0)			wn = write(afd, playbuf, n);	} while(n  > 0 && wn == n && playing == p->active);	close(fd);	close(afd);	if (n < 0 || n != wn)		threadexits("io");	if (playing == p->active){		p->active++;		if (p->active == p->nsongs)			p->active = 0;		update(p);		goto again;	}	threadexits(nil);} voidplay(Player* p){	proccreate(playproc, p, 16*1024);} voidstop(Player* p){	p->active = -1;} static voidplumbimg(char* dir, char* arg){	Plumbmsg*m;	static int	plumbsendfd = -1; 	if (plumbsendfd < 0)		plumbsendfd = open("/mnt/plumb/send", OWRITE|OCEXEC);	if (plumbsendfd < 0)		return;	m = malloc(sizeof(Plumbmsg));	if (m == nil)		return;	m->src = strdup(argv0);	m->dst = strdup("poster");	m->wdir= strdup(dir);	m->type = strdup("text");	m->attr = nil;	m->data = smprint("%s/%s", dir, arg);	m->ndata= -1;	assert(m->wdir && m->src && m->data);	plumbsend(plumbsendfd, m);	plumbfree(m);} static intmayplumbimg(char* dir, char* f){	int	n; 	n = strlen(f);	if (n < 5)		return 0;	n -= 4;	if (!cistrcmp(f+n, ".jpg") || !strcmp(f+n, ".gif") || !strcmp(f+n, ".img") || !strcmp(f+n, ".png")){		plumbimg(dir, f);		return 1;	}	return 0;} intreadsongs(Player* p, char* dir){	Dir*	ents;	int	fd;	int	i;	char	buf[512];	int	hasfiles; 	if (chdir(dir) < 0)		return -1;	getwd(buf, sizeof(buf));	fd = open(".", OREAD);	if (fd < 0)		return -1;	free(p->dir);	p->dir = estrdup(buf);	for (i = 0; i < p->nsongs; i++)		free(p->songs[i]);	free(p->songs);	p->songs = 0;	p->nsongs = dirreadall(fd, &ents);	close(fd);	if (p->nsongs < 0){		return -1;	}	p->songs = emalloc(p->nsongs * sizeof(char*));	hasfiles = 0;	for (i = 0; i < p->nsongs; i++)		if (ents[i].qid.type&QTDIR)			p->songs[i] = smprint("%s/", ents[i].name);		else {			hasfiles++;			p->songs[i] = estrdup(ents[i].name);			mayplumbimg(p->dir, ents[i].name);		}	free(ents);	p->active = -1;	p->pause = 0;	if (hasfiles)		evhistory("oplayer", "look", p->dir);	return hasfiles;} voidcontrols(Panel* w){	Panel*	c; 	createsubpanel(w, "button:Play");	createsubpanel(w, "button:Stop");	createsubpanel(w, "button:Next");	createsubpanel(w, "button:Done");	p.gpause = createsubpanel(w, "button:Pause");	c = createsubpanel(w, "slider:volume");	openpanel(c, OWRITE);	writepanel(c, "75", 2);	closepanel(c);	openpanelctl(c);	panelctl(c, "tag");	closepanelctl(c);}  voidshowlist(Player* p){	int	i;	char*	s;	char*	txt;	char*	mrk;	char*	ap; 	txt = emalloc(32*1024);	s = ap = txt;	*txt = 0;	for (i = 0; i < p->nsongs; i++){		if (i != p->active)			mrk = "";		else {			ap = s;			mrk = "->";		}		s = seprint(s, txt+(32*1024), "%s\t%s\n", mrk, p->songs[i]);	}	if (!txt[0])		strcpy(txt, "no songs.");	openpanel(p->gsongs, OWRITE|OTRUNC);	writepanel(p->gsongs, txt, strlen(txt));	closepanel(p->gsongs);	openpanelctl(p->gsongs);	panelctl(p->gsongs, "sel %d %d\n", ap - txt, ap - txt);	closepanelctl(p->gsongs);	free(txt);} voidui(Panel* w){	Panel*	c; 	p.gtag = createsubpanel(w, "tag:player");	c = createsubpanel(w, "row:controls");	controls(c);	p.gsongs = createsubpanel(w, "text:songs");} voidupdate(Player* p){	char*	tag; 	tag = smprint("player — %s ..", p->dir ? p->dir : "no dir");	openpanel(p->gtag, OWRITE|OTRUNC);	writepanel(p->gtag, tag, strlen(tag));	closepanel(p->gtag);	free(tag);	showlist(p);}  intisdir(char* p){	Dir*	d;	int	r; 	d = dirstat(p);	if (d == nil)		return 0;	r = (d->qid.type&QTDIR);	free(d);	return r;} static intfindsong(Player* p, char* s){	int	i; 	for (i = 0; i < p->nsongs; i++)		if (!strcmp(p->songs[i], s))			return i;	// no exact match, try substring	for (i = 0; i < p->nsongs; i++)		if (strstr(p->songs[i], s))			return i; 	return 0;} voidplayfile(Player* p, char* file){	char*	d; 	if (isdir(file)){		if (readsongs(p, file) > 0){			p->active = p->pause = 0;			play(p);		}		update(p);	} else if (access(file, AREAD) != -1){		d = utfrrune(file, '/');		if (d)			*d++ = 0;		readsongs(p, d ? file : ".");		if (d){			p->active = findsong(p, d);			p->pause = 0;			play(p);		}		update(p);	}} voidelook(Player* p, Oev* e){	char	str[40];	int	vol; 	if (strstr(e->path, "/tag:")){		if (readsongs(p, e->arg + 11 + 1) != -1)			update(p);		return;	}	if (strstr(e->path, "/text:songs")){		if (isdir(e->arg + 11 + 1))			readsongs(p, e->arg + 11 + 1);		else {			p->active = findsong(p, e->arg + 11 + 1);			play(p);		}		update(p);	}	if (strstr(e->path, "/button:Play")){		p->active = 0;		play(p);		update(p);		return;	}	if (strstr(e->path, "/button:Stop")){		stop(p);		update(p);		return;	}	if (strstr(e->path, "/button:Done")){		stop(p);		omeroterm();		threadexitsall(nil);	}	if (strstr(e->path, "/button:Pause")){		openpanel(p->gpause, OWRITE|OTRUNC);		if (p->pause){			writepanel(p->gpause,"Pause", 5);			p->pause = 0;		} else {			writepanel(p->gpause,"Resume", 6);			p->pause++;		}		closepanel(p->gpause);		return;	}	if (strstr(e->path, "/button:Next")){		p->active++;		if (p->active == p->nsongs)			p->active = 0;		update(p);		play(p);		return;	}	if (strstr(e->path, "/slider:volume")){		vol = atoi(e->arg);		seprint(str, str+sizeof(str), "audio out %d", vol);		writefstr("/devs/audio/volume", str);	}} voideexit(Player* , Oev* ){	omeroterm();	threadexitsall(nil);} Evh evsh[] = {	{ "Look",	elook },	{ "look",	elook },	{ "exit",	eexit },	{ "exec",	elook },	// BUG	{ "data",	elook },	// BUG};  voidthreadmain(int argc, char* argv[]){	Panel*	w;	Channel* ec;	Oev	e;	Plumbmsg* m;	int	i, ai;	Alt	a[] = {		{ nil, &e, CHANRCV },		{ nil, &m, CHANRCV },		{ nil, nil,CHANEND }}; 	ARGBEGIN{	case 'd':		omerodebug++;		break;	default:		fprint(2, "usage: %s [-d] [dir]\n", argv0);		sysfatal("usage");	}ARGEND;	if (argc > 1){		fprint(2, "usage: %s [-d] [dir]\n", argv0);		sysfatal("usage");	}	ec = omeroeventchan(nil);	a[0].c = ec;	w = createpanel("oplayer", "col", nil);	if (w == nil)		sysfatal("createpanel: %r\n");	plumbc = createportproc("song");	a[1].c = plumbc; 	readsongs(&p, argc ? argv[0] : "/n/music"); 	ui(w); 	update(&p);	closepanelctl(w);	while((ai = alt(a)) != -1){		switch(ai){		case 0:			for (i = 0; i < nelem(evsh); i++)				if (!strcmp(evsh[i].name, e.ev)){					evsh[i].f(&p, &e);					break;				}			clearoev(&e);			break;		case 1:			playfile(&p, m->data);			plumbfree(m);			break;		}	}	eexit(&p, nil);}