- /* Call the prefork function. */
- p = trackdb_rawpath(q->track);
- if(q->type & DISORDER_PLAYER_PREFORK)
- if(!(q->data = play_prefork(q->pl, p))) {
- error(0, "prefork function for %s failed", q->track);
- return START_HARDFAIL;
- }
- /* Use the second arg as the tag if available (it's probably a command name),
- * otherwise the module name. */
- if(!isatty(2))
- lfd = logfd(ev, (config->player.s[n].s[2]
- ? config->player.s[n].s[2] : config->player.s[n].s[1]));
- else
- lfd = -1;
- optc = config->player.s[n].n - 2;
- optv = (void *)&config->player.s[n].s[2];
- while(optc > 0 && optv[0][0] == '-') {
- if(!strcmp(optv[0], "--")) {
- ++optv;
- --optc;
- break;
- }
- if(!strcmp(optv[0], "--wait-for-device")
- || !strncmp(optv[0], "--wait-for-device=", 18)) {
- if((waitdevice = strchr(optv[0], '='))) {
- ++waitdevice;
- } else
- waitdevice = ""; /* use default */
- ++optv;
- --optc;
- } else {
- error(0, "unknown option %s", optv[0]);
- return START_HARDFAIL;
- }
- }
- switch(pid = fork()) {
- case 0: /* child */
- exitfn = _exit;
- progname = "disorderd-fork";
- ev_signal_atfork(ev);
- signal(SIGPIPE, SIG_DFL);
- if(lfd != -1) {
- xdup2(lfd, 1);
- xdup2(lfd, 2);
- xclose(lfd); /* tidy up */
- }
- setpgid(0, 0);
- if((q->type & DISORDER_PLAYER_TYPEMASK) == DISORDER_PLAYER_RAW) {
- /* "Raw" format players always have their output send down a pipe
- * to the disorder-normalize process. This will connect to the
- * speaker process to actually play the audio data.
- */
- /* np will be the pipe to disorder-normalize */
- 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 */
- if(!(npid = xfork())) {
- if(!xfork()) {
- /* Connect to the speaker process */
- memset(&addr, 0, sizeof addr);
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path, sizeof addr.sun_path,
- "%s/speaker/socket", config->home);
- 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);
- 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 */
- read(sfd, &l, 1);
- /* Plumbing */
- xdup2(np[0], 0);
- xdup2(sfd, 1);
- xclose(np[0]);
- xclose(np[1]);
- xclose(sfd);
- /* Ask the speaker to actually start playing the track; we do it here
- * so it's definitely after ack. */
- if(!prepare_only) {
- strcpy(sm.id, q->id);
- sm.type = SM_PLAY;
- speaker_send(speaker_fd, &sm);
- D(("sent SM_PLAY for %s", sm.id));
- }
- /* 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 innermost fork */
- }
- _exit(0);
- /* end of the middle fork */
- }
- /* Wait for the middle fork to finish */
- while(waitpid(npid, &n, 0) < 0 && errno == EINTR)
- ;
- /* Pass the file descriptor to the driver in an environment
- * variable. */
- 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]);
- }
- if(waitdevice) {
- ao_initialize();
- if(*waitdevice) {
- n = ao_driver_id(waitdevice);
- if(n == -1)
- fatal(0, "invalid libao driver: %s", optv[0]);
- } else
- n = ao_default_driver_id();
- /* Make up a format. */
- memset(&format, 0, sizeof format);
- format.bits = 8;
- format.rate = 44100;
- format.channels = 1;
- format.byte_format = AO_FMT_NATIVE;
- retries = 20;
- ts.tv_sec = 0;
- ts.tv_nsec = 100000000; /* 0.1s */
- while((device = ao_open_live(n, &format, 0)) == 0 && retries-- > 0)
- nanosleep(&ts, 0);
- if(device)
- ao_close(device);
- }
- play_track(q->pl,
- optv, optc,
- p,
- q->track);
- _exit(0);
- case -1: /* error */
- error(errno, "error calling fork");
- if(q->type & DISORDER_PLAYER_PREFORK)
- play_cleanup(q->pl, q->data); /* else would leak */
- if(lfd != -1)
- xclose(lfd);
- return START_SOFTFAIL;