+ return START_OK; /* Not a raw player */
+ const int rc = play_background(ev, player, q, prepare_child, NULL);
+ if(rc == START_OK) {
+ ev_child(ev, q->pid, 0, player_finished, q);
+ q->prepared = 1;
+ }
+ return rc;
+}
+
+/** @brief Child-process half of prepare() */
+static int prepare_child(struct queue_entry *q,
+ const struct pbgc_params *params,
+ void attribute((unused)) *bgdata) {
+ /* np will be the pipe to disorder-normalize */
+ int np[2];
+ if(socketpair(PF_UNIX, SOCK_STREAM, 0, np) < 0)
+ fatal(errno, "error calling socketpair");
+ /* Beware of the Leopard! On OS X 10.5.x, the order of the shutdown
+ * calls here DOES MATTER. If you do the SHUT_WR first then the SHUT_RD
+ * fails with "Socket is not connected". I think this is a bug but
+ * provided implementors either don't care about the order or all agree
+ * about the order, choosing the reliable order is an adequate
+ * workaround. */
+ xshutdown(np[1], SHUT_RD); /* decoder writes to np[1] */
+ xshutdown(np[0], SHUT_WR); /* normalize reads from np[0] */
+ blocking(np[0]);
+ blocking(np[1]);
+ /* Start disorder-normalize. We double-fork so that nothing has to wait
+ * for disorder-normalize. */
+ pid_t npid;
+ if(!(npid = xfork())) {
+ /* Grandchild of disorderd */
+ if(!xfork()) {
+ /* Great-grandchild of disorderd */
+ /* Connect to the speaker process */
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof addr);
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof addr.sun_path,
+ "%s/speaker/socket", config->home);
+ int sfd = xsocket(PF_UNIX, SOCK_STREAM, 0);
+ if(connect(sfd, (const struct sockaddr *)&addr, sizeof addr) < 0)
+ fatal(errno, "connecting to %s", addr.sun_path);
+ /* Send the ID, with a NATIVE-ENDIAN 32 bit length */
+ uint32_t l = strlen(q->id);
+ if(write(sfd, &l, sizeof l) < 0
+ || write(sfd, q->id, l) < 0)
+ fatal(errno, "writing to %s", addr.sun_path);
+ /* Await the ack */
+ if (read(sfd, &l, 1) < 0)
+ fatal(errno, "reading ack from %s", addr.sun_path);
+ /* Plumbing */
+ xdup2(np[0], 0);
+ xdup2(sfd, 1);
+ xclose(np[0]);
+ xclose(np[1]);
+ xclose(sfd);
+ /* TODO stderr shouldn't be redirected for disorder-normalize
+ * (but it should be for play_track() */
+ execlp("disorder-normalize", "disorder-normalize",
+ log_default == &log_syslog ? "--syslog" : "--no-syslog",
+ "--config", configfile,
+ (char *)0);
+ fatal(errno, "executing disorder-normalize");
+ /* End of the great-grandchild of disorderd */
+ }
+ /* Back in the grandchild of disorderd */
+ _exit(0);
+ /* End of the grandchild of disorderd */
+ }
+ /* Back in the child of disorderd */
+ /* Wait for the grandchild of disordered to finish */
+ int n;
+ while(waitpid(npid, &n, 0) < 0 && errno == EINTR)
+ ;
+ /* Pass the file descriptor to the driver in an environment
+ * variable. */
+ char buffer[64];
+ 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(np[0]);
+ /* Start the decoder itself */
+ play_track(q->pl,
+ params->argv, params->argc,
+ params->rawpath,
+ q->track);
+ return 0;