From: Mike Brady Date: Mon, 17 Jun 2019 06:54:04 +0000 (+0100) Subject: restore full code for checking for precise timing but stop making it necessary for... X-Git-Tag: 3.3.2~4^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dbea82c2120e16f04c8fd4e1dba80811dae08a9f;p=thirdparty%2Fshairport-sync.git restore full code for checking for precise timing but stop making it necessary for disable standby mode. --- diff --git a/audio_alsa.c b/audio_alsa.c index 956deba5..f56cb478 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -162,12 +162,70 @@ int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, // use this to allow the use of standard or precision delay calculations, with standard the, uh, standard. int (*delay_and_status)(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) = standard_delay_and_status; +// this will return true if the DAC can return precision delay information and false if not +// if it is not yet known, it will test the output device to find out + +// note -- once it has done the test, it decides -- even if the delay comes back with +// "don't know", it will take that as a "No" and remember it. +// If you want it to check again, set precision_delay_available_status to YNDK_DONT_KNOW +// first. + int precision_delay_available() { - // this is very crude -- if the device is a hardware device, then it's assumed the delay is precise - const char *output_device_name = snd_pcm_name(alsa_handle); - return (strstr(output_device_name,"hw:") == output_device_name); + if (precision_delay_available_status == YNDK_DONT_KNOW) { + // At present, the only criterion as to whether precision delay is available + // is whether the device driver returns non-zero update timestamps + // If it does, it is considered precision delay is available + // Otherwise, it's considered to be unavailable + + // To test, we play a silence buffer (fairly large to avoid underflow) + // and then we check the delay return. It will tell us if it + // was able to use the (non-zero) update timestamps + + int frames_of_silence = 4410; + size_t size_of_silence_buffer = frames_of_silence * frame_size; + void *silence = malloc(size_of_silence_buffer); + if (silence == NULL) { + debug(1, "alsa: precision_delay_available -- failed to " + "allocate memory for a " + "silent frame buffer."); + } else { + pthread_cleanup_push(malloc_cleanup, silence); + int use_dither = 0; + if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) && + (config.airplay_volume != 0.0)) + use_dither = 1; + dither_random_number_store = + generate_zero_frames(silence, frames_of_silence, config.output_format, + use_dither, // i.e. with dither + dither_random_number_store); + // debug(1,"Play %d frames of silence with most_recent_write_time of + // %" PRIx64 ".", + // frames_of_silence,most_recent_write_time); + do_play(silence, frames_of_silence); + pthread_cleanup_pop(1); + // now we can get the delay, and we'll note if it uses update timestamps + enum yndk_type uses_update_timestamps; + snd_pcm_state_t state; + snd_pcm_sframes_t delay; + int ret = delay_and_status(&state, &delay, &uses_update_timestamps); + // debug(3,"alsa: precision_delay_available asking for delay and status with a return status of %d, a delay of %ld and a uses_update_timestamps of %d.", ret, delay, uses_update_timestamps); + if (ret == 0) { + if (uses_update_timestamps == YNDK_YES) { + precision_delay_available_status = YNDK_YES; + debug(2,"alsa: precision delay timing available."); + } else { + precision_delay_available_status = YNDK_NO; + debug(2,"alsa: precision delay timing not available."); + if (config.disable_standby_mode != disable_standby_off) + inform("Note: disable_standby_mode has been turned off because the output device is not capable of precision delay timing."); + } + } + } + } + return (precision_delay_available_status == YNDK_YES); } + // static int play_number; // static int64_t accumulated_delay, accumulated_da_delay; int alsa_characteristics_already_listed = 0; @@ -1850,8 +1908,8 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) { // and config.keep_dac_busy is true (at the present, this has to be the case // to be in the // abm_connected state in the first place...) then do the silence-filling - // thing, if needed, and if the output device is capable of precision delay. - if ((alsa_backend_state != abm_disconnected) && (config.keep_dac_busy != 0) && precision_delay_available()) { + // thing, if needed /* only if the output device is capable of precision delay */. + if ((alsa_backend_state != abm_disconnected) && (config.keep_dac_busy != 0) /* && precision_delay_available() */ ) { int reply; long buffer_size = 0; snd_pcm_state_t state;