From f5e7e87c519e578c22a6ed989fac0d62769cdb12 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 14:13:23 -0600 Subject: [PATCH 01/14] Remove dead code in alac.c --- alac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/alac.c b/alac.c index 5c40b2e9..3ad57580 100644 --- a/alac.c +++ b/alac.c @@ -109,7 +109,6 @@ void alac_set_info(alac_file *alac, char *inputbuffer) alac->setinfo_8a_rate = *(uint32_t*)ptr; if (!host_bigendian) _Swap32(alac->setinfo_8a_rate); - ptr += 4; allocate_buffers(alac); From 7fcfd3ddacff06ff537ee5bfdf453aa856513ed3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 14:17:30 -0600 Subject: [PATCH 02/14] Small socketlib static and return value tweaks --- socketlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/socketlib.c b/socketlib.c index 82e63e81..9efdf221 100644 --- a/socketlib.c +++ b/socketlib.c @@ -183,7 +183,7 @@ void delay(long pMillisecs, struct timeval *pRes) select(0,NULL,NULL,NULL,pRes); } -int getCorrectedEncodeSize(int pSize) +static int getCorrectedEncodeSize(int pSize) { if(pSize % 4 == 0) { @@ -264,7 +264,7 @@ char *encode_base64(unsigned char *input, int length) b64 = BIO_push(b64, bmem); BIO_write(b64, input, length); - BIO_flush(b64); + (void)BIO_flush(b64); BIO_get_mem_ptr(b64, &bptr); char *buff = (char *)malloc(bptr->length); From d9964383e6c54520c6ddc5b77652dd223e466e23 Mon Sep 17 00:00:00 2001 From: Stef Simoens Date: Mon, 10 Oct 2011 23:48:41 +0200 Subject: [PATCH 03/14] Improve resending of frames (and avoid missed frames) - when requesting a packet, do not request an already received packet - move the last-chance resend to buffer_get_frame - check more often for missing frames own checks show that some frames need to be requested up to 4 times on bad connections --- hairtunes.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index 21577820..471c42c6 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -354,7 +354,6 @@ void alac_decode(short *dest, char *buf, int len) { void buffer_put_packet(seq_t seqno, char *data, int len) { volatile abuf_t *abuf = 0; - short read; short buf_fill; pthread_mutex_lock(&ab_mutex); @@ -367,7 +366,7 @@ void buffer_put_packet(seq_t seqno, char *data, int len) { abuf = audio_buffer + BUFIDX(seqno); ab_write = seqno; } else if (seq_order(ab_write, seqno)) { // newer than expected - rtp_request_resend(ab_write, seqno-1); + rtp_request_resend(ab_write+1, seqno-1); abuf = audio_buffer + BUFIDX(seqno); ab_write = seqno; } else if (seq_order(ab_read, seqno)) { // late but not yet played @@ -387,15 +386,6 @@ void buffer_put_packet(seq_t seqno, char *data, int len) { ab_buffering = 0; pthread_cond_signal(&ab_buffer_ready); } - if (!ab_buffering) { - // check if the t+10th packet has arrived... last-chance resend - read = ab_read + 10; - abuf = audio_buffer + BUFIDX(read); - if (abuf->ready != 1) { - rtp_request_resend(read, read); - abuf->ready = -1; - } - } } static int rtp_sockets[2]; // data, control @@ -642,6 +632,9 @@ void bf_est_update(short fill) { short *buffer_get_frame(void) { short buf_fill; seq_t read; + volatile abuf_t *abuf = 0; + unsigned short next; + int i; pthread_mutex_lock(&ab_mutex); @@ -670,8 +663,19 @@ short *buffer_get_frame(void) { buf_fill = ab_write - ab_read; bf_est_update(buf_fill); + // check if t+16, t+32, t+64, t+128, ... (START_FILL / 2) packets have arrived... last-chance resend + if (!ab_buffering) { + for (i = 16; i < (START_FILL / 2); i = (i * 2)) { + next = ab_read + i; + abuf = audio_buffer + BUFIDX(next); + if (!abuf->ready) { + rtp_request_resend(next, next); + } + } + } + volatile abuf_t *curframe = audio_buffer + BUFIDX(read); - if (curframe->ready != 1) { + if (!curframe->ready) { fprintf(stderr, "\nmissing frame.\n"); memset(curframe->data, 0, FRAME_BYTES); } From be145fa704b628c990bc4aa19800816f00512ccc Mon Sep 17 00:00:00 2001 From: "B. van Berkum" Date: Sat, 30 Jul 2011 11:48:17 +0200 Subject: [PATCH 04/14] Removed typo in Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 767ce191..17fc3943 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ install: hairtunes shairport install -D -m 0755 shairport.pl $(DESTDIR)$(prefix)/bin/shairport.pl install -D -m 0755 shairport $(DESTDIR)$(prefix)/bin/shairport -.PTHONY: all clean install +.PHONY: all clean install .SILENT: clean From 82e7cf8490d36e5725ff97c3b0172b8919aeb7a0 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 14:22:39 -0600 Subject: [PATCH 05/14] Fix dependency issue in Makefile Make the dependency and compile command match in the resources used. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 17fc3943..0a7d912c 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ OBJS=socketlib.o shairport.o alac.o hairtunes.o all: hairtunes shairport hairtunes: hairtunes.c alac.o - $(CC) $(CFLAGS) -DHAIRTUNES_STANDALONE hairtunes.c alac.c -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) -DHAIRTUNES_STANDALONE hairtunes.c alac.o -o $@ $(LDFLAGS) shairport: $(OBJS) $(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) From 565b223bb09f2c4669b45098695c7e2a9b7249fc Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 14:28:19 -0600 Subject: [PATCH 06/14] Don't require extern usage of frame buffering value This makes things a bit cleaner and easier to grasp. --- hairtunes.c | 10 +++++++--- hairtunes.h | 5 +++-- shairport.c | 11 ++++++----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index 471c42c6..34106a5e 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -163,7 +163,8 @@ int init_decoder(void) { } int hairtunes_init(char *pAeskey, char *pAesiv, char *fmtpstr, int pCtrlPort, int pTimingPort, - int pDataPort, char *pRtpHost, char*pPipeName, char *pLibaoDriver, char *pLibaoDeviceName, char *pLibaoDeviceId) + int pDataPort, char *pRtpHost, char*pPipeName, char *pLibaoDriver, char *pLibaoDeviceName, char *pLibaoDeviceId, + int bufStartFill) { if(pAeskey != NULL) memcpy(aeskey, pAeskey, sizeof(aeskey)); @@ -183,6 +184,9 @@ int hairtunes_init(char *pAeskey, char *pAesiv, char *fmtpstr, int pCtrlPort, in controlport = pCtrlPort; timingport = pTimingPort; dataport = pDataPort; + if(bufStartFill < 0) + bufStartFill = START_FILL; + buffer_start_fill = bufStartFill; AES_set_decrypt_key(aeskey, 128, &aes); @@ -309,7 +313,7 @@ int main(int argc, char **argv) { if (hex2bin(aeskey, hexaeskey)) die("can't understand key"); return hairtunes_init(NULL, NULL, fmtpstr, controlport, timingport, dataport, - NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL, START_FILL); } #endif @@ -654,7 +658,7 @@ short *buffer_get_frame(void) { } if (buf_fill >= BUFFER_FRAMES) { // overrunning! uh-oh. restart at a sane distance fprintf(stderr, "\noverrun.\n"); - ab_read = ab_write - START_FILL; + ab_read = ab_write - buffer_start_fill; } read = ab_read; ab_read++; diff --git a/hairtunes.h b/hairtunes.h index 93589ae6..7666154b 100644 --- a/hairtunes.h +++ b/hairtunes.h @@ -1,7 +1,8 @@ #ifndef _HAIRTUNES_H_ #define _HAIRTUNES_H_ -int hairtunes_init(char *pAeskey, char *pAesiv, char *pFmtpstr, int pCtrlPort, int pTimingPort, - int pDataPort, char *pRtpHost, char*pPipeName, char *pLibaoDriver, char *pLibaoDeviceName, char *pLibaoDeviceId); +int hairtunes_init(char *pAeskey, char *pAesiv, char *fmtpstr, int pCtrlPort, int pTimingPort, + int pDataPort, char *pRtpHost, char*pPipeName, char *pLibaoDriver, char *pLibaoDeviceName, char *pLibaoDeviceId, + int bufStartFill); // default buffer size // needs to be a power of 2 because of the way BUFIDX(seqno) works diff --git a/shairport.c b/shairport.c index 2433456d..924d9401 100644 --- a/shairport.c +++ b/shairport.c @@ -40,7 +40,7 @@ // TEMP int kCurrentLogLevel = LOG_INFO; -extern int buffer_start_fill; +int bufferStartFill = -1; #ifdef _WIN32 #define DEVNULL "nul" @@ -113,12 +113,12 @@ int main(int argc, char **argv) } else if(!strcmp(arg, "-b")) { - buffer_start_fill = atoi(*++argv); + bufferStartFill = atoi(*++argv); argc--; } else if(!strncmp(arg, "--buffer=", 9)) { - buffer_start_fill = atoi(arg + 9); + bufferStartFill = atoi(arg + 9); } else if(!strcmp(arg, "-k")) { @@ -161,7 +161,7 @@ int main(int argc, char **argv) } } - if ( buffer_start_fill < 30 || buffer_start_fill > BUFFER_FRAMES ) { + if ( bufferStartFill < 30 || bufferStartFill > BUFFER_FRAMES ) { fprintf(stderr, "buffer value must be > 30 and < %d\n", BUFFER_FRAMES); return(0); } @@ -774,7 +774,8 @@ int parseMessage(struct connection *pConn, unsigned char *pIpBin, unsigned int p } cleanupBuffers(pConn); hairtunes_init(tKeys->aeskey, tKeys->aesiv, tKeys->fmt, tControlport, tTimingport, - tDataport, tRtp, tPipe, tAoDriver, tAoDeviceName, tAoDeviceId); + tDataport, tRtp, tPipe, tAoDriver, tAoDeviceName, tAoDeviceId, + bufferStartFill); // Quit when finished. slog(LOG_DEBUG, "Returned from hairtunes init....returning -1, should close out this whole side of the fork\n"); From 74ed9c6fa2bda9397de9838dfb4d553d3b82ad36 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 14:48:24 -0600 Subject: [PATCH 07/14] hairtunes: use static keyword appropriately This allows the compiler to do a much better job on this file, as it currently can't inline most of the functions because they are technically visible outside the file. Mark most functions and variables static to let the compiler work. --- hairtunes.c | 126 ++++++++++++++++++++++++++-------------------------- 1 file changed, 64 insertions(+), 62 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index 34106a5e..1a19140a 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -48,7 +48,7 @@ #endif #include -int debug = 0; +static int debug = 0; #include "alac.h" @@ -60,41 +60,41 @@ int debug = 0; typedef unsigned short seq_t; // global options (constant after init) -unsigned char aeskey[16], aesiv[16]; -AES_KEY aes; -char *rtphost = 0; -int dataport = 0, controlport = 0, timingport = 0; -int fmtp[32]; -int sampling_rate; -int frame_size; +static unsigned char aeskey[16], aesiv[16]; +static AES_KEY aes; +static char *rtphost = 0; +static int dataport = 0, controlport = 0, timingport = 0; +static int fmtp[32]; +static int sampling_rate; +static int frame_size; -int buffer_start_fill = START_FILL; +static int buffer_start_fill; -char *libao_driver = NULL; -char *libao_devicename = NULL; -char *libao_deviceid = NULL; // ao_options expects "char*" +static char *libao_driver = NULL; +static char *libao_devicename = NULL; +static char *libao_deviceid = NULL; // ao_options expects "char*" // FIFO name and file handle -char *pipename = NULL; -int pipe_handle = -1; +static char *pipename = NULL; +static int pipe_handle = -1; #define FRAME_BYTES (4*frame_size) // maximal resampling shift - conservative #define OUTFRAME_BYTES (4*(frame_size+3)) -alac_file *decoder_info; +static alac_file *decoder_info; #ifdef FANCY_RESAMPLING -int fancy_resampling = 1; -SRC_STATE *src; +static int fancy_resampling = 1; +static SRC_STATE *src; #endif -int init_rtp(void); -void init_buffer(void); -int init_output(void); -void rtp_request_resend(seq_t first, seq_t last); -void ab_resync(void); +static int init_rtp(void); +static void init_buffer(void); +static int init_output(void); +static void rtp_request_resend(seq_t first, seq_t last); +static void ab_resync(void); // interthread variables // stdin->decoder @@ -114,12 +114,13 @@ int ab_buffering = 1, ab_synced = 0; pthread_mutex_t ab_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t ab_buffer_ready = PTHREAD_COND_INITIALIZER; -void die(char *why) { +static void die(char *why) { fprintf(stderr, "FATAL: %s\n", why); exit(1); } -int hex2bin(unsigned char *buf, char *hex) { +#ifdef HAIRTUNES_STANDALONE +static int hex2bin(unsigned char *buf, char *hex) { int i, j; if (strlen(hex) != 0x20) return 1; @@ -131,8 +132,9 @@ int hex2bin(unsigned char *buf, char *hex) { } return 0; } +#endif -int init_decoder(void) { +static int init_decoder(void) { alac_file *alac; frame_size = fmtp[1]; // stereo samples @@ -317,14 +319,14 @@ int main(int argc, char **argv) { } #endif -void init_buffer(void) { +static void init_buffer(void) { int i; for (i=0; i 0; } -void alac_decode(short *dest, char *buf, int len) { +static void alac_decode(short *dest, char *buf, int len) { unsigned char packet[MAX_PACKET]; assert(len<=MAX_PACKET); @@ -356,8 +358,8 @@ void alac_decode(short *dest, char *buf, int len) { assert(outsize == FRAME_BYTES); } -void buffer_put_packet(seq_t seqno, char *data, int len) { - volatile abuf_t *abuf = 0; +static void buffer_put_packet(seq_t seqno, char *data, int len) { + abuf_t *abuf = 0; short buf_fill; pthread_mutex_lock(&ab_mutex); @@ -394,12 +396,12 @@ void buffer_put_packet(seq_t seqno, char *data, int len) { static int rtp_sockets[2]; // data, control #ifdef AF_INET6 - struct sockaddr_in6 rtp_client; +static struct sockaddr_in6 rtp_client; #else - struct sockaddr_in rtp_client; +static struct sockaddr_in rtp_client; #endif -void *rtp_thread_func(void *arg) { +static void *rtp_thread_func(void *arg) { socklen_t si_len = sizeof(rtp_client); char packet[MAX_PACKET]; char *pktp; @@ -443,7 +445,7 @@ void *rtp_thread_func(void *arg) { return 0; } -void rtp_request_resend(seq_t first, seq_t last) { +static void rtp_request_resend(seq_t first, seq_t last) { if (seq_order(last, first)) return; @@ -465,25 +467,25 @@ void rtp_request_resend(seq_t first, seq_t last) { } -int init_rtp(void) { +static int init_rtp(void) { struct sockaddr_in si; int type = AF_INET; - struct sockaddr* si_p = (struct sockaddr*)&si; - socklen_t si_len = sizeof(si); + struct sockaddr* si_p = (struct sockaddr*)&si; + socklen_t si_len = sizeof(si); unsigned short *sin_port = &si.sin_port; memset(&si, 0, sizeof(si)); #ifdef AF_INET6 struct sockaddr_in6 si6; type = AF_INET6; - si_p = (struct sockaddr*)&si6; - si_len = sizeof(si6); + si_p = (struct sockaddr*)&si6; + si_len = sizeof(si6); sin_port = &si6.sin6_port; memset(&si6, 0, sizeof(si6)); #endif si.sin_family = AF_INET; #ifdef SIN_LEN - si.sin_len = sizeof(si); + si.sin_len = sizeof(si); #endif si.sin_addr.s_addr = htonl(INADDR_ANY); #ifdef AF_INET6 @@ -501,14 +503,14 @@ int init_rtp(void) { if(sock < 0) sock = socket(type, SOCK_DGRAM, IPPROTO_UDP); #ifdef AF_INET6 - if(sock==-1 && type == AF_INET6) { - // try fallback to IPv4 - type = AF_INET; - si_p = (struct sockaddr*)&si; - si_len = sizeof(si); - sin_port = &si.sin_port; - continue; - } + if(sock==-1 && type == AF_INET6) { + // try fallback to IPv4 + type = AF_INET; + si_p = (struct sockaddr*)&si; + si_len = sizeof(si); + sin_port = &si.sin_port; + continue; + } #endif if (sock==-1) die("Can't create data socket!"); @@ -591,7 +593,7 @@ static double biquad_filt(biquad_t *bq, double in) { return w; } -double bf_playback_rate = 1.0; +static double bf_playback_rate = 1.0; static double bf_est_drift = 0.0; // local clock is slower by static biquad_t bf_drift_lpf; @@ -600,7 +602,7 @@ static biquad_t bf_err_lpf, bf_err_deriv_lpf; static double desired_fill; static int fill_count; -void bf_est_reset(short fill) { +static void bf_est_reset(short fill) { biquad_lpf(&bf_drift_lpf, 1.0/180.0, 0.3); biquad_lpf(&bf_err_lpf, 1.0/10.0, 0.25); biquad_lpf(&bf_err_deriv_lpf, 1.0/2.0, 0.2); @@ -609,7 +611,7 @@ void bf_est_reset(short fill) { bf_est_err = bf_last_err = 0; desired_fill = fill_count = 0; } -void bf_est_update(short fill) { +static void bf_est_update(short fill) { if (fill_count < 1000) { desired_fill += (double)fill/1000.0; fill_count++; @@ -633,7 +635,7 @@ void bf_est_update(short fill) { } // get the next frame, when available. return 0 if underrun/stream reset. -short *buffer_get_frame(void) { +static short *buffer_get_frame(void) { short buf_fill; seq_t read; volatile abuf_t *abuf = 0; @@ -687,7 +689,7 @@ short *buffer_get_frame(void) { return curframe->data; } -int stuff_buffer(double playback_rate, short *inptr, short *outptr) { +static int stuff_buffer(double playback_rate, short *inptr, short *outptr) { int i; int stuffsamp = frame_size; int stuff = 0; @@ -726,8 +728,8 @@ int stuff_buffer(double playback_rate, short *inptr, short *outptr) { return frame_size + stuff; } -void *audio_thread_func(void *arg) { - ao_device* dev = arg; +static void *audio_thread_func(void *arg) { + ao_device* dev = arg; int play_samples; signed short buf_fill __attribute__((unused)); @@ -795,18 +797,18 @@ void *audio_thread_func(void *arg) { #define NUM_CHANNELS 2 -void handle_broken_fifo() { +static void handle_broken_fifo() { close(pipe_handle); pipe_handle = -1; } -void init_pipe(char* pipe) { +static void init_pipe(const char* pipe) { // make the FIFO and catch the broken pipe signal mknod(pipe, S_IFIFO | 0644, 0); signal(SIGPIPE, handle_broken_fifo); } -void* init_ao() { +static void* init_ao(void) { ao_initialize(); int driver; @@ -823,12 +825,12 @@ void* init_ao() { ao_sample_format fmt; memset(&fmt, 0, sizeof(fmt)); - + fmt.bits = 16; fmt.rate = sampling_rate; fmt.channels = NUM_CHANNELS; fmt.byte_format = AO_FMT_NATIVE; - + ao_option *ao_opts = NULL; if(libao_deviceid) { ao_append_option(&ao_opts, "id", libao_deviceid); @@ -847,8 +849,8 @@ void* init_ao() { return dev; } -int init_output(void) { - void* arg = 0; +static int init_output(void) { + void* arg = 0; if (pipename) { init_pipe(pipename); From 0a446a421d0f73bb3dbe5ad90d5a68839eb2074d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 15:44:09 -0600 Subject: [PATCH 08/14] Return the correct value from biquad_filt() If you turned set `debug = 1` in hairtunes, you'd quickly get a mess of debug messages that showed bf_est_drift in bf_est_update() going quicky out of range toward a float NaN value (usually negative). Clearly the presence of this `out` variable in biquad_filt was meant to be used, not marked as unused. --- hairtunes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index 1a19140a..a9abfcb7 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -586,11 +586,11 @@ static void biquad_lpf(biquad_t *bq, double freq, double Q) { static double biquad_filt(biquad_t *bq, double in) { double w = in - bq->a[0]*bq->hist[0] - bq->a[1]*bq->hist[1]; - double out __attribute__((unused)) = bq->b[1]*bq->hist[0] + bq->b[2]*bq->hist[1] + bq->b[0]*w; + double out = bq->b[1]*bq->hist[0] + bq->b[2]*bq->hist[1] + bq->b[0]*w; bq->hist[1] = bq->hist[0]; bq->hist[0] = w; - return w; + return out; } static double bf_playback_rate = 1.0; From 8b1728d946828badec6b3d1383d5729eca19d746 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 15:47:07 -0600 Subject: [PATCH 09/14] Use a pthread mutex around the volume settings Using the `volatile` qualifier in multithreading code is never the right answer. Mutexes should be used as was attempted with the audio buffer code. Here, we implement a new mutex for the volume and fix_volume globals, and grab a lock on it when necessary, which is for both reads and writes. --- hairtunes.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index a9abfcb7..ecd99211 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -97,9 +97,10 @@ static void rtp_request_resend(seq_t first, seq_t last); static void ab_resync(void); // interthread variables - // stdin->decoder -volatile double volume = 1.0; -volatile long fix_volume = 0x10000; +// stdin->decoder +static double volume = 1.0; +static int fix_volume = 0x10000; +static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER; typedef struct audio_buffer_entry { // decoded audio packets int ready; @@ -220,8 +221,10 @@ int hairtunes_init(char *pAeskey, char *pAesiv, char *fmtpstr, int pCtrlPort, in assert(f<=0); if (debug) fprintf(stderr, "VOL: %lf\n", f); + pthread_mutex_lock(&vol_mutex); volume = pow(10.0,0.05*f); fix_volume = 65536.0 * volume; + pthread_mutex_unlock(&vol_mutex); continue; } if (!strcmp(line, "exit\n")) { @@ -702,6 +705,7 @@ static int stuff_buffer(double playback_rate, short *inptr, short *outptr) { stuffsamp = rand() % (frame_size - 1); } + pthread_mutex_lock(&vol_mutex); for (i=0; i Date: Fri, 24 Feb 2012 15:50:41 -0600 Subject: [PATCH 10/14] Use the audio buffer mutex appropriately We need to use this any time we write to or access any of the audio-buffer related variables. This also removes the need to use 'volatile', which cripples the compiler optimizations. --- hairtunes.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index ecd99211..ba6687af 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -106,14 +106,14 @@ typedef struct audio_buffer_entry { // decoded audio packets int ready; signed short *data; } abuf_t; -volatile abuf_t audio_buffer[BUFFER_FRAMES]; +static abuf_t audio_buffer[BUFFER_FRAMES]; #define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES) // mutex-protected variables -volatile seq_t ab_read, ab_write; -int ab_buffering = 1, ab_synced = 0; -pthread_mutex_t ab_mutex = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t ab_buffer_ready = PTHREAD_COND_INITIALIZER; +static seq_t ab_read, ab_write; +static int ab_buffering = 1, ab_synced = 0; +static pthread_mutex_t ab_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t ab_buffer_ready = PTHREAD_COND_INITIALIZER; static void die(char *why) { fprintf(stderr, "FATAL: %s\n", why); @@ -391,10 +391,12 @@ static void buffer_put_packet(seq_t seqno, char *data, int len) { abuf->ready = 1; } + pthread_mutex_lock(&ab_mutex); if (ab_buffering && buf_fill >= buffer_start_fill) { ab_buffering = 0; pthread_cond_signal(&ab_buffer_ready); } + pthread_mutex_unlock(&ab_mutex); } static int rtp_sockets[2]; // data, control @@ -641,7 +643,7 @@ static void bf_est_update(short fill) { static short *buffer_get_frame(void) { short buf_fill; seq_t read; - volatile abuf_t *abuf = 0; + abuf_t *abuf = 0; unsigned short next; int i; @@ -656,9 +658,9 @@ static short *buffer_get_frame(void) { pthread_cond_wait(&ab_buffer_ready, &ab_mutex); ab_read++; buf_fill = ab_write - ab_read; + bf_est_reset(buf_fill); pthread_mutex_unlock(&ab_mutex); - bf_est_reset(buf_fill); return 0; } if (buf_fill >= BUFFER_FRAMES) { // overrunning! uh-oh. restart at a sane distance @@ -667,8 +669,6 @@ static short *buffer_get_frame(void) { } read = ab_read; ab_read++; - pthread_mutex_unlock(&ab_mutex); - buf_fill = ab_write - ab_read; bf_est_update(buf_fill); @@ -683,12 +683,14 @@ static short *buffer_get_frame(void) { } } - volatile abuf_t *curframe = audio_buffer + BUFIDX(read); + abuf_t *curframe = audio_buffer + BUFIDX(read); if (!curframe->ready) { fprintf(stderr, "\nmissing frame.\n"); memset(curframe->data, 0, FRAME_BYTES); } curframe->ready = 0; + pthread_mutex_unlock(&ab_mutex); + return curframe->data; } From 0b4c7ad4befa8195568ee74c1e0f6695689e9585 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 15:51:49 -0600 Subject: [PATCH 11/14] hairplay: various small code cleanups --- hairtunes.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hairtunes.c b/hairtunes.c index ba6687af..181dd031 100644 --- a/hairtunes.c +++ b/hairtunes.c @@ -551,11 +551,11 @@ static int init_rtp(void) { static inline short dithered_vol(short sample) { static short rand_a, rand_b; long out; - rand_b = rand_a; - rand_a = rand() & 0xffff; out = (long)sample * fix_volume; if (fix_volume < 0x10000) { + rand_b = rand_a; + rand_a = rand() & 0xffff; out += rand_a; out -= rand_b; } @@ -616,6 +616,7 @@ static void bf_est_reset(short fill) { bf_est_err = bf_last_err = 0; desired_fill = fill_count = 0; } + static void bf_est_update(short fill) { if (fill_count < 1000) { desired_fill += (double)fill/1000.0; @@ -629,12 +630,14 @@ static void bf_est_update(short fill) { double buf_delta = fill - desired_fill; bf_est_err = biquad_filt(&bf_err_lpf, buf_delta); double err_deriv = biquad_filt(&bf_err_deriv_lpf, bf_est_err - bf_last_err); + double adj_error = CONTROL_A * bf_est_err; - bf_est_drift = biquad_filt(&bf_drift_lpf, CONTROL_B*(bf_est_err*CONTROL_A + err_deriv) + bf_est_drift); + bf_est_drift = biquad_filt(&bf_drift_lpf, CONTROL_B*(adj_error + err_deriv) + bf_est_drift); if (debug) - fprintf(stderr, "bf %d err %f drift %f desiring %f ed %f estd %f\r", fill, bf_est_err, bf_est_drift, desired_fill, err_deriv, err_deriv + CONTROL_A*bf_est_err); - bf_playback_rate = 1.0 + CONTROL_A*bf_est_err + bf_est_drift; + fprintf(stderr, "bf %d err %f drift %f desiring %f ed %f estd %f\n", + fill, bf_est_err, bf_est_drift, desired_fill, err_deriv, err_deriv + adj_error); + bf_playback_rate = 1.0 + adj_error + bf_est_drift; bf_last_err = bf_est_err; } @@ -672,7 +675,8 @@ static short *buffer_get_frame(void) { buf_fill = ab_write - ab_read; bf_est_update(buf_fill); - // check if t+16, t+32, t+64, t+128, ... (START_FILL / 2) packets have arrived... last-chance resend + // check if t+16, t+32, t+64, t+128, ... (START_FILL / 2) + // packets have arrived... last-chance resend if (!ab_buffering) { for (i = 16; i < (START_FILL / 2); i = (i * 2)) { next = ab_read + i; From 435a866816ff5ca906300f0546c0a7d85f33d4e2 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 16:02:47 -0600 Subject: [PATCH 12/14] Add static to some functions in alac.c --- alac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/alac.c b/alac.c index 3ad57580..466b560d 100644 --- a/alac.c +++ b/alac.c @@ -289,7 +289,7 @@ found: #define RICE_THRESHOLD 8 // maximum number of bits for a rice prefix. -int32_t entropy_decode_value(alac_file* alac, +static int32_t entropy_decode_value(alac_file* alac, int readSampleSize, int k, int rice_kmodifier_mask) @@ -333,7 +333,7 @@ int32_t entropy_decode_value(alac_file* alac, return x; } -void entropy_rice_decode(alac_file* alac, +static void entropy_rice_decode(alac_file* alac, int32_t* outputBuffer, int outputSize, int readSampleSize, @@ -550,7 +550,7 @@ static void predictor_decompress_fir_adapt(int32_t *error_buffer, } } -void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, +static void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, int16_t *buffer_out, int numchannels, int numsamples, uint8_t interlacing_shift, @@ -609,7 +609,7 @@ void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, } } -void deinterlace_24(int32_t *buffer_a, int32_t *buffer_b, +static void deinterlace_24(int32_t *buffer_a, int32_t *buffer_b, int uncompressed_bytes, int32_t *uncompressed_bytes_buffer_a, int32_t *uncompressed_bytes_buffer_b, void *buffer_out, From 59d26d3a7ce00dcd9c6d5ef26953d161a622eab4 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 16:14:38 -0600 Subject: [PATCH 13/14] Use static where appropriate in shairport.c Most functions don't need to be public outside of this file, so move all the forward declarations out of shairport.h. --- shairport.c | 90 +++++++++++++++++++++++++++++++++-------------------- shairport.h | 27 ---------------- 2 files changed, 57 insertions(+), 60 deletions(-) diff --git a/shairport.c b/shairport.c index 924d9401..63027599 100644 --- a/shairport.c +++ b/shairport.c @@ -52,7 +52,37 @@ int bufferStartFill = -1; #define HEADER_LOG_LEVEL LOG_DEBUG #define AVAHI_LOG_LEVEL LOG_DEBUG -void handle_sigchld(int signo) { +static void handleClient(int pSock, char *pPassword, char *pHWADDR); +static void writeDataToClient(int pSock, struct shairbuffer *pResponse); +static int readDataFromClient(int pSock, struct shairbuffer *pClientBuffer); + +static int parseMessage(struct connection *pConn,unsigned char *pIpBin, unsigned int pIpBinLen, char *pHWADDR); +static void propogateCSeq(struct connection *pConn); + +static void cleanupBuffers(struct connection *pConnection); +static void cleanup(struct connection *pConnection); + +static int startAvahi(const char *pHwAddr, const char *pServerName, int pPort); + +static int getAvailChars(struct shairbuffer *pBuf); +static void addToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf); +static void addNToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf, int pNofNewBuf); + +static char *getTrimmedMalloc(char *pChar, int pSize, int pEndStr, int pAddNL); +static char *getTrimmed(char *pChar, int pSize, int pEndStr, int pAddNL, char *pTrimDest); + +static void slog(int pLevel, char *pFormat, ...); +static int isLogEnabledFor(int pLevel); + +static void initConnection(struct connection *pConn, struct keyring *pKeys, struct comms *pComms, int pSocket, char *pPassword); +static void closePipe(int *pPipe); +static void initBuffer(struct shairbuffer *pBuf, int pNumChars); + +static void setKeys(struct keyring *pKeys, char *pIV, char* pAESKey, char *pFmtp); +static RSA *loadKey(void); + + +static void handle_sigchld(int signo) { int status; waitpid(-1, &status, WNOHANG); } @@ -275,7 +305,7 @@ int main(int argc, char **argv) return 0; } -int findEnd(char *tReadBuf) +static int findEnd(char *tReadBuf) { // find \n\n, \r\n\r\n, or \r\r is found int tIdx = 0; @@ -313,7 +343,7 @@ int findEnd(char *tReadBuf) return -1; } -void handleClient(int pSock, char *pPassword, char *pHWADDR) +static void handleClient(int pSock, char *pPassword, char *pHWADDR) { slog(LOG_DEBUG_VV, "In Handle Client\n"); fflush(stdout); @@ -421,15 +451,14 @@ void handleClient(int pSock, char *pPassword, char *pHWADDR) fflush(stdout); } - -void writeDataToClient(int pSock, struct shairbuffer *pResponse) +static void writeDataToClient(int pSock, struct shairbuffer *pResponse) { slog(LOG_DEBUG_VV, "\n----Beg Send Response Header----\n%.*s\n", pResponse->current, pResponse->data); send(pSock, pResponse->data, pResponse->current,0); slog(LOG_DEBUG_VV, "----Send Response Header----\n"); } -int readDataFromClient(int pSock, struct shairbuffer *pClientBuffer) +static int readDataFromClient(int pSock, struct shairbuffer *pClientBuffer) { char tReadBuf[MAX_SIZE]; tReadBuf[0] = '\0'; @@ -481,7 +510,7 @@ int readDataFromClient(int pSock, struct shairbuffer *pClientBuffer) return 0; } -char *getFromBuffer(char *pBufferPtr, const char *pField, int pLenAfterField, int *pReturnSize, char *pDelims) +static char *getFromBuffer(char *pBufferPtr, const char *pField, int pLenAfterField, int *pReturnSize, char *pDelims) { slog(LOG_DEBUG_V, "GettingFromBuffer: %s\n", pField); char* tFound = strstr(pBufferPtr, pField); @@ -517,25 +546,25 @@ char *getFromBuffer(char *pBufferPtr, const char *pField, int pLenAfterField, in return tFound; } - -char *getFromHeader(char *pHeaderPtr, const char *pField, int *pReturnSize) +static char *getFromHeader(char *pHeaderPtr, const char *pField, int *pReturnSize) { return getFromBuffer(pHeaderPtr, pField, 2, pReturnSize, "\r\n"); } -char *getFromContent(char *pContentPtr, const char* pField, int *pReturnSize) +static char *getFromContent(char *pContentPtr, const char* pField, int *pReturnSize) { return getFromBuffer(pContentPtr, pField, 1, pReturnSize, "\r\n"); } -char *getFromSetup(char *pContentPtr, const char* pField, int *pReturnSize) +static char *getFromSetup(char *pContentPtr, const char* pField, int *pReturnSize) { return getFromBuffer(pContentPtr, pField, 1, pReturnSize, ";\r\n"); } // Handles compiling the Apple-Challenge, HWID, and Server IP Address // Into the response the airplay client is expecting. -int buildAppleResponse(struct connection *pConn, unsigned char *pIpBin, unsigned int pIpBinLen, char *pHWID) +static int buildAppleResponse(struct connection *pConn, unsigned char *pIpBin, + unsigned int pIpBinLen, char *pHWID) { // Find Apple-Challenge char *tResponse = NULL; @@ -604,7 +633,7 @@ int buildAppleResponse(struct connection *pConn, unsigned char *pIpBin, unsigned } //parseMessage(tConn->recv.data, tConn->recv.mark, &tConn->resp, ipstr, pHWADDR, tConn->keys); -int parseMessage(struct connection *pConn, unsigned char *pIpBin, unsigned int pIpBinLen, char *pHWID) +static int parseMessage(struct connection *pConn, unsigned char *pIpBin, unsigned int pIpBinLen, char *pHWID) { int tReturn = 0; // 0 = good, 1 = Needs More Data, -1 = close client socket. if(pConn->resp.data == NULL) @@ -860,7 +889,7 @@ int parseMessage(struct connection *pConn, unsigned char *pIpBin, unsigned int p } // Copies CSeq value from request, and adds standard header values in. -void propogateCSeq(struct connection *pConn) //char *pRecvBuffer, struct shairbuffer *pConn->recp.data) +static void propogateCSeq(struct connection *pConn) //char *pRecvBuffer, struct shairbuffer *pConn->recp.data) { int tSize=0; char *tRecPtr = getFromHeader(pConn->recv.data, "CSeq", &tSize); @@ -884,7 +913,7 @@ void cleanupBuffers(struct connection *pConn) } } -void cleanup(struct connection *pConn) +static void cleanup(struct connection *pConn) { cleanupBuffers(pConn); if(pConn->hairtunes != NULL) @@ -918,7 +947,7 @@ void cleanup(struct connection *pConn) } } -int startAvahi(const char *pHWStr, const char *pServerName, int pPort) +static int startAvahi(const char *pHWStr, const char *pServerName, int pPort) { int tMaxServerName = 25; // Something reasonable? iPad showed 21, iphone 25 int tPid = fork(); @@ -960,22 +989,17 @@ int startAvahi(const char *pHWStr, const char *pServerName, int pPort) return tPid; } -void printBufferInfo(struct shairbuffer *pBuf, int pLevel) -{ - slog(pLevel, "Buffer: [%s] size: %d maxchars:%d\n", pBuf->data, pBuf->current, pBuf->maxsize/sizeof(char)); -} - -int getAvailChars(struct shairbuffer *pBuf) +static int getAvailChars(struct shairbuffer *pBuf) { return (pBuf->maxsize / sizeof(char)) - pBuf->current; } -void addToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf) +static void addToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf) { addNToShairBuffer(pBuf, pNewBuf, strlen(pNewBuf)); } -void addNToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf, int pNofNewBuf) +static void addNToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf, int pNofNewBuf) { int tAvailChars = getAvailChars(pBuf); if(pNofNewBuf > tAvailChars) @@ -999,7 +1023,7 @@ void addNToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf, int pNofNewBuf) } } -char *getTrimmedMalloc(char *pChar, int pSize, int pEndStr, int pAddNL) +static char *getTrimmedMalloc(char *pChar, int pSize, int pEndStr, int pAddNL) { int tAdditionalSize = 0; if(pEndStr) @@ -1011,7 +1035,7 @@ char *getTrimmedMalloc(char *pChar, int pSize, int pEndStr, int pAddNL) } // Must free returned ptr -char *getTrimmed(char *pChar, int pSize, int pEndStr, int pAddNL, char *pTrimDest) +static char *getTrimmed(char *pChar, int pSize, int pEndStr, int pAddNL, char *pTrimDest) { int tSize = pSize; if(pEndStr) @@ -1036,7 +1060,7 @@ char *getTrimmed(char *pChar, int pSize, int pEndStr, int pAddNL, char *pTrimDes return pTrimDest; } -void slog(int pLevel, char *pFormat, ...) +static void slog(int pLevel, char *pFormat, ...) { #ifdef SHAIRPORT_LOG if(isLogEnabledFor(pLevel)) @@ -1049,7 +1073,7 @@ void slog(int pLevel, char *pFormat, ...) #endif } -int isLogEnabledFor(int pLevel) +static int isLogEnabledFor(int pLevel) { if(pLevel <= kCurrentLogLevel) { @@ -1058,7 +1082,7 @@ int isLogEnabledFor(int pLevel) return FALSE; } -void initConnection(struct connection *pConn, struct keyring *pKeys, +static void initConnection(struct connection *pConn, struct keyring *pKeys, struct comms *pComms, int pSocket, char *pPassword) { pConn->hairtunes = pComms; @@ -1082,7 +1106,7 @@ void initConnection(struct connection *pConn, struct keyring *pKeys, } } -void closePipe(int *pPipe) +static void closePipe(int *pPipe) { if(*pPipe != -1) { @@ -1091,7 +1115,7 @@ void closePipe(int *pPipe) } } -void initBuffer(struct shairbuffer *pBuf, int pNumChars) +static void initBuffer(struct shairbuffer *pBuf, int pNumChars) { if(pBuf->data != NULL) { @@ -1106,7 +1130,7 @@ void initBuffer(struct shairbuffer *pBuf, int pNumChars) memset(pBuf->data, 0, pBuf->maxsize); } -void setKeys(struct keyring *pKeys, char *pIV, char* pAESKey, char *pFmtp) +static void setKeys(struct keyring *pKeys, char *pIV, char* pAESKey, char *pFmtp) { if(pKeys->aesiv != NULL) { @@ -1150,7 +1174,7 @@ void setKeys(struct keyring *pKeys, char *pIV, char* pAESKey, char *pFmtp) "2gG0N5hvJpzwwhbhXqFKA4zaaSrw622wDniAK5MlIE0tIAKKP4yxNGjoD2QYjhBGuhvkWKY=\n" \ "-----END RSA PRIVATE KEY-----" -RSA *loadKey() +static RSA *loadKey(void) { BIO *tBio = BIO_new_mem_buf(AIRPORT_PRIVATE_KEY, -1); RSA *rsa = PEM_read_bio_RSAPrivateKey(tBio, NULL, NULL, NULL); //NULL, NULL, NULL); diff --git a/shairport.h b/shairport.h index 21a0b932..901a1722 100644 --- a/shairport.h +++ b/shairport.h @@ -52,33 +52,6 @@ struct connection char *password; }; -RSA *loadKey(); -int startAvahi(const char *pHwAddr, const char *pServerName, int pPort); -void cleanupBuffers(struct connection *pConnection); -void cleanup(struct connection *pConnection); -void handleClient(int pSock, char *pPassword, char *pHWADDR); -int getAvailChars(struct shairbuffer *pBuf); - -char *getTrimmedMalloc(char *pChar, int pSize, int pEndStr, int pAddNL); -char *getTrimmed(char *pChar, int pSize, int pEndStr, int pAddNL, char *pTrimDest); -void initBuffer(struct shairbuffer *pBuf, int pNumChars); -void printBufferInfo(struct shairbuffer *pBuf, int pLevel); -void addToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf); -void addNToShairBuffer(struct shairbuffer *pBuf, char *pNewBuf, int pNofNewBuf); - -int readDataFromClient(int pSock, struct shairbuffer *pClientBuffer); -int parseMessage(struct connection *pConn,unsigned char *pIpBin, unsigned int pIpBinLen, char *pHWADDR); - -void closePipe(int *pPipe); -void setKeys(struct keyring *pKeys, char *pIV, char* pAESKey, char *pFmtp); -void initConnection(struct connection *pConn, struct keyring *pKeys, - struct comms *pComms, int pSocket, char *pPassword); - -void writeDataToClient(int pSock, struct shairbuffer *pResponse); -void propogateCSeq(struct connection *pConn); -int buildAppleResponse(struct connection *pConn, unsigned char *pIpBin, unsigned int pIpBinLen, char *pHwAddr); void sim(int pLevel, char *pValue1, char *pValue2); -void slog(int pLevel, char *pFormat, ...); -int isLogEnabledFor(int pLevel); #endif From b5a91cbebda41da9d41ac5ab225493a59f1e91ed Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Feb 2012 16:15:21 -0600 Subject: [PATCH 14/14] Tabs to spaces conversion --- shairport.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/shairport.c b/shairport.c index 63027599..f71916dd 100644 --- a/shairport.c +++ b/shairport.c @@ -376,13 +376,13 @@ static void handleClient(int pSock, char *pPassword, char *pHWADDR) port = ntohs(s->sin6_port); inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr); - union { - struct sockaddr_in6 s; - unsigned char bin[sizeof(struct sockaddr_in6)]; - } addr; - memcpy(&addr.s, &s->sin6_addr, sizeof(struct sockaddr_in6)); - - if(memcmp(&addr.bin[0], "\x00\x00\x00\x00" "\x00\x00\x00\x00" "\x00\x00\xff\xff", 12) == 0) + union { + struct sockaddr_in6 s; + unsigned char bin[sizeof(struct sockaddr_in6)]; + } addr; + memcpy(&addr.s, &s->sin6_addr, sizeof(struct sockaddr_in6)); + + if(memcmp(&addr.bin[0], "\x00\x00\x00\x00" "\x00\x00\x00\x00" "\x00\x00\xff\xff", 12) == 0) { // its ipv4... memcpy(ipbin, &addr.bin[12], 4);