X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/763d5e6ad88ef3ba1cd1d7742d060e4f1e54c6b8..2a6c7b7954660db70734a4485981864498f80155:/server/play.c diff --git a/server/play.c b/server/play.c index 3b18891..be25dda 100644 --- a/server/play.c +++ b/server/play.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder. - * Copyright (C) 2004, 2005, 2006 Richard Kettlewell + * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ */ #include +#include "types.h" #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include "event.h" #include "log.h" @@ -47,7 +49,7 @@ #include "eventlog.h" #include "logfd.h" #include "syscalls.h" -#include "speaker.h" +#include "speaker-protocol.h" #include "disorder.h" #include "signame.h" #include "hash.h" @@ -85,10 +87,8 @@ static int speaker_terminated(ev_source attribute((unused)) *ev, int attribute((unused)) status, const struct rusage attribute((unused)) *rusage, void attribute((unused)) *u) { - if(status) - error(0, "speaker subprocess terminated with status %s", - wstat(status)); - return 0; + fatal(0, "speaker subprocess terminated with status %s", + wstat(status)); } /* called when speaker process has something to say */ @@ -291,7 +291,7 @@ static int start(ev_source *ev, int smop) { int n, lfd; const char *p; - int sp[2]; + int np[2], sp[2]; struct speaker_message sm; char buffer[64]; int optc; @@ -301,7 +301,7 @@ static int start(ev_source *ev, struct timespec ts; const char *waitdevice = 0; const char *const *optv; - pid_t pid; + pid_t pid, npid; memset(&sm, 0, sizeof sm); if(find_player_pid(q->id) > 0) { @@ -365,21 +365,53 @@ static int start(ev_source *ev, xclose(lfd); /* tidy up */ setpgid(0, 0); if((q->type & DISORDER_PLAYER_TYPEMASK) == DISORDER_PLAYER_RAW) { - /* Raw format players write down a pipe (in fact a socket) to - * the speaker process. */ + /* "Raw" format players need special treatment: + * 1) their output needs to go via the disorder-normalize process + * 2) the output of that needs to be passed to the disorder-speaker + * process. + */ + /* np will be the pipe to disorder-normalize */ + if(socketpair(PF_UNIX, SOCK_STREAM, 0, np) < 0) + fatal(errno, "error calling socketpair"); + xshutdown(np[0], SHUT_WR); /* normalize reads from np[0] */ + xshutdown(np[1], SHUT_RD); /* decoder writes to np[1] */ + /* sp will be the pipe to disorder-speaker */ sm.type = smop; - strcpy(sm.id, q->id); if(socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) fatal(errno, "error calling socketpair"); - xshutdown(sp[0], SHUT_WR); - xshutdown(sp[1], SHUT_RD); + xshutdown(sp[0], SHUT_WR); /* speaker reads from sp[0] */ + xshutdown(sp[1], SHUT_RD); /* normalize writes to sp[1] */ + /* Start disorder-normalize */ + if(!(npid = xfork())) { + if(!xfork()) { + xdup2(np[0], 0); + xdup2(sp[1], 1); + xclose(np[0]); + xclose(np[1]); + xclose(sp[0]); + xclose(sp[1]); + execlp("disorder-normalize", "disorder-normalize", (char *)0); + fatal(errno, "executing disorder-normalize"); + } + _exit(0); + } else { + int w; + + while(waitpid(npid, &w, 0) < 0 && errno == EINTR) + ; + } + /* Send the speaker process the file descriptor to read from */ + strcpy(sm.id, q->id); speaker_send(speaker_fd, &sm, sp[0]); /* Pass the file descriptor to the driver in an environment * variable. */ - snprintf(buffer, sizeof buffer, "DISORDER_RAW_FD=%d", sp[1]); + snprintf(buffer, sizeof buffer, "DISORDER_RAW_FD=%d", np[1]); if(putenv(buffer) < 0) fatal(errno, "error calling putenv"); + /* Close all the FDs we don't need */ xclose(sp[0]); + xclose(sp[1]); + xclose(np[0]); } if(waitdevice) { ao_initialize(); @@ -458,24 +490,31 @@ void abandon(ev_source attribute((unused)) *ev, int add_random_track(void) { struct queue_entry *q; const char *p; + long qlen = 0; + int rc = 0; /* If random play is not enabled then do nothing. */ if(shutting_down || !random_is_enabled()) return 0; - /* If there is already a random track, do nothing. */ + /* Count how big the queue is */ for(q = qhead.next; q != &qhead; q = q->next) - if(q->state == playing_random) - return 0; - /* Try to pick a random track */ - if(!(p = trackdb_random(16))) - return -1; - /* Add it to the end of the queue. */ - q = queue_add(p, 0, WHERE_END); - q->state = playing_random; + ++qlen; + /* Add random tracks until the queue is at the right size */ + while(qlen < config->queue_pad) { + /* Try to pick a random track */ + if(!(p = trackdb_random(16))) { + rc = -1; + break; + } + /* Add it to the end of the queue. */ + q = queue_add(p, 0, WHERE_END); + q->state = playing_random; + D(("picked %p (%s) at random", (void *)q, q->track)); + ++qlen; + } /* Commit the queue */ queue_write(); - D(("picked %p (%s) at random", (void *)q, q->track)); - return 0; + return rc; } /* try to play a track */