mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-08 13:29:59 -05:00
Base mainloop on pa_rtclock_now()
Move the mainloop to monotonic based time events.
Introduces 4 helper functions:
pa_{context,core}_rttime_{new,restart}(), that fill correctly a
timeval with the rtclock flag set if the mainloop supports it.
Both mainloop-test and mainloop-test-glib works with rt and timeval
based time events. PulseAudio and clients should be fully functional.
This patch has received several iterations, and this one as been
largely untested.
Signed-off-by: Marc-André Lureau <marca-andre.lureau@nokia.com>
This commit is contained in:
parent
125c528896
commit
0955e3d45b
42 changed files with 311 additions and 233 deletions
|
|
@ -64,6 +64,7 @@
|
|||
#include <pulsecore/dynarray.h>
|
||||
#include <pulsecore/socket-client.h>
|
||||
#include <pulsecore/pstream-util.h>
|
||||
#include <pulsecore/core-rtclock.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
#include <pulsecore/socket-util.h>
|
||||
|
|
@ -540,7 +541,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) {
|
|||
pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
|
||||
|
||||
pa_assert(!c->pdispatch);
|
||||
c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
|
||||
c->pdispatch = pa_pdispatch_new(c->mainloop, c->use_rtclock, command_table, PA_COMMAND_MAX);
|
||||
|
||||
if (!c->conf->cookie_valid)
|
||||
pa_log_info(_("No cookie loaded. Attempting to connect without."));
|
||||
|
|
@ -757,7 +758,7 @@ static void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wr
|
|||
pa_assert(conn);
|
||||
|
||||
dbus_error_init(&error);
|
||||
if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, type, &error)) || dbus_error_is_set(&error)) {
|
||||
if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) {
|
||||
pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message);
|
||||
goto finish;
|
||||
}
|
||||
|
|
@ -827,7 +828,7 @@ static int try_next_connection(pa_context *c) {
|
|||
pa_xfree(c->server);
|
||||
c->server = pa_xstrdup(u);
|
||||
|
||||
if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT)))
|
||||
if (!(c->client = pa_socket_client_new_string(c->mainloop, c->use_rtclock, u, PA_NATIVE_DEFAULT_PORT)))
|
||||
continue;
|
||||
|
||||
c->is_local = !!pa_socket_client_is_local(c->client);
|
||||
|
|
@ -1443,3 +1444,25 @@ finish:
|
|||
if (pl)
|
||||
pa_proplist_free(pl);
|
||||
}
|
||||
|
||||
pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
|
||||
struct timeval tv;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(c->mainloop);
|
||||
|
||||
pa_timeval_rtstore(&tv, usec, c->use_rtclock);
|
||||
|
||||
return c->mainloop->time_new(c->mainloop, &tv, cb, userdata);
|
||||
}
|
||||
|
||||
void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec) {
|
||||
struct timeval tv;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(c->mainloop);
|
||||
|
||||
pa_timeval_rtstore(&tv, usec, c->use_rtclock);
|
||||
|
||||
c->mainloop->time_restart(e, &tv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,6 +260,14 @@ pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[]
|
|||
* introspection functions, such as pa_context_get_client_info(). \since 0.9.11 */
|
||||
uint32_t pa_context_get_index(pa_context *s);
|
||||
|
||||
/** Create a new timer event source for the specified time (wrapper
|
||||
for mainloop->time_new). \since 0.9.16 */
|
||||
pa_time_event* pa_context_rttime_new(pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata);
|
||||
/** Restart a running or expired timer event source (wrapper
|
||||
for mainloop->time_restart). \since 0.9.16 */
|
||||
void pa_context_rttime_restart(pa_context *c, pa_time_event *e, pa_usec_t usec);
|
||||
|
||||
|
||||
PA_C_DECL_END
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ struct pa_context {
|
|||
pa_bool_t server_specified:1;
|
||||
pa_bool_t no_fail:1;
|
||||
pa_bool_t do_autospawn:1;
|
||||
pa_bool_t use_rtclock:1;
|
||||
pa_spawn_api spawn_api;
|
||||
|
||||
pa_strlist *server_list;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include <pulse/cdecl.h>
|
||||
#include <pulse/sample.h>
|
||||
#include <pulse/version.h>
|
||||
|
||||
/** \file
|
||||
|
|
|
|||
|
|
@ -42,10 +42,12 @@
|
|||
#include <pulsecore/pipe.h>
|
||||
#endif
|
||||
|
||||
#include <pulse/i18n.h>
|
||||
#include <pulse/rtclock.h>
|
||||
#include <pulse/timeval.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/i18n.h>
|
||||
|
||||
#include <pulsecore/core-rtclock.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/llist.h>
|
||||
#include <pulsecore/log.h>
|
||||
|
|
@ -75,7 +77,7 @@ struct pa_time_event {
|
|||
pa_bool_t dead:1;
|
||||
|
||||
pa_bool_t enabled:1;
|
||||
struct timeval timeval;
|
||||
pa_usec_t time;
|
||||
|
||||
pa_time_event_cb_t callback;
|
||||
void *userdata;
|
||||
|
|
@ -317,6 +319,21 @@ static void mainloop_defer_set_destroy(pa_defer_event *e, pa_defer_event_destroy
|
|||
}
|
||||
|
||||
/* Time events */
|
||||
static pa_usec_t timeval_load(struct timeval *tv) {
|
||||
pa_bool_t is_rtclock;
|
||||
|
||||
if (!tv)
|
||||
return PA_USEC_INVALID;
|
||||
|
||||
is_rtclock = !!(tv->tv_usec & PA_TIMEVAL_RTCLOCK);
|
||||
tv->tv_usec &= ~PA_TIMEVAL_RTCLOCK;
|
||||
|
||||
if (!is_rtclock)
|
||||
pa_rtclock_from_wallclock(tv);
|
||||
|
||||
return pa_timeval_load(tv);
|
||||
}
|
||||
|
||||
static pa_time_event* mainloop_time_new(
|
||||
pa_mainloop_api*a,
|
||||
const struct timeval *tv,
|
||||
|
|
@ -325,11 +342,14 @@ static pa_time_event* mainloop_time_new(
|
|||
|
||||
pa_mainloop *m;
|
||||
pa_time_event *e;
|
||||
pa_usec_t t;
|
||||
struct timeval ttv;
|
||||
|
||||
pa_assert(a);
|
||||
pa_assert(a->userdata);
|
||||
pa_assert(callback);
|
||||
|
||||
t = timeval_load(tv? ttv = *tv, &ttv : NULL);
|
||||
m = a->userdata;
|
||||
pa_assert(a == &m->api);
|
||||
|
||||
|
|
@ -337,15 +357,15 @@ static pa_time_event* mainloop_time_new(
|
|||
e->mainloop = m;
|
||||
e->dead = FALSE;
|
||||
|
||||
if ((e->enabled = !!tv)) {
|
||||
e->timeval = *tv;
|
||||
if ((e->enabled = (t != PA_USEC_INVALID))) {
|
||||
e->time = t;
|
||||
|
||||
m->n_enabled_time_events++;
|
||||
|
||||
if (m->cached_next_time_event) {
|
||||
pa_assert(m->cached_next_time_event->enabled);
|
||||
|
||||
if (pa_timeval_cmp(tv, &m->cached_next_time_event->timeval) < 0)
|
||||
if (t < m->cached_next_time_event->time)
|
||||
m->cached_next_time_event = e;
|
||||
}
|
||||
}
|
||||
|
|
@ -363,24 +383,30 @@ static pa_time_event* mainloop_time_new(
|
|||
}
|
||||
|
||||
static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) {
|
||||
pa_bool_t valid;
|
||||
pa_usec_t t;
|
||||
struct timeval ttv;
|
||||
|
||||
pa_assert(e);
|
||||
pa_assert(!e->dead);
|
||||
|
||||
if (e->enabled && !tv) {
|
||||
t = timeval_load(tv? ttv = *tv, &ttv : NULL);
|
||||
valid = (t != PA_USEC_INVALID);
|
||||
if (e->enabled && !valid) {
|
||||
pa_assert(e->mainloop->n_enabled_time_events > 0);
|
||||
e->mainloop->n_enabled_time_events--;
|
||||
} else if (!e->enabled && tv)
|
||||
} else if (!e->enabled && valid)
|
||||
e->mainloop->n_enabled_time_events++;
|
||||
|
||||
if ((e->enabled = !!tv)) {
|
||||
e->timeval = *tv;
|
||||
if ((e->enabled = valid)) {
|
||||
e->time = t;
|
||||
pa_mainloop_wakeup(e->mainloop);
|
||||
}
|
||||
|
||||
if (e->mainloop->cached_next_time_event && e->enabled) {
|
||||
pa_assert(e->mainloop->cached_next_time_event->enabled);
|
||||
|
||||
if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0)
|
||||
if (t < e->mainloop->cached_next_time_event->time)
|
||||
e->mainloop->cached_next_time_event = e;
|
||||
} else if (e->mainloop->cached_next_time_event == e)
|
||||
e->mainloop->cached_next_time_event = NULL;
|
||||
|
|
@ -721,11 +747,11 @@ static pa_time_event* find_next_time_event(pa_mainloop *m) {
|
|||
if (t->dead || !t->enabled)
|
||||
continue;
|
||||
|
||||
if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) {
|
||||
if (!n || t->time < n->time) {
|
||||
n = t;
|
||||
|
||||
/* Shortcut for tv = { 0, 0 } */
|
||||
if (n->timeval.tv_sec <= 0)
|
||||
/* Shortcut for time == 0 */
|
||||
if (n->time == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -736,7 +762,6 @@ static pa_time_event* find_next_time_event(pa_mainloop *m) {
|
|||
|
||||
static int calc_next_timeout(pa_mainloop *m) {
|
||||
pa_time_event *t;
|
||||
struct timeval now;
|
||||
pa_usec_t usec;
|
||||
|
||||
if (!m->n_enabled_time_events)
|
||||
|
|
@ -745,41 +770,41 @@ static int calc_next_timeout(pa_mainloop *m) {
|
|||
t = find_next_time_event(m);
|
||||
pa_assert(t);
|
||||
|
||||
if (t->timeval.tv_sec <= 0)
|
||||
if (t->time == 0)
|
||||
return 0;
|
||||
|
||||
pa_gettimeofday(&now);
|
||||
usec = t->time - pa_rtclock_now();
|
||||
|
||||
if (pa_timeval_cmp(&t->timeval, &now) <= 0)
|
||||
if (usec <= 0)
|
||||
return 0;
|
||||
|
||||
usec = pa_timeval_diff(&t->timeval, &now);
|
||||
return (int) (usec / 1000);
|
||||
return (int) (usec / 1000); /* in milliseconds */
|
||||
}
|
||||
|
||||
static int dispatch_timeout(pa_mainloop *m) {
|
||||
pa_time_event *e;
|
||||
struct timeval now;
|
||||
pa_usec_t now;
|
||||
int r = 0;
|
||||
pa_assert(m);
|
||||
|
||||
if (m->n_enabled_time_events <= 0)
|
||||
return 0;
|
||||
|
||||
pa_gettimeofday(&now);
|
||||
now = pa_rtclock_now();
|
||||
|
||||
for (e = m->time_events; e && !m->quit; e = e->next) {
|
||||
|
||||
if (e->dead || !e->enabled)
|
||||
continue;
|
||||
|
||||
if (pa_timeval_cmp(&e->timeval, &now) <= 0) {
|
||||
if (e->time <= now) {
|
||||
struct timeval tv;
|
||||
pa_assert(e->callback);
|
||||
|
||||
/* Disable time event */
|
||||
mainloop_time_restart(e, NULL);
|
||||
|
||||
e->callback(&m->api, e, &e->timeval, e->userdata);
|
||||
e->callback(&m->api, e, pa_timeval_rtstore(&tv, e->time, TRUE), e->userdata);
|
||||
|
||||
r++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,14 +320,10 @@ static void request_auto_timing_update(pa_stream *s, pa_bool_t force) {
|
|||
}
|
||||
|
||||
if (s->auto_timing_update_event) {
|
||||
struct timeval next;
|
||||
|
||||
if (force)
|
||||
s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
|
||||
|
||||
pa_gettimeofday(&next);
|
||||
pa_timeval_add(&next, s->auto_timing_interval_usec);
|
||||
s->mainloop->time_restart(s->auto_timing_update_event, &next);
|
||||
pa_context_rttime_restart(s->context, s->auto_timing_update_event, pa_rtclock_now() + s->auto_timing_interval_usec);
|
||||
|
||||
s->auto_timing_interval_usec = PA_MIN(AUTO_TIMING_INTERVAL_END_USEC, s->auto_timing_interval_usec*2);
|
||||
}
|
||||
|
|
@ -801,7 +797,7 @@ static void invalidate_indexes(pa_stream *s, pa_bool_t r, pa_bool_t w) {
|
|||
request_auto_timing_update(s, TRUE);
|
||||
}
|
||||
|
||||
static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) {
|
||||
static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
|
||||
pa_stream *s = userdata;
|
||||
|
||||
pa_assert(s);
|
||||
|
|
@ -823,12 +819,9 @@ static void create_stream_complete(pa_stream *s) {
|
|||
s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata);
|
||||
|
||||
if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
|
||||
struct timeval tv;
|
||||
pa_gettimeofday(&tv);
|
||||
s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
|
||||
pa_timeval_add(&tv, s->auto_timing_interval_usec);
|
||||
pa_assert(!s->auto_timing_update_event);
|
||||
s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s);
|
||||
s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s);
|
||||
|
||||
request_auto_timing_update(s, TRUE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ PA_C_DECL_BEGIN
|
|||
/** The number of nanoseconds in a microsecond */
|
||||
#define PA_NSEC_PER_USEC ((pa_usec_t) 1000ULL)
|
||||
|
||||
/** Invalid time in usec */
|
||||
#define PA_USEC_INVALID ((pa_usec_t) -1)
|
||||
|
||||
struct timeval;
|
||||
|
||||
/** Return the current timestamp, just like UNIX gettimeofday() */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue