From 8f6e2137366506b0ef6895ffc00575f6338a35e7 Mon Sep 17 00:00:00 2001 From: Matthew Flint Date: Mon, 18 Apr 2011 00:55:42 +0100 Subject: [PATCH] added command-line options for named pipes --- hairtunes.c | 73 ++++++++++++++++++++++++++++++++++++++++++---------- shairport.pl | 32 +++++++++++++++++------ 2 files changed, 84 insertions(+), 21 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index 206fc0bd..868b96e8 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #if !defined(HAVE_AO) #define HAVE_AO 1 @@ -73,6 +75,7 @@ int dataport = 0, controlport = 0, timingport = 0; int fmtp[32]; int sampling_rate; int frame_size; +char *pipename = 0; #define FRAME_BYTES (4*frame_size) // maximal resampling shift - conservative #define OUTFRAME_BYTES (4*(frame_size+3)) @@ -187,7 +190,10 @@ int main(int argc, char **argv) { } else if (!strcasecmp(arg, "host")) { rtphost = *++argv; - } + } else + if (!strcasecmp(arg, "pipe")) { + pipename = *++argv; + } #ifdef FANCY_RESAMPLING else if (!strcasecmp(arg, "resamp")) { @@ -659,16 +665,27 @@ int stuff_buffer(double playback_rate, short *inptr, short *outptr) { void *audio_thread_func(void *arg) { #if HAVE_AO - ao_device* dev = arg; + ao_device* dev = arg; #else - PaStream* stream = arg; + PaStream* stream = arg; #endif + // file handle for named pipe + int fd = -1; + int i __attribute__((unused)), play_samples; signed short buf_fill __attribute__((unused)); signed short *inbuf, *outbuf; outbuf = malloc(OUTFRAME_BYTES); + if (pipename) { + fd = open(pipename, O_WRONLY); + if (fd == -1) { + printf( "Pipe open failure: %s\n", pipename ); + exit(1); + } + } + #ifdef FANCY_RESAMPLING float *frame, *outframe; SRC_DATA srcdat; @@ -703,17 +720,26 @@ void *audio_thread_func(void *arg) { play_samples = srcdat.output_frames_gen; } else #endif + play_samples = stuff_buffer(bf_playback_rate, inbuf, outbuf); + if (pipename) { + int ret = write(fd, outbuf, play_samples*4); + if (!ret) { + printf( "Pipe write error" ); + exit(1); + } + } else { #if HAVE_AO - ao_play(dev, (char *)outbuf, play_samples*4); + ao_play(dev, (char *)outbuf, play_samples*4); #else - int err = Pa_WriteStream(stream, (char *)outbuf, play_samples*4); - if( err != paNoError ) { - printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); - exit(1); - } + int err = Pa_WriteStream(stream, (char *)outbuf, play_samples*4); + if( err != paNoError ) { + printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); + exit(1); + } #endif + } } return 0; @@ -721,9 +747,13 @@ void *audio_thread_func(void *arg) { #define NUM_CHANNELS 2 -int init_output(void) { - int err __attribute__((unused)); +void* init_pipe(char* pipe) { + mknod(pipe, S_IFIFO | 0644, 0); + return NULL; +} + #if HAVE_AO +void* init_ao() { ao_initialize(); int driver = ao_default_driver_id(); @@ -736,8 +766,11 @@ int init_output(void) { fmt.byte_format = AO_FMT_LITTLE; ao_device *dev = ao_open_live(driver, &fmt, 0); - void* arg = dev; + return dev; +} #else +void* init_portaudio() { + int err __attribute__((unused)); err = Pa_Initialize(); if( err != paNoError ) { printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) ); @@ -773,9 +806,23 @@ int init_output(void) { exit(1); } - void* arg = stream; + return stream; +} #endif +int init_output(void) { + void* arg = 0; + + if (pipename) { + arg = init_pipe(pipename); + } else { +#if HAVE_AO + arg = init_ao(); +#else + arg = init_portaudio(); +#endif + } + #ifdef FANCY_RESAMPLING if (fancy_resampling) src = src_new(SRC_SINC_MEDIUM_QUALITY, 2, &err); diff --git a/shairport.pl b/shairport.pl index a7d00297..359528a7 100755 --- a/shairport.pl +++ b/shairport.pl @@ -48,12 +48,15 @@ my $apname = "ShairPort $$ on " . `hostname`; # password - required to connect # for no password, set: my $password = ''; +# output to a pipe? +my $pipepath; my $daemon; # suppose hairtunes is under same directory my $hairtunes_cli = $FindBin::Bin . '/hairtunes'; GetOptions("a|apname=s" => \$apname, "p|password=s" => \$password, + "i|pipe=s" => \$pipepath, "d" => \$daemon, "h|help" => \$help); @@ -65,6 +68,7 @@ sub usage { "Options:\n". " -a, --apname=AirPort Sets AirPort name\n". " -p, --password=secret Sets password\n", + " -i, --pipe=pipepath Sets the path to a named pipe for output\n", " -d Daemon mode\n", " -h, --help This help\n", "\n"; @@ -334,14 +338,26 @@ sub conn_handle_request { $resp->header('Session', 'DEADBEEF'); - my $dec = sprintf("$hairtunes_cli iv %s key %s fmtp %s cport %s tport %s dport %s host %s", - map { "'$_'" } ( - unpack('H*', $conn->{aesiv}), - unpack('H*', $conn->{aeskey}), - $conn->{fmtp}, - $cport, $tport, $dport, - 'unused' - )); + my $dec; + if (defined($pipepath)) { + $dec = sprintf("$hairtunes_cli iv %s key %s fmtp %s cport %s tport %s dport %s host %s pipe %s", + map { "'$_'" } ( + unpack('H*', $conn->{aesiv}), + unpack('H*', $conn->{aeskey}), + $conn->{fmtp}, + $cport, $tport, $dport, + 'unused', $pipepath + )); + } else { + $dec = sprintf("$hairtunes_cli iv %s key %s fmtp %s cport %s tport %s dport %s host %s", + map { "'$_'" } ( + unpack('H*', $conn->{aesiv}), + unpack('H*', $conn->{aeskey}), + $conn->{fmtp}, + $cport, $tport, $dport, + 'unused' + )); + } # print "decode command: $dec\n"; my $decoder = open2(my $dec_out, my $dec_in, $dec);