diff --git a/README.md b/README.md index 6cbe42f9..5d667362 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: diff --git a/RELEASENOTES.md b/RELEASENOTES.md index daf68af5..b90770f5 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,9 +1,16 @@ -HEAD +Version 2.4.1 ---- -These changes have been made in the HEAD, not yet part of a release. -**Documentation Updates** -* Various small documentation updates. +This release has two small bug fixes and some small documentation updates. + +**Bug Fixes** +Changes from the previous stable version -- 2.4 -- are summarised here: + * The USE_CUSTOM_LOCAL_STATE_DIR macro was still being used when it should have been USE_CUSTOM_PID_DIR. This could affect users using a custom location for the PID directory. + * A crash has been fixed that occured if metadata was enabled and a metadata pipename was not specified. + * If a mixer being used to control volume does not have a control denominated in dB, a warning is logged and the mixer is not used. + +**Small Changes** + * Slight revisions have been made to the configuration file `configure.ac` to make compilation on FreeBSD a little easier. Version 2.4 ---- 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 4c3d3afd..b3cd1726 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.4.1], [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/mdns_dns_sd.c b/mdns_dns_sd.c index b9e11b45..114bb991 100644 --- a/mdns_dns_sd.c +++ b/mdns_dns_sd.c @@ -39,7 +39,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 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 21680017..c2be34bc 100644 --- a/rtsp.c +++ b/rtsp.c @@ -549,7 +549,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; @@ -584,8 +584,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) { @@ -626,6 +645,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; @@ -960,7 +980,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); @@ -1377,7 +1397,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-sync.spec b/shairport-sync.spec index 5c1308e8..80b000f9 100644 --- a/shairport-sync.spec +++ b/shairport-sync.spec @@ -1,5 +1,5 @@ Name: shairport-sync -Version: 2.4 +Version: 2.4.1 Release: 1%{?dist} Summary: AirTunes emulator. Shairport Sync adds multi-room capability with Audio Synchronisation @@ -57,6 +57,8 @@ getent passwd %{name} &> /dev/null || useradd --system -c "%{name} User" \ %doc AUTHORS LICENSES README.md %changelog +* Thu Aug 27 2015 Mike Brady 2.4.1 +- Minor bug fixes 2.4.1 * Thu Aug 27 2015 Mike Brady 2.4 - Prepare for stable release 2.4 * Wed Aug 26 2015 Mike Brady 2.3.13.1-1 diff --git a/shairport.c b/shairport.c index e6a9ea0a..e90f3675 100644 --- a/shairport.c +++ b/shairport.c @@ -378,13 +378,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)) { @@ -538,6 +539,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; @@ -627,7 +635,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 (?) @@ -646,8 +654,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; @@ -678,8 +685,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