diff --git a/pipewire-pulseaudio/src/internal.h b/pipewire-pulseaudio/src/internal.h index 1ef9b2231..a2207a9da 100644 --- a/pipewire-pulseaudio/src/internal.h +++ b/pipewire-pulseaudio/src/internal.h @@ -508,6 +508,9 @@ struct pa_operation bool pa_mainloop_api_is_pipewire(pa_mainloop_api *api); +#define PA_TIMEVAL_RTCLOCK ((time_t) (1LU << 30)) +struct timeval* pa_rtclock_from_wallclock(struct timeval *tv); + pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, size_t userdata_size); void pa_operation_done(pa_operation *o); int pa_operation_sync(pa_operation *o); diff --git a/pipewire-pulseaudio/src/mainloop.c b/pipewire-pulseaudio/src/mainloop.c index 8fc64538f..eb3e84d16 100644 --- a/pipewire-pulseaudio/src/mainloop.c +++ b/pipewire-pulseaudio/src/mainloop.c @@ -116,48 +116,46 @@ static void source_timer_func(void *data, uint64_t expirations) ev->cb(&ev->mainloop->api, ev, &tv, ev->userdata); } +static void set_timer(pa_time_event *ev, const struct timeval *tv) +{ + pa_mainloop *mainloop = ev->mainloop; + struct timespec ts; + struct timeval ttv = *tv; + + if (tv == NULL) { + ts.tv_sec = 0; + ts.tv_nsec = 1; + } else { + if ((tv->tv_usec & PA_TIMEVAL_RTCLOCK) == 0) + pa_rtclock_from_wallclock(&ttv); + ts.tv_sec = ttv.tv_sec; + ts.tv_nsec = ttv.tv_usec * 1000LL; + } + pw_log_debug("set timer %p %ld %ld", ev, ts.tv_sec, ts.tv_nsec); + pw_loop_update_timer(mainloop->loop, ev->source, &ts, NULL, true); +} + static pa_time_event* api_time_new(pa_mainloop_api*a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) { pa_mainloop *mainloop = SPA_CONTAINER_OF(a, pa_mainloop, api); pa_time_event *ev; - struct timespec ts; ev = calloc(1, sizeof(pa_time_event)); ev->source = pw_loop_add_timer(mainloop->loop, source_timer_func, ev); ev->mainloop = mainloop; ev->cb = cb; ev->userdata = userdata; + pw_log_debug("new timer %p", ev); - if (tv == NULL) { - ts.tv_sec = 0; - ts.tv_nsec = 1; - } - else { - ts.tv_sec = tv->tv_sec; - ts.tv_nsec = tv->tv_usec * 1000LL; - } - pw_log_debug("new timer %p %ld %ld", ev, ts.tv_sec, ts.tv_nsec); - pw_loop_update_timer(mainloop->loop, ev->source, &ts, NULL, true); + set_timer(ev, tv); return ev; } static void api_time_restart(pa_time_event* e, const struct timeval *tv) { - struct timespec ts; - pa_assert(e); - - if (tv == NULL) { - ts.tv_sec = 0; - ts.tv_nsec = 1; - } - else { - ts.tv_sec = tv->tv_sec; - ts.tv_nsec = tv->tv_usec * 1000LL; - } - pw_log_debug("io %p", e); - pw_loop_update_timer(e->mainloop->loop, e->source, &ts, NULL, true); + set_timer(e, tv); } static void api_time_free(pa_time_event* e) diff --git a/pipewire-pulseaudio/src/rtclock.c b/pipewire-pulseaudio/src/rtclock.c index a3e5e4cb0..a9208f488 100644 --- a/pipewire-pulseaudio/src/rtclock.c +++ b/pipewire-pulseaudio/src/rtclock.c @@ -23,7 +23,9 @@ #include +#include #include +#include "internal.h" SPA_EXPORT pa_usec_t pa_rtclock_now(void) @@ -36,3 +38,34 @@ pa_usec_t pa_rtclock_now(void) return res; } +static struct timeval *pa_rtclock_get(struct timeval *tv) +{ + struct timespec ts; + + pa_assert(tv); + + clock_gettime(CLOCK_MONOTONIC, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC; + return tv; +} + +struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) +{ + struct timeval wc_now, rt_now; + + pa_assert(tv); + + pa_gettimeofday(&wc_now); + pa_rtclock_get(&rt_now); + + if (pa_timeval_cmp(&wc_now, tv) < 0) + pa_timeval_add(&rt_now, pa_timeval_diff(tv, &wc_now)); + else + pa_timeval_sub(&rt_now, pa_timeval_diff(&wc_now, tv)); + + *tv = rt_now; + + return tv; +} +