From 696da609efc5b55cc65c18174a4fd6ce270ae373 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Mon, 31 Aug 2015 10:36:55 +0100 Subject: [PATCH 01/14] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9b33c0aa..848f5b5e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Audio played by a Shairport Sync-powered device stays synchronised with the sour Shairport Sync does not support AirPlay video or photo streaming. -This branch -- "master" -- is the stable branch of Shairport Sync. To access the development version, please switch to the "development" branch. +This branch -- "development" -- is likely to be unstable and may change frequently. To access the stable version, please switch to the "master" branch. More Information ---------- @@ -204,7 +204,7 @@ Please note that the full path to the programs must be specified, and script fil *Command Line Arguments* -You can use command line arguments to provide settings to Shairport Sync as before. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/update-documentation/man/shairport-sync.html. +You can use command line arguments to provide settings to Shairport Sync as before. For full information, please read the Shairport Sync `man` page, also available at http://htmlpreview.github.io/?https://github.com/mikebrady/shairport-sync/blob/development/man/shairport-sync.html. Apart from the following options, all command line options can be replaced by settings in the configuration file. Here is a brief description of command line options that are not replicated by settings in the settings file. From d6a7d93df02c4364bcd160c9d29571b26e890d0e Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Mon, 31 Aug 2015 10:44:26 +0100 Subject: [PATCH 02/14] Start 2.5.X development sequence --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4c3d3afd..ec4c83fc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.4], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.5.0], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) From abe4d83ef0c794efa419fccdc0fd515d0dc9b187 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Mon, 31 Aug 2015 11:18:25 +0000 Subject: [PATCH 03/14] Add flush request to handle_record, see if it helps --- rtsp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/rtsp.c b/rtsp.c index 9340dbfb..6adea0a6 100644 --- a/rtsp.c +++ b/rtsp.c @@ -582,8 +582,27 @@ static void msg_write_response(int fd, rtsp_message *resp) { } static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { + debug(1,"Handle Record"); resp->respcode = 200; msg_add_header(resp, "Audio-Latency", "88200"); + + char *p; + uint32_t rtptime = 0; + char *hdr = msg_get_header(req, "RTP-Info"); + + if (hdr) { + // debug(1,"FLUSH message received: \"%s\".",hdr); + // get the rtp timestamp + p = strstr(hdr, "rtptime="); + if (p) { + p = strchr(p, '=') + 1; + if (p) + rtptime = uatoi(p); // unsigned integer -- up to 2^32-1 + } + } + rtptime--; + debug(1,"RTSP Flush Requested by handle_record: %u.",rtptime); + player_flush(rtptime); } static void handle_options(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { @@ -624,6 +643,7 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message * } static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { + debug(1,"Handle Setup"); int cport, tport; int lsport, lcport, ltport; uint32_t active_remote = 0; From 7d2045881f6fb2b94e000a4b7efc0cad32d12c62 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Tue, 1 Sep 2015 09:13:20 +0100 Subject: [PATCH 04/14] Update RELEASENOTES.md --- RELEASENOTES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index de425aba..5b7fd5b4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,11 @@ +Version 2.5.0 +---- +**Changes** +Add flush request to handle_record, see if it helps in a rare situation. + +Versions 2.5.x is new development sequence. +---- + Version 2.4 ---- **Stable release** From d10e097f4c89758c7e8148e41dc62a1d38fa5926 Mon Sep 17 00:00:00 2001 From: Mke Brady Date: Tue, 1 Sep 2015 10:02:09 +0100 Subject: [PATCH 05/14] Turn on a lot of debugging --- configure.ac | 2 +- player.c | 40 ++++++++++++++++++---------------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index ec4c83fc..58fd70cb 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.5.0], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.5.0.1], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/player.c b/player.c index 425bc879..68a84adc 100644 --- a/player.c +++ b/player.c @@ -548,10 +548,8 @@ static abuf_t *buffer_get_frame(void) { if (local_time_now >= first_packet_time_to_play) { // we've gone past the time... - // debug(1,"Run past the exact start time by %llu frames, with time now of %llx, fpttp - // of %llx and dac_delay of %d and %d packets; - // flush.",(((tn-first_packet_time_to_play)*44100)>>32)+dac_delay,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, - // ab_write)); + //debug(1,"Run past the exact start time by %llu frames, with time now of %llx, fpttp of %llx and dac_delay of %d and %d packets; flush.", + //(((tn-first_packet_time_to_play)*44100)>>32)+dac_delay,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read,ab_write)); if (config.output->flush) config.output->flush(); @@ -573,10 +571,10 @@ static abuf_t *buffer_get_frame(void) { int64_t exact_frame_gap = gross_frame_gap - dac_delay; if (exact_frame_gap <= 0) { // we've gone past the time... - // debug(1,"Run a bit past the exact start time by %lld frames, with time now of - // %llx, fpttp of %llx and dac_delay of %d and %d packets; - // flush.",-exact_frame_gap,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, - // ab_write)); + //debug(1,"Run a bit past the exact start time by %lld frames, with time now of + //%llx, fpttp of %llx and dac_delay of %d and %d packets; + //flush.",-exact_frame_gap,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, + //ab_write)); if (config.output->flush) config.output->flush(); ab_resync(); @@ -597,8 +595,7 @@ static abuf_t *buffer_get_frame(void) { signed short *silence; silence = malloc(FRAME_BYTES(fs)); memset(silence, 0, FRAME_BYTES(fs)); - // debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, - // with %d packets.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, ab_write)); + debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, with %d packets.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, ab_write)); config.output->play(silence, fs); free(silence); if (ab_buffering == 0) { @@ -643,11 +640,11 @@ static abuf_t *buffer_get_frame(void) { if (net_offset >= 0) { net_offset_fp_sec = (net_offset << 32) / 44100; time_to_play += net_offset_fp_sec; // using the latency requested... - // debug(2,"Net Offset: %lld, adjusted: %lld.",net_offset,net_offset_fp_sec); + debug(2,"Net Offset: %lld, adjusted: %lld.",net_offset,net_offset_fp_sec); } else { net_offset_fp_sec = ((-net_offset) << 32) / 44100; time_to_play -= net_offset_fp_sec; - // debug(2,"Net Offset: %lld, adjusted: -%lld.",net_offset,net_offset_fp_sec); + debug(2,"Net Offset: %lld, adjusted: -%lld.",net_offset,net_offset_fp_sec); } if (local_time_now >= time_to_play) { @@ -672,10 +669,10 @@ static abuf_t *buffer_get_frame(void) { time_of_wakeup.tv_sec = sec; time_of_wakeup.tv_nsec = nsec; - pthread_cond_timedwait(&flowcontrol, &ab_mutex, &time_of_wakeup); -// int rc = pthread_cond_timedwait(&flowcontrol,&ab_mutex,&time_of_wakeup); -// if (rc!=0) -// debug(1,"pthread_cond_timedwait returned error code %d.",rc); +// pthread_cond_timedwait(&flowcontrol, &ab_mutex, &time_of_wakeup); + int rc = pthread_cond_timedwait(&flowcontrol,&ab_mutex,&time_of_wakeup); + if (rc!=0) + debug(1,"pthread_cond_timedwait returned error code %d.",rc); #endif #ifdef COMPILE_FOR_OSX uint64_t sec = time_to_wait_for_wakeup_fp >> 32; @@ -712,7 +709,7 @@ static abuf_t *buffer_get_frame(void) { } if (!curframe->ready) { - // debug(1, " %d. Supplying a silent frame.", read); + debug(1, " %d. Supplying a silent frame.", read); missing_packets++; memset(curframe->data, 0, FRAME_BYTES(frame_size)); curframe->timestamp = 0; @@ -913,7 +910,7 @@ static void *player_thread_func(void *arg) { play_number++; // if it's a supplied silent frame, let us know... if (inframe->timestamp == 0) { - // debug(1,"Player has a supplied silent frame."); + debug(1,"Player has a supplied silent frame."); last_seqno_read = (SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder config.output->play(inbuf, frame_size); @@ -1072,9 +1069,8 @@ static void *player_thread_func(void *arg) { if ((inframe->timestamp != 0) && (!please_stop) && (config.resyncthreshold != 0) && (abs(sync_error) > config.resyncthreshold)) { sync_error_out_of_bounds++; - // debug(1,"Sync error out of bounds: Error: %lld; previous error: %lld; DAC: %lld; - // timestamp: %llx, time now - // %llx",sync_error,previous_sync_error,current_delay,inframe->timestamp,local_time_now); + debug(1,"Sync error out of bounds: Error: %lld; previous error: %lld; DAC: %lld; timestamp: %llx, time now %llx", + sync_error,previous_sync_error,current_delay,inframe->timestamp,local_time_now); if (sync_error_out_of_bounds > 3) { debug(1, "Lost sync with source for %d consecutive packets -- flushing and " "resyncing. Error: %lld.", @@ -1099,7 +1095,7 @@ static void *player_thread_func(void *arg) { inframe->timestamp = 0; inframe->sequence_number = 0; - // debug(1,"Sync error %lld frames. Amount to stuff %d." ,sync_error,amount_to_stuff); + debug(1,"Sync error %lld frames. Amount to stuff %d." ,sync_error,amount_to_stuff); // new stats calculation. We want a running average of sync error, drift, adjustment, // number of additions+subtractions From 83b7049ef36929ed7eae8bc6e253419d78ac92a8 Mon Sep 17 00:00:00 2001 From: Mke Brady Date: Tue, 1 Sep 2015 10:28:55 +0100 Subject: [PATCH 06/14] Quieten unnecessary debugging --- configure.ac | 2 +- player.c | 40 ++++++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/configure.ac b/configure.ac index 58fd70cb..624fb5ac 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.5.0.1], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.5.0.2], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/player.c b/player.c index 68a84adc..425bc879 100644 --- a/player.c +++ b/player.c @@ -548,8 +548,10 @@ static abuf_t *buffer_get_frame(void) { if (local_time_now >= first_packet_time_to_play) { // we've gone past the time... - //debug(1,"Run past the exact start time by %llu frames, with time now of %llx, fpttp of %llx and dac_delay of %d and %d packets; flush.", - //(((tn-first_packet_time_to_play)*44100)>>32)+dac_delay,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read,ab_write)); + // debug(1,"Run past the exact start time by %llu frames, with time now of %llx, fpttp + // of %llx and dac_delay of %d and %d packets; + // flush.",(((tn-first_packet_time_to_play)*44100)>>32)+dac_delay,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, + // ab_write)); if (config.output->flush) config.output->flush(); @@ -571,10 +573,10 @@ static abuf_t *buffer_get_frame(void) { int64_t exact_frame_gap = gross_frame_gap - dac_delay; if (exact_frame_gap <= 0) { // we've gone past the time... - //debug(1,"Run a bit past the exact start time by %lld frames, with time now of - //%llx, fpttp of %llx and dac_delay of %d and %d packets; - //flush.",-exact_frame_gap,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, - //ab_write)); + // debug(1,"Run a bit past the exact start time by %lld frames, with time now of + // %llx, fpttp of %llx and dac_delay of %d and %d packets; + // flush.",-exact_frame_gap,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, + // ab_write)); if (config.output->flush) config.output->flush(); ab_resync(); @@ -595,7 +597,8 @@ static abuf_t *buffer_get_frame(void) { signed short *silence; silence = malloc(FRAME_BYTES(fs)); memset(silence, 0, FRAME_BYTES(fs)); - debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, with %d packets.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, ab_write)); + // debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, + // with %d packets.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, ab_write)); config.output->play(silence, fs); free(silence); if (ab_buffering == 0) { @@ -640,11 +643,11 @@ static abuf_t *buffer_get_frame(void) { if (net_offset >= 0) { net_offset_fp_sec = (net_offset << 32) / 44100; time_to_play += net_offset_fp_sec; // using the latency requested... - debug(2,"Net Offset: %lld, adjusted: %lld.",net_offset,net_offset_fp_sec); + // debug(2,"Net Offset: %lld, adjusted: %lld.",net_offset,net_offset_fp_sec); } else { net_offset_fp_sec = ((-net_offset) << 32) / 44100; time_to_play -= net_offset_fp_sec; - debug(2,"Net Offset: %lld, adjusted: -%lld.",net_offset,net_offset_fp_sec); + // debug(2,"Net Offset: %lld, adjusted: -%lld.",net_offset,net_offset_fp_sec); } if (local_time_now >= time_to_play) { @@ -669,10 +672,10 @@ static abuf_t *buffer_get_frame(void) { time_of_wakeup.tv_sec = sec; time_of_wakeup.tv_nsec = nsec; -// pthread_cond_timedwait(&flowcontrol, &ab_mutex, &time_of_wakeup); - int rc = pthread_cond_timedwait(&flowcontrol,&ab_mutex,&time_of_wakeup); - if (rc!=0) - debug(1,"pthread_cond_timedwait returned error code %d.",rc); + pthread_cond_timedwait(&flowcontrol, &ab_mutex, &time_of_wakeup); +// int rc = pthread_cond_timedwait(&flowcontrol,&ab_mutex,&time_of_wakeup); +// if (rc!=0) +// debug(1,"pthread_cond_timedwait returned error code %d.",rc); #endif #ifdef COMPILE_FOR_OSX uint64_t sec = time_to_wait_for_wakeup_fp >> 32; @@ -709,7 +712,7 @@ static abuf_t *buffer_get_frame(void) { } if (!curframe->ready) { - debug(1, " %d. Supplying a silent frame.", read); + // debug(1, " %d. Supplying a silent frame.", read); missing_packets++; memset(curframe->data, 0, FRAME_BYTES(frame_size)); curframe->timestamp = 0; @@ -910,7 +913,7 @@ static void *player_thread_func(void *arg) { play_number++; // if it's a supplied silent frame, let us know... if (inframe->timestamp == 0) { - debug(1,"Player has a supplied silent frame."); + // debug(1,"Player has a supplied silent frame."); last_seqno_read = (SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder config.output->play(inbuf, frame_size); @@ -1069,8 +1072,9 @@ static void *player_thread_func(void *arg) { if ((inframe->timestamp != 0) && (!please_stop) && (config.resyncthreshold != 0) && (abs(sync_error) > config.resyncthreshold)) { sync_error_out_of_bounds++; - debug(1,"Sync error out of bounds: Error: %lld; previous error: %lld; DAC: %lld; timestamp: %llx, time now %llx", - sync_error,previous_sync_error,current_delay,inframe->timestamp,local_time_now); + // debug(1,"Sync error out of bounds: Error: %lld; previous error: %lld; DAC: %lld; + // timestamp: %llx, time now + // %llx",sync_error,previous_sync_error,current_delay,inframe->timestamp,local_time_now); if (sync_error_out_of_bounds > 3) { debug(1, "Lost sync with source for %d consecutive packets -- flushing and " "resyncing. Error: %lld.", @@ -1095,7 +1099,7 @@ static void *player_thread_func(void *arg) { inframe->timestamp = 0; inframe->sequence_number = 0; - debug(1,"Sync error %lld frames. Amount to stuff %d." ,sync_error,amount_to_stuff); + // debug(1,"Sync error %lld frames. Amount to stuff %d." ,sync_error,amount_to_stuff); // new stats calculation. We want a running average of sync error, drift, adjustment, // number of additions+subtractions From b36dc7107fc48d54b0b9dc6351422d30294c0631 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Tue, 1 Sep 2015 10:30:54 +0100 Subject: [PATCH 07/14] Update RELEASENOTES.md --- RELEASENOTES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5b7fd5b4..c604b988 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,13 @@ +Version 2.5.0.2 +---- +**Changes** +Turn off unnecessary debug messages -- usable. + +Version 2.5.0.1 +---- +**Changes** +Turn on lots of debugging -- unusable. + Version 2.5.0 ---- **Changes** From d586252d8ffa511d077dbbf2c6d704763639f702 Mon Sep 17 00:00:00 2001 From: thsm Date: Fri, 11 Sep 2015 19:44:24 +0200 Subject: [PATCH 08/14] Fixed the usage of the USE_CUSTOM_LOCAL_STATE_DIR macro, which prevented to set the daemon_pid_file_proc. --- shairport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shairport.c b/shairport.c index 8acd523b..6a7e5ebd 100644 --- a/shairport.c +++ b/shairport.c @@ -680,8 +680,8 @@ int main(int argc, char **argv) { return 1; } -#if USE_CUSTOM_LOCAL_STATE_DIR - debug(1, "Locating localstatedir at \"%s\"", LOCALSTATEDIR); +#if USE_CUSTOM_PID_DIR + debug(1, "Locating custom pid dir at \"%s\"", PIDDIR); /* Point to a function to help locate where the PID file will go */ daemon_pid_file_proc = pid_file_proc; #endif From cb345056f90c036816cfe0c176512de9dc8de4f6 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sat, 12 Sep 2015 14:02:18 +0100 Subject: [PATCH 09/14] Update RELEASENOTES.md --- RELEASENOTES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c604b988..cb653812 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,3 +1,9 @@ +HEAD +---- + +**Bug fixes** +* Fix in the `shairport.c`: the USE_CUSTOM_LOCAL_STATE_DIR macro was still being used when it should have been USE_CUSTOM_PID_DIR. + Version 2.5.0.2 ---- **Changes** From 79da74800501592fc2c0a3dd5db862844b8475b9 Mon Sep 17 00:00:00 2001 From: Petri Lehtinen Date: Wed, 16 Sep 2015 07:32:32 +0300 Subject: [PATCH 10/14] README.md: s/raspian/raspbian/ --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 848f5b5e..c3e40785 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,9 @@ What else? Status ------ -Shairport Sync works on a wide variety of Linux devices. It works on standard Ubuntu laptops, on the Raspberry Pi with Raspian, Arch Linux and OpenWrt, and it runs on a Linksys NSLU2 and a TP-Link 710N using OpenWrt. It works with built-in audio and with a variety of USB-connected audio amplifiers and DACs, including a cheapo USB "3D Sound" dongle, a first generation iMic and a Topping TP30 amplifier with a USB DAC input. It will not work properly – if at all – with a PulseAudio (pseudo-)output device. +Shairport Sync works on a wide variety of Linux devices. It works on standard Ubuntu laptops, on the Raspberry Pi with Raspbian, Arch Linux and OpenWrt, and it runs on a Linksys NSLU2 and a TP-Link 710N using OpenWrt. It works with built-in audio and with a variety of USB-connected audio amplifiers and DACs, including a cheapo USB "3D Sound" dongle, a first generation iMic and a Topping TP30 amplifier with a USB DAC input. It will not work properly – if at all – with a PulseAudio (pseudo-)output device. -Shairport Sync runs well on the Raspberry Pi. It can drive the built-in sound card, though the audio out of the card is of poor quality. USB-connected sound cards work well on recent versions of Raspian; however older versions of Raspian appear to suffer from a problem — see http://www.raspberrypi.org/forums/viewtopic.php?t=23544, so it is wise to update. Shairport Sync works well with the IQAudIO Pi-DAC — see http://www.iqaudio.com. +Shairport Sync runs well on the Raspberry Pi. It can drive the built-in sound card, though the audio out of the card is of poor quality. USB-connected sound cards work well on recent versions of Raspbian; however older versions of Raspbian appear to suffer from a problem — see http://www.raspberrypi.org/forums/viewtopic.php?t=23544, so it is wise to update. Shairport Sync works well with the IQAudIO Pi-DAC — see http://www.iqaudio.com. At the time of writing, OpenWrt trunk does not support USB audio well on the Raspberry Pi. @@ -83,7 +83,7 @@ Sincere thanks to all package contributors! **General Build Instructions** -To build Shairport Sync from sources on Debian, Ubuntu, Raspian, etc. follow these instructions. +To build Shairport Sync from sources on Debian, Ubuntu, Raspbian, etc. follow these instructions. The following libraries are required: * OpenSSL or PolarSSL @@ -100,13 +100,13 @@ Optional: Many Linux distributions have Avahi and OpenSSL already in place, so normally it probably makes sense to choose those options rather than tinysvcmdns or PolarSSL. Libsoxr is available in recent Linux distributions, but it requires lots of processor power — chances are an embedded processor won't be able to keep up. -Assuming the usual build essentials and git, Debian, Ubuntu and Raspian users can get the basics with: +Assuming the usual build essentials and git, Debian, Ubuntu and Raspbian users can get the basics with: - `apt-get install autoconf libtool libdaemon-dev libasound2-dev libpopt-dev libconfig-dev` - `apt-get install avahi-daemon libavahi-client-dev` if you want to use Avahi (recommended). - `apt-get install libssl-dev` if you want to use OpenSSL and libcrypto, or use PolarSSL otherwise. - `apt-get install libpolarssl-dev` if you want to use PolarSSL, or use OpenSSL/libcrypto otherwise. -- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is not yet part of Raspian; instructions for how to build it from source are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/2.3/LIBSOXR.md). +- `apt-get install libsoxr-dev` if you want support for libsoxr-based resampling. This library is not yet part of Raspbian; instructions for how to build it from source are available at [LIBSOXR.md](https://github.com/mikebrady/shairport-sync/blob/2.3/LIBSOXR.md). Download Shairport Sync: From e052b5fb9efe6572e3eb4584921f712905575ca3 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sat, 11 Oct 2014 19:55:29 +0100 Subject: [PATCH 11/14] Use pkg-config to find libdaemon -- useful in FreeBSD -- and quieten a few warnings in FreeBSD --- audio_alsa.c | 10 +++++----- configure.ac | 12 ++++++++++-- player.c | 8 +++++--- rtsp.c | 6 +++--- shairport.c | 5 +++-- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/audio_alsa.c b/audio_alsa.c index 9b423f9e..d4e54973 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -226,7 +226,7 @@ static int init(int argc, char **argv) { debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0, (1.0 * alsa_mix_maxdb) / 100.0); } else { - debug(1, "Hardware mixer does not have dB volume -- not used."); + inform("note: the hardware mixer specified -- \"%s\" -- does not have dB volume, so it can not be used for volume control.",alsa_mix_ctrl); } } if (snd_mixer_selem_has_playback_switch(alsa_mix_elem)) { @@ -304,7 +304,7 @@ static uint32_t delay() { current_delay = -1; debug(1, "Error -- ALSA delay(): bad state: %d.", snd_pcm_state(alsa_handle)); } - if (derr = snd_pcm_prepare(alsa_handle)) { + if ((derr = snd_pcm_prepare(alsa_handle))) { ignore = snd_pcm_recover(alsa_handle, derr, 0); debug(1, "Error preparing after delay error: %s.", snd_strerror(derr)); current_delay = -1; @@ -336,7 +336,7 @@ static void play(short buf[], int samples) { } else { debug(1, "Error -- ALSA device in incorrect state (%d) for play.", snd_pcm_state(alsa_handle)); - if (err = snd_pcm_prepare(alsa_handle)) { + if ((err = snd_pcm_prepare(alsa_handle))) { ignore = snd_pcm_recover(alsa_handle, err, 0); debug(1, "Error preparing after play error: %s.", snd_strerror(err)); } @@ -349,10 +349,10 @@ static void flush(void) { int derr; if (alsa_handle) { // debug(1,"Dropping frames for flush..."); - if (derr = snd_pcm_drop(alsa_handle)) + if ((derr = snd_pcm_drop(alsa_handle))) debug(1, "Error dropping frames: %s.", snd_strerror(derr)); // debug(1,"Dropped frames ok. State is %d.",snd_pcm_state(alsa_handle)); - if (derr = snd_pcm_prepare(alsa_handle)) + if ((derr = snd_pcm_prepare(alsa_handle))) debug(1, "Error preparing after flush: %s.", snd_strerror(derr)); // debug(1,"Frames successfully dropped."); /* diff --git a/configure.ac b/configure.ac index 624fb5ac..cfca274e 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.5.0.2], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.5.0.3], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) @@ -34,7 +34,15 @@ fi AC_ARG_WITH([pkg_config], [ --with-pkg-config = use pkg-config to find libraries], ,[with_pkg_config=yes]) -AC_CHECK_LIB([daemon],[daemon_log], , AC_MSG_ERROR(libdaemon needed)) +AC_MSG_RESULT(>>Including libdaemon) +if test "x${with_pkg_config}" = xyes ; then + PKG_CHECK_MODULES( + [DAEMON], [libdaemon], + [LIBS="${DAEMON_LIBS} ${LIBS}"]) +else + AC_CHECK_LIB([daemon],[daemon_fork], , AC_MSG_ERROR(libdaemon needed)) +fi + AC_CHECK_LIB([pthread],[pthread_create], , AC_MSG_ERROR(pthread library needed)) AC_CHECK_LIB([m],[exp], , AC_MSG_ERROR(maths library needed)) diff --git a/player.c b/player.c index 425bc879..c86b9724 100644 --- a/player.c +++ b/player.c @@ -1152,8 +1152,8 @@ static void *player_thread_func(void *arg) { (1.0 * tsum_of_insertions_and_deletions) / number_of_statistics; double moving_average_drift = (1.0 * tsum_of_drifts) / number_of_statistics; // if ((play_number/print_interval)%20==0) - if (config.statistics_requested) - if (at_least_one_frame_seen) + if (config.statistics_requested) { + if (at_least_one_frame_seen) { if (config.output->delay) inform("Sync error: %.1f (frames); net correction: %.1f (ppm); corrections: %.1f " "(ppm); missing packets %llu; late packets %llu; too late packets %llu; " @@ -1170,8 +1170,10 @@ static void *player_thread_func(void *arg) { missing_packets, late_packets, too_late_packets, resend_requests, minimum_buffer_occupancy, maximum_buffer_occupancy); - else + } else { inform("No frames received in the last sampling interval."); + } + } minimum_dac_queue_size = 1000000; // hack reset maximum_buffer_occupancy = 0; // can't be less than this minimum_buffer_occupancy = BUFFER_FRAMES; // can't be more than this diff --git a/rtsp.c b/rtsp.c index 6adea0a6..cbd1fa6f 100644 --- a/rtsp.c +++ b/rtsp.c @@ -547,7 +547,7 @@ shutdown: msg_free(msg); // which will free the content and everything else } // in case the message wasn't formed or wasn't fully initialised - if ((msg) && (msg->content == NULL) || (!msg)) + if ((msg && (msg->content == NULL)) || (!msg)) free(buf); *the_packet = NULL; return reply; @@ -973,7 +973,7 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length) if (towrite_count > 57) towrite_count = 57; size_t outbuf_size = 76; // size of output buffer on entry, length of result on exit - if (base64_encode_so(remaining_data, towrite_count, outbuf, &outbuf_size) == NULL) + if (base64_encode_so((unsigned char *)remaining_data, towrite_count, outbuf, &outbuf_size) == NULL) debug(1, "Error encoding base64 data."); // debug(1,"Remaining count: %d ret: %d, outbuf_size: %d.",remaining_count,ret,outbuf_size); ret = non_blocking_write(fd, outbuf, outbuf_size); @@ -1390,7 +1390,7 @@ static int rtsp_auth(char **nonce, rtsp_message *req, rtsp_message *resp) { MD5_Update(&ctx, *nonce, strlen(*nonce)); MD5_Update(&ctx, ":", 1); for (i = 0; i < 16; i++) - sprintf(buf + 2 * i, "%02X", digest_mu[i]); + sprintf((char *)buf + 2 * i, "%02X", digest_mu[i]); MD5_Update(&ctx, buf, 32); MD5_Final(digest_total, &ctx); #endif diff --git a/shairport.c b/shairport.c index 6a7e5ebd..2b37ef05 100644 --- a/shairport.c +++ b/shairport.c @@ -380,13 +380,14 @@ int parse_options(int argc, char **argv) { config.resyncthreshold = value; /* Get the verbosity setting. */ - if (config_lookup_int(config.cfg, "general.log_verbosity", &value)) + if (config_lookup_int(config.cfg, "general.log_verbosity", &value)) { if ((value >= 0) && (value <= 3)) debuglev = value; else die("Invalid log verbosity setting option choice \"%d\". It should be between 0 and 3, " "inclusive.", value); + } /* Get the ignore_volume_control setting. */ if (config_lookup_string(config.cfg, "general.ignore_volume_control", &str)) { @@ -629,7 +630,7 @@ int main(int argc, char **argv) { strcat(configuration_file_path, ".conf"); config.configfile = configuration_file_path; - config.statistics_requested - 0; // don't print stats in the log + config.statistics_requested = 0; // don't print stats in the log config.latency = 88200; // AirPlay. Is also reset in rtsp.c when play is about to start config.userSuppliedLatency = 0; // zero means none supplied config.iTunesLatency = 99400; // this seems to work pretty well for iTunes from Version 10 (?) From 6ae067af1f695e615415cde69a506ad330dbc45b Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Mon, 21 Sep 2015 12:28:55 +0100 Subject: [PATCH 12/14] Fix compilation bug -- did not replace meta_dir with metadata_enabled in a few places --- mdns_dns_sd.c | 2 +- mdns_tinysvcmdns.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mdns_dns_sd.c b/mdns_dns_sd.c index 922c2fb5..99b6b0be 100644 --- a/mdns_dns_sd.c +++ b/mdns_dns_sd.c @@ -38,7 +38,7 @@ static int mdns_dns_sd_register(char *apname, int port) { #endif char **record; #ifdef CONFIG_METADATA - if (config.meta_dir) + if (config.metadata_enabled) record = recordwithmetadata; else #endif diff --git a/mdns_tinysvcmdns.c b/mdns_tinysvcmdns.c index a3c475a2..9452c1f8 100644 --- a/mdns_tinysvcmdns.c +++ b/mdns_tinysvcmdns.c @@ -118,7 +118,7 @@ static int mdns_tinysvcmdns_register(char *apname, int port) { char **txt; #ifdef CONFIG_METADATA - if (config.meta_dir) + if (config.metadata_enabled) txt = txtwithmetadata; else #endif From 5e1d4519e9bed7895c34c1d498bca058d0f60bd0 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Mon, 21 Sep 2015 12:30:14 +0100 Subject: [PATCH 13/14] Bump bug-fix number --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cfca274e..4c778fb8 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.5.0.3], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.5.0.4], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) From ea723e0bde80645fcd39a26e7ea793cc91417530 Mon Sep 17 00:00:00 2001 From: Mke Brady Date: Mon, 21 Sep 2015 21:52:37 +0100 Subject: [PATCH 14/14] Fix crash when metadata enabled but no metadata pipename given --- configure.ac | 2 +- shairport.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 4c778fb8..4d6f2983 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.50]) -AC_INIT([shairport-sync], [2.5.0.4], [mikebrady@eircom.net]) +AC_INIT([shairport-sync], [2.5.0.5], [mikebrady@eircom.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([shairport.c]) AC_CONFIG_HEADERS([config.h]) diff --git a/shairport.c b/shairport.c index 2b37ef05..2561350a 100644 --- a/shairport.c +++ b/shairport.c @@ -541,6 +541,13 @@ int parse_options(int argc, char **argv) { if (c < -1) { die("%s: %s", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c)); } + +#ifdef CONFIG_METADATA + if ((config.metadata_enabled == 1) && (config.metadata_pipename == NULL)) + config.metadata_pipename=strdup("/tmp/shairport-sync-metadata"); +#endif + + if (tdebuglev!=0) debuglev = tdebuglev; return optind + 1; @@ -649,8 +656,7 @@ int main(int argc, char **argv) { gethostname(hostname, 100); config.apname = malloc(20 + 100); snprintf(config.apname, 20 + 100, "Shairport Sync on %s", hostname); - set_requested_connection_state_to_output( - 1); // we expect to be able to connect to the output device + set_requested_connection_state_to_output(1); // we expect to be able to connect to the output device config.audio_backend_buffer_desired_length = 6615; // 0.15 seconds. config.udp_port_base = 6001; config.udp_port_range = 100;