From: Mike Brady Date: Mon, 3 Dec 2018 12:44:57 +0000 (+0000) Subject: Ensure no pthread cancellation can occur during an ALSA-related call. X-Git-Tag: 3.3RC0~119^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e49707e051073e9b1eed71e58cee427e3a23b0a6;p=thirdparty%2Fshairport-sync.git Ensure no pthread cancellation can occur during an ALSA-related call. --- e49707e051073e9b1eed71e58cee427e3a23b0a6 diff --cc audio_alsa.c index a5c47d8c,372f84d1..98182989 --- a/audio_alsa.c +++ b/audio_alsa.c @@@ -136,6 -134,6 +136,8 @@@ static void help(void) void set_alsa_out_dev(char *dev) { alsa_out_dev = dev; } ++ ++//assuming pthread cancellation is disabled int open_mixer() { int response = 0; if (hardware_mixer) { @@@ -179,6 -177,6 +181,7 @@@ return response; } ++//assuming pthread cancellation is disabled void close_mixer() { if (alsa_mix_handle) { snd_mixer_close(alsa_mix_handle); @@@ -186,6 -184,6 +189,7 @@@ } } ++//assuming pthread cancellation is disabled void do_snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *mix_elem, double vol) { if (snd_mixer_selem_set_playback_dB_all(mix_elem, vol, 0) != 0) { debug(1, "Can't set playback volume accurately to %f dB.", vol); @@@ -196,8 -194,6 +200,9 @@@ } static int init(int argc, char **argv) { ++ // for debugging + snd_output_stdio_attach(&output, stdout, 0); + // debug(2,"audio_alsa init called."); int response = 0; // this will be what we return to the caller. const char *str; @@@ -406,11 -402,9 +411,11 @@@ warn("Invalid audio argument: \"%s\" -- ignored", argv[optind]); } - debug(1, "alsa output device name is \"%s\".", alsa_out_dev); + debug(1, "alsa: output device name is \"%s\".", alsa_out_dev); if (hardware_mixer) { + int oldState; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable if (alsa_mix_dev == NULL) alsa_mix_dev = alsa_out_dev; @@@ -497,9 -491,8 +502,9 @@@ } debug_mutex_unlock(&alsa_mutex, 3); // release the mutex pthread_cleanup_pop(0); + pthread_setcancelstate(oldState, NULL); } else { - // debug(1, "Has no mixer and thus no hardware mute."); + debug(1, "alsa: no hardware mixer selected."); } alsa_mix_handle = NULL; @@@ -511,7 -504,7 +516,8 @@@ static void deinit(void) stop(); } -int open_alsa_device(void) { ++//assuming pthread cancellation is disabled +int actual_open_alsa_device(void) { // the alsa mutex is already acquired when this is called const snd_pcm_uframes_t minimal_buffer_headroom = 352 * 2; // we accept this much headroom in the hardware buffer, but we'll @@@ -906,42 -867,6 +912,43 @@@ static void start(int i_sample_rate, in measurement_data_is_valid = 0; } ++//assuming pthread cancellation is disabled +int my_snd_pcm_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { + int ret; + snd_pcm_status_t *alsa_snd_pcm_status; + snd_pcm_status_alloca(&alsa_snd_pcm_status); + + struct timespec tn; // time now + snd_htimestamp_t update_timestamp; // actually a struct timespec + + ret = snd_pcm_status(pcm, alsa_snd_pcm_status); + if (ret) { + *delayp = 0; + return ret; + } + + snd_pcm_state_t state = snd_pcm_status_get_state(alsa_snd_pcm_status); + if (state != SND_PCM_STATE_RUNNING) { + *delayp = 0; + return -EIO; // might be a better code than this... + } + + clock_gettime(CLOCK_MONOTONIC, &tn); + snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp); + + uint64_t t1 = tn.tv_sec * (uint64_t)1000000000 + tn.tv_nsec; + uint64_t t2 = update_timestamp.tv_sec * (uint64_t)1000000000 + update_timestamp.tv_nsec; + uint64_t delta = t1 - t2; + + uint64_t frames_played_since_last_interrupt = + ((uint64_t)desired_sample_rate * delta) / 1000000000; + snd_pcm_sframes_t frames_played_since_last_interrupt_sized = frames_played_since_last_interrupt; + + *delayp = + snd_pcm_status_get_delay(alsa_snd_pcm_status) - frames_played_since_last_interrupt_sized; + return 0; +} + int delay(long *the_delay) { // snd_pcm_sframes_t is a signed long -- hence the return of a "long" int reply = 0; @@@ -1125,10 -1045,9 +1133,10 @@@ static int play(void *buf, int samples frame_index = 0; measurement_data_is_valid = 0; } - debug_mutex_unlock(&alsa_mutex, 3); + debug_mutex_unlock(&alsa_mutex, 0); pthread_cleanup_pop(0); // release the mutex } + pthread_setcancelstate(oldState, NULL); return ret; } @@@ -1292,7 -1205,5 +1300,6 @@@ void do_mute(int mute_state_requested) close_mixer(); } } -- mute_request_pending = 0; - ++ mute_request_pending = 0; + pthread_setcancelstate(oldState, NULL); }