Skip to content


Subversion checkout URL

You can clone with
Download ZIP


implement start/stop command #201

wants to merge 5 commits into from

3 participants



I use this to turn on/off my stereo via gpio using the perl script. implementing this in your 1.0-dev codebase is quite simple, as long as you regard player.c to be the correct place to call those commands.



Hmm well I should have testet that in the wild before; fails with

Shutting down...
Got SIGTERM, quitting.
failed to accept connection: Interrupted system call
failed to accept connection: Interrupted system call

on my raspi, have to check why


Did you get this one working?


No but I know what the problem is: launching the subprocess from the player thread makes it receive signals from that subprocess. One of these signales interrupt a connect()-call somewhere else in the code.

I see that I'm novice when it comes to unix multithreading, so I'll have to try different solutions:


You need to be careful here - signals are essential to the RTSP multiple connection handling functionality. Also if your external script takes too long at startup, the connection might run into trouble.

fork() would be a better choice from an isolation point of view, but then you start getting SIGCHLD instead - which is currently used to detect death of the mDNS advertising subprocess.

Any idea if SIGCHLD is delivered to the parent thread of the subprocess, or to any old thread that has SIGCHLD unblocked?


You could block SIGCHLD globally (in the main() before threads are spawned) and then add a thread in the mDNS handler that does nothing but waitpid()... but there'd need to be a wait somewhere else to mop up all the dead subprocesses too.


I'd like to have this functionality in the 1.0 release. We need to figure out how to do this right.


I am interested in using a gpio to switch inputs on my radio already got the circuitry figured out and working but, I am super new to all things unix so i dont think i will be of much help as far as the coding goes, but i figured i would say something ...

@abrasive abrasive referenced this pull request from a commit
@abrasive provide -B/-E for running shell commands on begin/end of playing
Implements functionality described by MaZderMind <>
in issue #201.

Implemented. Thanks for the patch!

@abrasive abrasive closed this
@ckassen ckassen referenced this pull request from a commit in ckassen/shairport
@abrasive provide -B/-E for running shell commands on begin/end of playing
Implements functionality described by MaZderMind <>
in issue #201.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 14 additions and 1 deletion.
  1. +2 −0  common.h
  2. +3 −0  player.c
  3. +9 −1 shairport.c
2  common.h
@@ -22,6 +22,8 @@ typedef struct {
uint8_t hw_addr[6];
int port;
char *output_name;
+ char *play_prog;
+ char *stop_prog;
audio_output *output;
int buffer_start_fill;
} shairport_cfg;
3  player.c
@@ -517,9 +517,11 @@ int player_play(stream_cfg *stream) {
please_stop = 0;
+ if(config.play_prog) system(config.play_prog);
pthread_create(&player_thread, NULL, player_thread_func, NULL);
return 0;
@@ -527,6 +529,7 @@ void player_stop(void) {
please_stop = 1;
pthread_join(player_thread, NULL);
+ if(config.stop_prog) system(config.stop_prog);
10 shairport.c
@@ -56,6 +56,8 @@ void usage(char *progname) {
" -h show this help\n"
" -p port set RTSP listening port\n"
" -a name set advertised name\n"
+ " -P command program to launch when playback begins\n"
+ " -S command program to launch when playback ends\n"
" -o output set audio output\n"
" -b fill set how full the buffer must be before audio output starts\n"
" This value is in frames; default %d\n"
@@ -74,7 +76,7 @@ void usage(char *progname) {
int parse_options(int argc, char **argv) {
int opt;
- while ((opt = getopt(argc, argv, "+hvp:a:o:b:")) > 0) {
+ while ((opt = getopt(argc, argv, "+hvp:a:o:b:P:S:")) > 0) {
switch (opt) {
printf("Unknown argument -%c\n", optopt);
@@ -90,6 +92,12 @@ int parse_options(int argc, char **argv) {
case 'a':
config.apname = optarg;
+ case 'P':
+ config.play_prog = optarg;
+ break;
+ case 'S':
+ config.stop_prog = optarg;
+ break;
case 'o':
config.output_name = optarg;
Something went wrong with that request. Please try again.