/* Called from main context */ static void adjust_rates(struct userdata *u) { size_t buffer, fs; uint32_t old_rate, base_rate, new_rate; pa_usec_t buffer_latency; pa_assert(u); pa_assert_ctl_context(); pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); buffer = u->latency_snapshot.sink_input_buffer + u->latency_snapshot.source_output_buffer; if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter) buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter); else buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter)); buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec); pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms", (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC, (double) buffer_latency / PA_USEC_PER_MSEC, (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC, ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC); pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes", u->latency_snapshot.max_request*2, u->latency_snapshot.min_memblockq_length); fs = pa_frame_size(&u->sink_input->sample_spec); old_rate = u->sink_input->sample_spec.rate; base_rate = u->source_output->sample_spec.rate; if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2) new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time; else new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time; if (new_rate < (uint32_t) (base_rate*0.8) || new_rate > (uint32_t) (base_rate*1.25)) { pa_log_warn("Sample rates too different, not adjusting (%u vs. %u).", base_rate, new_rate); new_rate = base_rate; } else { if (base_rate < new_rate + 20 && new_rate < base_rate + 20) new_rate = base_rate; /* Do the adjustment in small steps; 2‰ can be considered inaudible */ if (new_rate < (uint32_t) (old_rate*0.998) || new_rate > (uint32_t) (old_rate*1.002)) { pa_log_info("New rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", new_rate, old_rate); new_rate = PA_CLAMP(new_rate, (uint32_t) (old_rate*0.998), (uint32_t) (old_rate*1.002)); } } pa_sink_input_set_rate(u->sink_input, new_rate); pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate); pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time); }
static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) { struct userdata *u = userdata; pa_assert(m); pa_assert(t); pa_assert(u); pa_sap_send(&u->sap_context, 0); pa_core_rttime_restart(u->module->core, t, pa_rtclock_now() + SAP_INTERVAL); }
static void timeout_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) { pa_core *c = userdata; pa_assert(c); pa_assert(c->mainloop == m); pa_assert(c->scache_auto_unload_event == e); pa_scache_unload_unused(c); pa_core_rttime_restart(c, e, pa_rtclock_now() + UNLOAD_POLL_TIME); }
static void restart(struct device_info *d) { pa_usec_t now; pa_assert(d); pa_assert(d->sink || d->source); d->last_use = now = pa_rtclock_now(); pa_core_rttime_restart(d->userdata->core, d->time_event, now + d->timeout); if (d->sink) pa_log_debug("Sink %s becomes idle, timeout in %" PRIu64 " seconds.", d->sink->name, d->timeout / PA_USEC_PER_SEC); if (d->source) pa_log_debug("Source %s becomes idle, timeout in %" PRIu64 " seconds.", d->source->name, d->timeout / PA_USEC_PER_SEC); }
/* Called from main context */ static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct timeval *t, void *userdata) { struct userdata *u = userdata; pa_assert(u); pa_assert(a); pa_assert(u->time_event == e); /* Restart timer right away */ pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time); /* Get sink and source latency snapshot */ pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); adjust_rates(u); }
/* Called from main context */ static void adjust_rates(struct userdata *u) { size_t buffer, fs; uint32_t old_rate, base_rate, new_rate; pa_usec_t buffer_latency; pa_assert(u); pa_assert_ctl_context(); pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); buffer = u->latency_snapshot.sink_input_buffer + u->latency_snapshot.source_output_buffer; if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter) buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter); else buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter)); buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec); pa_log_info("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms", (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC, (double) buffer_latency / PA_USEC_PER_MSEC, (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC, ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC); pa_log_info("Should buffer %zu bytes, buffered at minimum %zu bytes", u->latency_snapshot.max_request*2, u->latency_snapshot.min_memblockq_length); fs = pa_frame_size(&u->sink_input->sample_spec); old_rate = u->sink_input->sample_spec.rate; base_rate = u->source_output->sample_spec.rate; if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2) new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time; else new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time; pa_log_info("Old rate %lu Hz, new rate %lu Hz", (unsigned long) old_rate, (unsigned long) new_rate); pa_sink_input_set_rate(u->sink_input, new_rate); pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time); }
static void restart(struct device_info *d) { pa_usec_t now; const char *s; uint32_t timeout; pa_assert(d); pa_assert(d->sink || d->source); d->last_use = now = pa_rtclock_now(); s = pa_proplist_gets(d->sink ? d->sink->proplist : d->source->proplist, "module-suspend-on-idle.timeout"); if (!s || pa_atou(s, &timeout) < 0) timeout = d->userdata->timeout; pa_core_rttime_restart(d->userdata->core, d->time_event, now + timeout * PA_USEC_PER_SEC); if (d->sink) pa_log_debug("Sink %s becomes idle, timeout in %u seconds.", d->sink->name, timeout); if (d->source) pa_log_debug("Source %s becomes idle, timeout in %u seconds.", d->source->name, timeout); }