From: Cody Cutrer Date: Sun, 25 Jun 2017 01:27:37 +0000 (-0600) Subject: read stdout from the on-start command to choose ALSA output device X-Git-Tag: 3.1~10^2~38^2 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F545%2Fhead;p=thirdparty%2Fshairport-sync.git read stdout from the on-start command to choose ALSA output device refs GH-452 --- diff --git a/audio_alsa.c b/audio_alsa.c index 30183505..e0dae558 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -109,6 +109,10 @@ static void help(void) { " *) default option\n"); } +void set_alsa_out_dev(char *dev) { + alsa_out_dev = dev; +} + int open_mixer() { if (hardware_mixer) { debug(2, "Open Mixer"); diff --git a/common.c b/common.c index c13f1857..fedff727 100644 --- a/common.c +++ b/common.c @@ -80,6 +80,10 @@ #include +#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; @@ -504,11 +508,30 @@ void command_set_volume(double volume) { 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 @@ -522,13 +545,27 @@ void command_start(void) { 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"); } diff --git a/common.h b/common.h index f425c15e..2cfeaba7 100644 --- a/common.h +++ b/common.h @@ -116,7 +116,7 @@ typedef struct { 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; diff --git a/shairport.c b/shairport.c index 664ed357..b0b31651 100644 --- a/shairport.c +++ b/shairport.c @@ -694,6 +694,16 @@ int parse_options(int argc, char **argv) { "\"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) @@ -1276,6 +1286,7 @@ int main(int argc, char **argv) { 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);