From e1efc6e45a0bc9640f57cac920b489433acef64d Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sun, 17 Feb 2019 12:32:37 +0000 Subject: [PATCH 1/7] add, but don't use, a check to see if alsa uses CLOCK_MONOLITHIC (or, presumably, otherwise CLOCK_REALTIME) --- audio_alsa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/audio_alsa.c b/audio_alsa.c index 4e2fefda..e75d9b41 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -114,6 +114,7 @@ int frame_size; // in bytes for interleaved stereo int alsa_device_initialised; // boolean to ensure the initialisation is only // done once snd_pcm_t *alsa_handle = NULL; +int alsa_uses_monolithic_clock; static snd_pcm_hw_params_t *alsa_params = NULL; static snd_pcm_sw_params_t *alsa_swparams = NULL; static snd_ctl_t *ctl = NULL; @@ -457,6 +458,9 @@ int actual_open_alsa_device(void) { snd_strerror(ret)); return ret; } + + alsa_uses_monolithic_clock = snd_pcm_hw_params_is_monotonic (alsa_params); + debug(1,"alsa does%s use CLOCK_MONOLITHIC",alsa_uses_monolithic_clock ? "" : " not"); ret = snd_pcm_sw_params_current(alsa_handle, alsa_swparams); if (ret < 0) { From 984fc90e5c0eeb8cba7556b65806c5caaf16bffb Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sun, 17 Feb 2019 13:00:38 +0000 Subject: [PATCH 2/7] Check further on stall timing --- audio_alsa.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/audio_alsa.c b/audio_alsa.c index e75d9b41..484d6a23 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -461,6 +461,9 @@ int actual_open_alsa_device(void) { alsa_uses_monolithic_clock = snd_pcm_hw_params_is_monotonic (alsa_params); debug(1,"alsa does%s use CLOCK_MONOLITHIC",alsa_uses_monolithic_clock ? "" : " not"); + + debug (1,"sizeof time_t is: %d.", sizeof(time_t)); + debug (1,"sizeof long is: %d.", sizeof(long)); ret = snd_pcm_sw_params_current(alsa_handle, alsa_swparams); if (ret < 0) { @@ -1172,6 +1175,11 @@ int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay) { ", stall_monitor_error_threshold %" PRIX64 ".", time_now_ns, update_timestamp_ns, stall_monitor_start_time, stall_monitor_error_threshold); + debug(2, "DAC seems to have stalled with time_now: %lx,%lx" + ", update_timestamp: %lx,%lx, stall_monitor_start_time %" PRIX64 + ", stall_monitor_error_threshold %" PRIX64 ".", + tn.tv_sec, tn.tv_nsec, update_timestamp.tv_sec, update_timestamp.tv_nsec, stall_monitor_start_time, + stall_monitor_error_threshold); ret = sps_extra_code_output_stalled; } } else { From 9abb349a1da3e8472071735d64dc7d18ac634bd9 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sun, 17 Feb 2019 13:13:44 +0000 Subject: [PATCH 3/7] +1 --- audio_alsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/audio_alsa.c b/audio_alsa.c index 484d6a23..1013aaee 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -114,7 +114,7 @@ int frame_size; // in bytes for interleaved stereo int alsa_device_initialised; // boolean to ensure the initialisation is only // done once snd_pcm_t *alsa_handle = NULL; -int alsa_uses_monolithic_clock; +int alsa_uses_monotonic_clock = 0; static snd_pcm_hw_params_t *alsa_params = NULL; static snd_pcm_sw_params_t *alsa_swparams = NULL; static snd_ctl_t *ctl = NULL; @@ -459,8 +459,8 @@ int actual_open_alsa_device(void) { return ret; } - alsa_uses_monolithic_clock = snd_pcm_hw_params_is_monotonic (alsa_params); - debug(1,"alsa does%s use CLOCK_MONOLITHIC",alsa_uses_monolithic_clock ? "" : " not"); + alsa_uses_monotonic_clock = snd_pcm_hw_params_is_monotonic(alsa_params); + debug(1,"alsa_uses_monotonic_clock is %d",alsa_uses_monotonic_clock); debug (1,"sizeof time_t is: %d.", sizeof(time_t)); debug (1,"sizeof long is: %d.", sizeof(long)); From dc8483db14dece7e3853723d07476c0b8736931d Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sun, 17 Feb 2019 13:23:34 +0000 Subject: [PATCH 4/7] try using CLOCK_REALTIME -- a bad hack --- audio_alsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/audio_alsa.c b/audio_alsa.c index 484d6a23..2b8d2045 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -114,7 +114,7 @@ int frame_size; // in bytes for interleaved stereo int alsa_device_initialised; // boolean to ensure the initialisation is only // done once snd_pcm_t *alsa_handle = NULL; -int alsa_uses_monolithic_clock; +int alsa_uses_monotonic_clock = 0; static snd_pcm_hw_params_t *alsa_params = NULL; static snd_pcm_sw_params_t *alsa_swparams = NULL; static snd_ctl_t *ctl = NULL; @@ -459,8 +459,8 @@ int actual_open_alsa_device(void) { return ret; } - alsa_uses_monolithic_clock = snd_pcm_hw_params_is_monotonic (alsa_params); - debug(1,"alsa does%s use CLOCK_MONOLITHIC",alsa_uses_monolithic_clock ? "" : " not"); + alsa_uses_monotonic_clock = snd_pcm_hw_params_is_monotonic(alsa_params); + debug(1,"alsa_uses_monotonic_clock is %d",alsa_uses_monotonic_clock); debug (1,"sizeof time_t is: %d.", sizeof(time_t)); debug (1,"sizeof long is: %d.", sizeof(long)); @@ -1158,7 +1158,7 @@ int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay) { if (*state == SND_PCM_STATE_DRAINING) debug(1, "alsa: draining with a delay of %d.", delay); - clock_gettime(CLOCK_MONOTONIC, &tn); + clock_gettime(CLOCK_REALTIME, &tn); uint64_t time_now_ns = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec; uint64_t update_timestamp_ns = update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec; From 2c8d1dfc711564d2e8ec6297969e760fc71f6b83 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sun, 17 Feb 2019 13:52:38 +0000 Subject: [PATCH 5/7] use CLOCK_REALTIME if alsa is earlier than 1.0.28 --- audio_alsa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/audio_alsa.c b/audio_alsa.c index 2b8d2045..01882639 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -1158,7 +1158,12 @@ int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay) { if (*state == SND_PCM_STATE_DRAINING) debug(1, "alsa: draining with a delay of %d.", delay); +#if SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR < 28 clock_gettime(CLOCK_REALTIME, &tn); +#else + clock_gettime(CLOCK_MONOTONIC, &tn); +#endif + uint64_t time_now_ns = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec; uint64_t update_timestamp_ns = update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec; From a8038c15c9f408f8db2c067cd06247c712e2aef1 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sun, 17 Feb 2019 14:00:10 +0000 Subject: [PATCH 6/7] remove some diagnostics and add in a comment -- using CLOCK_REALTIME with alsa libraries before 1.0.28 --- audio_alsa.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/audio_alsa.c b/audio_alsa.c index 01882639..52cffe9d 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -114,7 +114,6 @@ int frame_size; // in bytes for interleaved stereo int alsa_device_initialised; // boolean to ensure the initialisation is only // done once snd_pcm_t *alsa_handle = NULL; -int alsa_uses_monotonic_clock = 0; static snd_pcm_hw_params_t *alsa_params = NULL; static snd_pcm_sw_params_t *alsa_swparams = NULL; static snd_ctl_t *ctl = NULL; @@ -459,12 +458,6 @@ int actual_open_alsa_device(void) { return ret; } - alsa_uses_monotonic_clock = snd_pcm_hw_params_is_monotonic(alsa_params); - debug(1,"alsa_uses_monotonic_clock is %d",alsa_uses_monotonic_clock); - - debug (1,"sizeof time_t is: %d.", sizeof(time_t)); - debug (1,"sizeof long is: %d.", sizeof(long)); - ret = snd_pcm_sw_params_current(alsa_handle, alsa_swparams); if (ret < 0) { warn("audio_alsa: Unable to get current sw parameters for device \"%s\": " @@ -1158,6 +1151,8 @@ int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay) { if (*state == SND_PCM_STATE_DRAINING) debug(1, "alsa: draining with a delay of %d.", delay); +// It seems that the alsa library uses CLOCK_REALTIME before 1.0.28, even though +// the check for monotonic returns true. Might have to watch out for this. #if SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR < 28 clock_gettime(CLOCK_REALTIME, &tn); #else From 00be8bc2a6dd29b5d1d71a85ecb6d0467a149f20 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sun, 17 Feb 2019 14:10:45 +0000 Subject: [PATCH 7/7] fix the ability to give attenation priority to hardware or software, set the default to software --- scripts/shairport-sync.conf | 2 +- shairport.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/shairport-sync.conf b/scripts/shairport-sync.conf index bf6ce4ba..52d3232f 100644 --- a/scripts/shairport-sync.conf +++ b/scripts/shairport-sync.conf @@ -29,7 +29,7 @@ general = // volume_control_profile = "standard" ; // use this advanced setting to specify how the airplay volume is transferred to the mixer volume. // "standard" makes the volume change more quickly at lower volumes and slower at higher volumes. // "flat" makes the volume change at the same rate at all volumes. -// volume_range_hw_priority = "yes"; // when extending the volume range by combining the built-in software attenuator with the hardware mixer attenuator, set this to "yes" to reduce volume by using the hardware attenuator first, then the software attenuator. +// volume_range_combined_hardware_priority = "no"; // when extending the volume range by combining the built-in software attenuator with the hardware mixer attenuator, set this to "yes" to reduce volume by using the hardware mixer first, then the built-in software attenuator. // run_this_when_volume_is_set = "/full/path/to/application/and/args"; // Run the specified application whenever the volume control is set or changed. // The desired AirPlay volume is appended to the end of the command line – leave a space if you want it treated as an extra argument. // AirPlay volume goes from 0 to -30 and -144 means "mute". diff --git a/shairport.c b/shairport.c index 4cb316e1..21f4ff52 100644 --- a/shairport.c +++ b/shairport.c @@ -344,8 +344,9 @@ int parse_options(int argc, char **argv) { config.diagnostic_drop_packet_fraction = 0.0; config.active_state_timeout = 10.0; config.volume_range_hw_priority = - 1; // if combining software and hardware volume control, give the hardware priority -// i.e. when reducing volume, reduce the hw first before reducing the software. + 0; // if combining software and hardware volume control, give the software priority +// i.e. when reducing volume, reduce the sw first before reducing the software. +// this is because some hw mixers mute at the bottom of their range, and they don't always advertise this fact #ifdef CONFIG_METADATA_HUB config.cover_art_cache_dir = "/tmp/shairport-sync/.cache/coverart"; @@ -1568,7 +1569,7 @@ int main(int argc, char **argv) { config.volume_range_db); debug( 1, - "combined attenuators (0 -- software is / 1 -- hardware is top of attenuation range) is %d.", + "volume_range_combined_hardware_priority (1 means hardware mixer attenuation is used first) is %d.", config.volume_range_hw_priority); debug(1, "playback_mode is %d (0-stereo, 1-mono, 1-reverse_stereo, 2-both_left, 3-both_right).", config.playback_mode);