Due to timer precision limitation, poll(2) may sleep longer or shorter than originally specified. Therefore it is not safe to always specify the fixed sleep interval for poll(2) (pa_rtpoll_set_timer_relative()) when executing some periodic tasks that are sensitive to precise timing. This patch calculates when the thread should wake up to transmit the next audio packet, and try to amortize the jitter caused by the actual poll sleep duration. This patch eliminates the audio glitch issue in Pioneer VSX-43 (and possibly in other devices as well). --- src/modules/raop/module-raop-sink.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/modules/raop/module-raop-sink.c b/src/modules/raop/module-raop-sink.c index c6008e9..0038bad 100644 --- a/src/modules/raop/module-raop-sink.c +++ b/src/modules/raop/module-raop-sink.c @@ -669,6 +669,11 @@ finish: } static void udp_thread_func(struct userdata *u) { + /* Sleep interval per audio packet */ + pa_usec_t sleep_interval = pa_bytes_to_usec(u->block_size, + &u->sink->sample_spec); + pa_usec_t wakeup_target = 0; /* Next wakeup target clock (in us) */ + pa_assert(u); pa_log_debug("UDP thread starting up"); @@ -753,7 +758,17 @@ static void udp_thread_func(struct userdata *u) { pa_assert(u->encoded_memchunk.length > 0); pa_raop_client_udp_send_audio_packet(u->raop, &u->encoded_memchunk, &written); - pa_rtpoll_set_timer_relative(u->rtpoll, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec)); + + /* Determine when to wake up next: + next_target = prev_target + interval, unless we passed + prev_target + interval. + In such a case just sleep for one interval */ + if (wakeup_target + sleep_interval < pa_rtclock_now()) + wakeup_target = pa_rtclock_now() + sleep_interval; + else + wakeup_target += sleep_interval; + /* Sleep until next packet transmission */ + pa_rtpoll_set_timer_absolute(u->rtpoll, wakeup_target); pa_assert(written != 0); -- 1.8.1.2