/*
* 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
*/
#include <config.h>
+#include "types.h"
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <pcre.h>
#include <ao/ao.h>
+#include <sys/wait.h>
#include "event.h"
#include "log.h"
#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"
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 %s",
+ wstat(status));
}
/* called when speaker process has something to say */
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;
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) {
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();
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 */