[pulseaudio-discuss] [PATCH 25/25] raop: More precise thread wakeup clock calculation
Hajime Fujita
crisp.fujita at nifty.com
Sat Sep 7 09:35:14 PDT 2013
Current wakeup clock calculation scheme accumulates an error per
each sleep cycle (max. 1us/cycle) due to precision limitation of
pa_usec_t. Thus it may cause timing issue when playing music for
a long period.
This patch introduces a new clock calculation scheme to minimize
an error.
---
src/modules/raop/module-raop-sink.c | 40 ++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/src/modules/raop/module-raop-sink.c b/src/modules/raop/module-raop-sink.c
index b600cf8..754877c 100644
--- a/src/modules/raop/module-raop-sink.c
+++ b/src/modules/raop/module-raop-sink.c
@@ -118,6 +118,10 @@ struct userdata {
/* Members only for the UDP protocol */
int udp_control_fd;
int udp_timing_fd;
+
+ /* For UDP thread wakeup clock calculation */
+ pa_usec_t udp_playback_start;
+ uint32_t udp_sent_packets;
};
static const char* const valid_modargs[] = {
@@ -281,6 +285,22 @@ static int tcp_sink_process_msg(pa_msgobject *o, int code, void *data, int64_t o
return pa_sink_process_msg(o, code, data, offset, chunk);
}
+static void udp_start_wakeup_clock(struct userdata *u) {
+ pa_usec_t now = pa_rtclock_now();
+
+ u->udp_playback_start = now;
+ u->udp_sent_packets = 0;
+ pa_rtpoll_set_timer_absolute(u->rtpoll, now);
+}
+
+static pa_usec_t udp_next_wakeup_clock(struct userdata *u) {
+ pa_usec_t intvl = pa_bytes_to_usec(u->block_size * u->udp_sent_packets,
+ &u->sink->sample_spec);
+ /* FIXME: how long until (u->block_size * u->udp_sent_packets) wraps?? */
+
+ return u->udp_playback_start + intvl;
+}
+
static int udp_sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK(o)->userdata;
@@ -318,7 +338,7 @@ static int udp_sink_process_msg(pa_msgobject *o, int code, void *data, int64_t o
/* Connecting will trigger a RECORD */
pa_raop_client_connect(u->raop);
}
- pa_rtpoll_set_timer_relative(u->rtpoll, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec));
+ udp_start_wakeup_clock(u);
break;
@@ -359,7 +379,7 @@ static int udp_sink_process_msg(pa_msgobject *o, int code, void *data, int64_t o
}
case SINK_MESSAGE_UDP_RECORD: {
- pa_rtpoll_set_timer_relative(u->rtpoll, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec));
+ udp_start_wakeup_clock(u);
if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
/* Our stream has been suspended so we just flush it... */
@@ -678,11 +698,6 @@ 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");
@@ -772,16 +787,9 @@ static void udp_thread_func(struct userdata *u) {
goto fail;
}
- /* 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;
+ u->udp_sent_packets++;
/* Sleep until next packet transmission */
- pa_rtpoll_set_timer_absolute(u->rtpoll, wakeup_target);
+ pa_rtpoll_set_timer_absolute(u->rtpoll, udp_next_wakeup_clock(u));
u->offset += written;
u->encoding_overhead += overhead;
--
1.8.1.2
More information about the pulseaudio-discuss
mailing list