#include <libdaemon/dlog.h>
+#ifdef CONFIG_ALSA
+void set_alsa_out_dev(char *);
+#endif
+
// true if Shairport Sync is supposed to be sending output to the output device, false otherwise
static volatile int requested_connection_state_to_output = 1;
void command_start(void) {
if (config.cmd_start) {
+ pid_t pid;
+ int pipes[2];
+
+ if (config.cmd_start_returns_output && pipe(pipes) != 0) {
+ warn("Unable to allocate pipe for popen of start command.");
+ debug(1, "pipe finished with error %d", errno);
+ return;
+ }
/*Spawn a child to run the program.*/
- pid_t pid = fork();
+ pid = fork();
if (pid == 0) { /* child process */
int argC;
char **argV;
+
+ if (config.cmd_start_returns_output) {
+ close(pipes[0]);
+ if (dup2(pipes[1], 1) < 0) {
+ warn("Unable to reopen pipe as stdout for popen of start command");
+ debug(1, "dup2 finished with error %d", errno);
+ close(pipes[1]);
+ return;
+ }
+ }
+
// debug(1,"on-start command found.");
if (poptParseArgvString(config.cmd_start, &argC, (const char ***)&argV) !=
0) // note that argV should be free()'d after use, but we expect this fork to exit
exit(127); /* only if execv fails */
}
} else {
- if (config.cmd_blocking) { /* pid!=0 means parent process and if blocking is true, wait for
+ if (config.cmd_blocking || config.cmd_start_returns_output) { /* pid!=0 means parent process and if blocking is true, wait for
process to finish */
pid_t rc = waitpid(pid, 0, 0); /* wait for child to exit */
if (rc != pid) {
warn("Execution of on-start command returned an error.");
debug(1, "on-start command %s finished with error %d", config.cmd_start, errno);
}
+ if (config.cmd_start_returns_output) {
+ static char buffer[256];
+ int len;
+ close(pipes[1]);
+ len = read(pipes[0], buffer, 255);
+ close(pipes[0]);
+ buffer[len] = '\0';
+ if (buffer[len - 1] == '\n')
+ buffer[len - 1] = '\0'; // strip trailing newlines
+ debug(1, "received '%s' as the device to use from the on-start command", buffer);
+#ifdef CONFIG_ALSA
+ set_alsa_out_dev(buffer);
+#endif
+ }
}
// debug(1,"Continue after on-start command");
}
int statistics_requested, use_negotiated_latencies;
enum playback_mode_type playback_mode;
char *cmd_start, *cmd_stop, *cmd_set_volume;
- int cmd_blocking;
+ int cmd_blocking, cmd_start_returns_output;
double tolerance; // allow this much drift before attempting to correct it
enum stuffing_type packet_stuffing;
int decoders_supported;
"\"yes\" or \"no\"");
}
+ if (config_lookup_string(config.cfg, "sessioncontrol.before_play_begins_returns_output", &str)) {
+ if (strcasecmp(str, "no") == 0)
+ config.cmd_start_returns_output = 0;
+ else if (strcasecmp(str, "yes") == 0)
+ config.cmd_start_returns_output = 1;
+ else
+ die("Invalid session control before_play_begins_returns_output option choice \"%s\". It should be "
+ "\"yes\" or \"no\"");
+ }
+
if (config_lookup_string(config.cfg, "sessioncontrol.allow_session_interruption", &str)) {
config.dont_check_timeout = 0; // this is for legacy -- only set by -t 0
if (strcasecmp(str, "no") == 0)
debug(1, "on-start action is \"%s\".", config.cmd_start);
debug(1, "on-stop action is \"%s\".", config.cmd_stop);
debug(1, "wait-cmd status is %d.", config.cmd_blocking);
+ debug(1, "on-start returns output is %d.", config.cmd_start_returns_output);
debug(1, "mdns backend \"%s\".", config.mdns_name);
debug(2, "userSuppliedLatency is %d.", config.userSuppliedLatency);
debug(2, "AirPlayLatency is %d.", config.AirPlayLatency);