static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SINK(o)->userdata; switch (code) { case PA_SINK_MESSAGE_SET_STATE: if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING) pa_rtclock_get(&u->timestamp); break; case PA_SINK_MESSAGE_GET_LATENCY: { struct timeval now; pa_rtclock_get(&now); if (pa_timeval_cmp(&u->timestamp, &now) > 0) *((pa_usec_t*) data) = 0; else *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now); break; } } return pa_sink_process_msg(o, code, data, offset, chunk); }
static gboolean check_func(GSource *source) { pa_glib_mainloop *g = (pa_glib_mainloop*) source; pa_io_event *e; g_assert(g); if (g->n_enabled_defer_events) return TRUE; else if (g->n_enabled_time_events) { pa_time_event *t; GTimeVal now; struct timeval tvnow; t = find_next_time_event(g); g_assert(t); g_get_current_time(&now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) return TRUE; } for (e = g->io_events; e; e = e->next) if (!e->dead && e->poll_fd.revents != 0) return TRUE; return FALSE; }
static gboolean prepare_func(GSource *source, gint *timeout) { pa_glib_mainloop *g = (pa_glib_mainloop*) source; g_assert(g); g_assert(timeout); scan_dead(g); if (g->n_enabled_defer_events) { *timeout = 0; return TRUE; } else if (g->n_enabled_time_events) { pa_time_event *t; GTimeVal now; struct timeval tvnow; pa_usec_t usec; t = find_next_time_event(g); g_assert(t); g_get_current_time(&now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { *timeout = 0; return TRUE; } usec = pa_timeval_diff(&t->timeval, &tvnow); *timeout = (gint) (usec / 1000); } else *timeout = -1; return FALSE; }
static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer userdata) { pa_glib_mainloop *g = (pa_glib_mainloop*) source; pa_io_event *e; g_assert(g); if (g->n_enabled_defer_events) { pa_defer_event *d; for (d = g->defer_events; d; d = d->next) { if (d->dead || !d->enabled) continue; break; } g_assert(d); d->callback(&g->api, d, d->userdata); return TRUE; } if (g->n_enabled_time_events) { GTimeVal now; struct timeval tvnow; pa_time_event *t; t = find_next_time_event(g); g_assert(t); g_get_current_time(&now); tvnow.tv_sec = now.tv_sec; tvnow.tv_usec = now.tv_usec; if (pa_timeval_cmp(&t->timeval, &tvnow) <= 0) { /* Disable time event */ glib_time_restart(t, NULL); t->callback(&g->api, t, &t->timeval, t->userdata); return TRUE; } } for (e = g->io_events; e; e = e->next) if (!e->dead && e->poll_fd.revents != 0) { e->callback(&g->api, e, e->poll_fd.fd, map_flags_from_glib(e->poll_fd.revents), e->userdata); e->poll_fd.revents = 0; return TRUE; } return FALSE; }
static void thread_func(void *userdata) { struct userdata *u = userdata; pa_assert(u); pa_log_debug("Thread starting up"); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); pa_rtclock_get(&u->timestamp); for (;;) { int ret; /* Render some data and drop it immediately */ if (u->sink->thread_info.state == PA_SINK_RUNNING) { struct timeval now; pa_rtclock_get(&now); if (pa_timeval_cmp(&u->timestamp, &now) <= 0) { pa_sink_skip(u->sink, u->block_size); pa_timeval_add(&u->timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec)); } pa_rtpoll_set_timer_absolute(u->rtpoll, &u->timestamp); } else pa_rtpoll_set_timer_disabled(u->rtpoll); /* Hmm, nothing to do. Let's sleep */ if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0) goto fail; if (ret == 0) goto finish; } fail: /* If this was no regular exit from the loop we have to continue * processing messages until we received PA_MESSAGE_SHUTDOWN */ pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); finish: pa_log_debug("Thread shutting down"); }
static struct timeval* wallclock_from_rtclock(struct timeval *tv) { struct timeval wc_now, rt_now; pa_assert(tv); pa_gettimeofday(&wc_now); pa_rtclock_get(&rt_now); /* pa_timeval_sub() saturates on underflow! */ if (pa_timeval_cmp(&rt_now, tv) < 0) pa_timeval_add(&wc_now, pa_timeval_diff(tv, &rt_now)); else pa_timeval_sub(&wc_now, pa_timeval_diff(&rt_now, tv)); *tv = wc_now; return tv; }
static void work(void *p) { pa_log_notice("CPU%i: Created thread.", PA_PTR_TO_UINT(p)); pa_make_realtime(12); #ifdef HAVE_PTHREAD_SETAFFINITY_NP { #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) cpuset_t mask; #else cpu_set_t mask; #endif CPU_ZERO(&mask); CPU_SET((size_t) PA_PTR_TO_UINT(p), &mask); pa_assert_se(pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) == 0); } #endif for (;;) { struct timeval now, end; uint64_t usec; pa_log_notice("CPU%i: Sleeping for 1s", PA_PTR_TO_UINT(p)); pa_msleep(1000); usec = (uint64_t) ((((double) rand())*(double)(msec_upper-msec_lower)*PA_USEC_PER_MSEC)/RAND_MAX) + (uint64_t) ((uint64_t) msec_lower*PA_USEC_PER_MSEC); pa_log_notice("CPU%i: Freezing for %ims", PA_PTR_TO_UINT(p), (int) (usec/PA_USEC_PER_MSEC)); pa_rtclock_get(&end); pa_timeval_add(&end, usec); do { pa_rtclock_get(&now); } while (pa_timeval_cmp(&now, &end) < 0); } }
static pa_time_event* glib_time_new( pa_mainloop_api*m, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) { pa_glib_mainloop *g; pa_time_event *e; g_assert(m); g_assert(m->userdata); g_assert(cb); g = m->userdata; e = pa_xnew(pa_time_event, 1); e->mainloop = g; e->dead = 0; if ((e->enabled = !!tv)) { e->timeval = *tv; g->n_enabled_time_events++; if (g->cached_next_time_event) { g_assert(g->cached_next_time_event->enabled); if (pa_timeval_cmp(tv, &g->cached_next_time_event->timeval) < 0) g->cached_next_time_event = e; } } e->callback = cb; e->userdata = userdata; e->destroy_callback = NULL; PA_LLIST_PREPEND(pa_time_event, g->time_events, e); return e; }
static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { g_assert(e); g_assert(!e->dead); if (e->enabled && !tv) { g_assert(e->mainloop->n_enabled_time_events > 0); e->mainloop->n_enabled_time_events--; } else if (!e->enabled && tv) e->mainloop->n_enabled_time_events++; if ((e->enabled = !!tv)) e->timeval = *tv; if (e->mainloop->cached_next_time_event == e) e->mainloop->cached_next_time_event = NULL; if (e->mainloop->cached_next_time_event && e->enabled) { g_assert(e->mainloop->cached_next_time_event->enabled); if (pa_timeval_cmp(tv, &e->mainloop->cached_next_time_event->timeval) < 0) e->mainloop->cached_next_time_event = e; } }
static pa_time_event* find_next_time_event(pa_glib_mainloop *g) { pa_time_event *t, *n = NULL; g_assert(g); if (g->cached_next_time_event) return g->cached_next_time_event; for (t = g->time_events; t; t = t->next) { if (t->dead || !t->enabled) continue; if (!n || pa_timeval_cmp(&t->timeval, &n->timeval) < 0) { n = t; /* Shortcut for tv = { 0, 0 } */ if (n->timeval.tv_sec <= 0) break; } } g->cached_next_time_event = n; return n; }