pa_log_info("Starting playback.");
snd_pcm_start(u->pcm_handle);
- pa_smoother_resume(u->smoother, pa_rtclock_usec());
+ pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE);
}
update_smoother(u);
snd_pcm_uframes_t period_frames, tsched_frames;
size_t frame_size;
pa_bool_t use_mmap = TRUE, b, use_tsched = TRUE, d, ignore_dB = FALSE;
- pa_usec_t usec;
pa_sink_new_data data;
pa_assert(m);
u->rtpoll = pa_rtpoll_new();
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
- u->smoother = pa_smoother_new(DEFAULT_TSCHED_BUFFER_USEC*2, DEFAULT_TSCHED_BUFFER_USEC*2, TRUE, 5);
- usec = pa_rtclock_usec();
- pa_smoother_set_time_offset(u->smoother, usec);
- pa_smoother_pause(u->smoother, usec);
+ u->smoother = pa_smoother_new(
+ DEFAULT_TSCHED_BUFFER_USEC*2,
+ DEFAULT_TSCHED_BUFFER_USEC*2,
+ TRUE,
+ TRUE,
+ 5,
+ pa_rtclock_usec(),
+ TRUE);
if (reserve_init(u, pa_modargs_get_value(
ma, "device_id",
/* FIXME: We need to reload the volume somehow */
snd_pcm_start(u->pcm_handle);
- pa_smoother_resume(u->smoother, pa_rtclock_usec());
+ pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE);
pa_log_info("Resumed successfully...");
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
u->alsa_rtpoll_item = NULL;
- u->smoother = pa_smoother_new(DEFAULT_TSCHED_WATERMARK_USEC*2, DEFAULT_TSCHED_WATERMARK_USEC*2, TRUE, 5);
- pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
+ u->smoother = pa_smoother_new(
+ DEFAULT_TSCHED_WATERMARK_USEC*2,
+ DEFAULT_TSCHED_WATERMARK_USEC*2,
+ TRUE,
+ TRUE,
+ 5,
+ pa_rtclock_usec(),
+ FALSE);
if (reserve_init(u, pa_modargs_get_value(
ma, "device_id",
if (start_stream_fd(u) < 0)
failed = TRUE;
- pa_smoother_resume(u->read_smoother, pa_rtclock_usec());
+ pa_smoother_resume(u->read_smoother, pa_rtclock_usec(), TRUE);
break;
case PA_SOURCE_UNLINKED:
u->core = m->core;
u->service_fd = -1;
u->stream_fd = -1;
- u->read_smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
+ u->read_smoother = pa_smoother_new(
+ PA_USEC_PER_SEC,
+ PA_USEC_PER_SEC*2,
+ TRUE,
+ TRUE,
+ 10,
+ 0,
+ FALSE);
u->sample_spec = m->core->default_sample_spec;
u->modargs = ma;
if (PA_PTR_TO_UINT(data) == PA_SINK_SUSPENDED)
pa_smoother_pause(u->thread_info.smoother, pa_rtclock_usec());
else
- pa_smoother_resume(u->thread_info.smoother, pa_rtclock_usec());
+ pa_smoother_resume(u->thread_info.smoother, pa_rtclock_usec(), TRUE);
break;
pa_atomic_store(&u->thread_info.running, FALSE);
u->thread_info.in_null_mode = FALSE;
u->thread_info.counter = 0;
- u->thread_info.smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
+ u->thread_info.smoother = pa_smoother_new(
+ PA_USEC_PER_SEC,
+ PA_USEC_PER_SEC*2,
+ TRUE,
+ TRUE,
+ 10,
+ 0,
+ FALSE);
if (pa_modargs_get_value_u32(ma, "adjust_time", &u->adjust_time) < 0) {
pa_log("Failed to parse adjust_time value");
case PA_SINK_RUNNING:
if (u->sink->thread_info.state == PA_SINK_SUSPENDED)
- pa_smoother_resume(u->smoother, pa_rtclock_usec());
+ pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE);
break;
u->module = m;
m->userdata = u;
u->fd = -1;
- u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
+ u->smoother = pa_smoother_new(
+ PA_USEC_PER_SEC,
+ PA_USEC_PER_SEC*2,
+ TRUE,
+ TRUE,
+ 10,
+ 0,
+ FALSE);
pa_memchunk_reset(&u->memchunk);
u->offset = 0;
case PA_SINK_RUNNING:
if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
- pa_smoother_resume(u->smoother, pa_rtclock_usec());
+ pa_smoother_resume(u->smoother, pa_rtclock_usec(), TRUE);
/* The connection can be closed when idle, so check to
see if we need to reestablish it */
u->module = m;
m->userdata = u;
u->fd = -1;
- u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
+ u->smoother = pa_smoother_new(
+ PA_USEC_PER_SEC,
+ PA_USEC_PER_SEC*2,
+ TRUE,
+ TRUE,
+ 10,
+ 0,
+ FALSE);
pa_memchunk_reset(&u->raw_memchunk);
pa_memchunk_reset(&u->encoded_memchunk);
u->offset = 0;
if (u->remote_suspended || u->remote_corked)
pa_smoother_pause(u->smoother, x);
else
- pa_smoother_resume(u->smoother, x);
+ pa_smoother_resume(u->smoother, x, TRUE);
}
/* Called from IO thread context */
u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));;
u->source = NULL;
#endif
- u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
+ u->smoother = pa_smoother_new(
+ PA_USEC_PER_SEC,
+ PA_USEC_PER_SEC*2,
+ TRUE,
+ TRUE,
+ 10,
+ pa_rtclock_usec(),
+ FALSE);
u->ctag = 1;
u->device_index = u->channel = PA_INVALID_INDEX;
u->time_event = NULL;
u->fragsize = (uint32_t) -1;
#endif
- pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
-
if (!(u->thread = pa_thread_new(thread_func, u))) {
pa_log("Failed to create thread.");
goto fail;
s->sdp_info = *sdp_info;
s->rtpoll_item = NULL;
s->intended_latency = LATENCY_USEC;
- s->smoother = pa_smoother_new(PA_USEC_PER_SEC*5, PA_USEC_PER_SEC*2, TRUE, 10);
- pa_smoother_set_time_offset(s->smoother, pa_timeval_load(&now));
+ s->smoother = pa_smoother_new(
+ PA_USEC_PER_SEC*5,
+ PA_USEC_PER_SEC*2,
+ TRUE,
+ TRUE,
+ 10,
+ pa_timeval_load(&now),
+ FALSE);
s->last_rate_update = pa_timeval_load(&now);
pa_atomic_store(&s->timestamp, (int) now.tv_sec);
if (s->suspended || s->corked || force_stop)
pa_smoother_pause(s->smoother, x);
else if (force_start || s->buffer_attr.prebuf == 0)
- pa_smoother_resume(s->smoother, x);
+ pa_smoother_resume(s->smoother, x, TRUE);
+
/* Please note that we have no idea if playback actually started
* if prebuf is non-zero! */
if (flags & PA_STREAM_INTERPOLATE_TIMING) {
pa_usec_t x;
- if (s->smoother)
- pa_smoother_free(s->smoother);
-
- s->smoother = pa_smoother_new(SMOOTHER_ADJUST_TIME, SMOOTHER_HISTORY_TIME, !(flags & PA_STREAM_NOT_MONOTONIC), SMOOTHER_MIN_HISTORY);
-
x = pa_rtclock_usec();
- pa_smoother_set_time_offset(s->smoother, x);
- pa_smoother_pause(s->smoother, x);
+
+ pa_assert(!s->smoother);
+ s->smoother = pa_smoother_new(
+ SMOOTHER_ADJUST_TIME,
+ SMOOTHER_HISTORY_TIME,
+ !(flags & PA_STREAM_NOT_MONOTONIC),
+ TRUE,
+ SMOOTHER_MIN_HISTORY,
+ x,
+ TRUE);
}
if (!dev)
pa_smoother_put(o->stream->smoother, u, calc_time(o->stream, TRUE));
if (i->playing)
- pa_smoother_resume(o->stream->smoother, x);
+ pa_smoother_resume(o->stream->smoother, x, TRUE);
}
}
/* Cached parameters for our interpolation polynomial y=ax^3+b^2+cx */
double a, b, c;
- pa_bool_t abc_valid;
+ pa_bool_t abc_valid:1;
pa_bool_t monotonic:1;
pa_bool_t paused:1;
+ pa_bool_t smoothing:1; /* If FALSE we skip the polonyomial interpolation step */
pa_usec_t pause_time;
unsigned min_history;
};
-pa_smoother* pa_smoother_new(pa_usec_t adjust_time, pa_usec_t history_time, pa_bool_t monotonic, unsigned min_history) {
+pa_smoother* pa_smoother_new(
+ pa_usec_t adjust_time,
+ pa_usec_t history_time,
+ pa_bool_t monotonic,
+ pa_bool_t smoothing,
+ unsigned min_history,
+ pa_usec_t time_offset,
+ pa_bool_t paused) {
+
pa_smoother *s;
pa_assert(adjust_time > 0);
s->abc_valid = FALSE;
s->paused = FALSE;
+ s->smoothing = smoothing;
s->min_history = min_history;
+ s->paused = paused;
+ s->time_offset = s->pause_time = time_offset;
+
return s;
}
pa_assert(s);
pa_assert(y);
- if (x >= s->px) {
+ if (!s->smoothing || x >= s->px) {
int64_t t;
/* The requested point is right of the point where we wanted
* we can adjust our position smoothly from this one */
estimate(s, x, &ney, &nde);
s->ex = x; s->ey = ney; s->de = nde;
-
s->ry = y;
}
s->dp = avg_gradient(s, x);
/* And calculate when we want to be on track again */
- s->px = s->ex + s->adjust_time;
- s->py = s->ry + (pa_usec_t) llrint(s->dp * (double) s->adjust_time);
+ if (s->smoothing) {
+ s->px = s->ex + s->adjust_time;
+ s->py = s->ry + (pa_usec_t) llrint(s->dp * (double) s->adjust_time);
+ } else {
+ s->px = s->ex;
+ s->py = s->ry;
+ }
s->abc_valid = FALSE;
s->pause_time = x;
}
-void pa_smoother_resume(pa_smoother *s, pa_usec_t x) {
+void pa_smoother_resume(pa_smoother *s, pa_usec_t x, pa_bool_t fix_now) {
pa_assert(s);
if (!s->paused)
s->paused = FALSE;
s->time_offset += x - s->pause_time;
+
+ if (fix_now)
+ pa_smoother_fix_now(s);
+}
+
+void pa_smoother_fix_now(pa_smoother *s) {
+ pa_assert(s);
+
+ s->px = s->ex;
+ s->py = s->ry;
}
pa_usec_t pa_smoother_translate(pa_smoother *s, pa_usec_t x, pa_usec_t y_delay) {
typedef struct pa_smoother pa_smoother;
-pa_smoother* pa_smoother_new(pa_usec_t x_adjust_time, pa_usec_t x_history_time, pa_bool_t monotonic, unsigned min_history);
+pa_smoother* pa_smoother_new(
+ pa_usec_t x_adjust_time,
+ pa_usec_t x_history_time,
+ pa_bool_t monotonic,
+ pa_bool_t smoothing,
+ unsigned min_history,
+ pa_usec_t x_offset,
+ pa_bool_t paused);
+
void pa_smoother_free(pa_smoother* s);
/* Adds a new value to our dataset. x = local/system time, y = remote time */
void pa_smoother_set_time_offset(pa_smoother *s, pa_usec_t x_offset);
void pa_smoother_pause(pa_smoother *s, pa_usec_t x);
-void pa_smoother_resume(pa_smoother *s, pa_usec_t x);
+void pa_smoother_resume(pa_smoother *s, pa_usec_t x, pa_bool_t abrupt);
void pa_smoother_reset(pa_smoother *s);
+void pa_smoother_fix_now(pa_smoother *s);
+
#endif
srand(0);
+ pa_log_set_level(PA_LOG_DEBUG);
+
for (m = 0, u = 0; u < PA_ELEMENTSOF(msec); u+= 2) {
msec[u] = m+1 + (rand() % 100) - 50;
- msec[u+1] = m + (rand() % 2000) - 1000;
+ msec[u+1] = m + (rand() % 2000) - 1000 + 5000;
m += rand() % 100;
msec[u+1] = 0;
}
- s = pa_smoother_new(700*PA_USEC_PER_MSEC, 2000*PA_USEC_PER_MSEC, TRUE, 6);
+ s = pa_smoother_new(700*PA_USEC_PER_MSEC, 2000*PA_USEC_PER_MSEC, FALSE, TRUE, 6, 0, TRUE);
for (x = 0, u = 0; x < PA_USEC_PER_SEC * 10; x += PA_USEC_PER_MSEC) {
pa_smoother_put(s, (pa_usec_t) msec[u] * PA_USEC_PER_MSEC, (pa_usec_t) msec[u+1] * PA_USEC_PER_MSEC);
printf("%i\t\t%i\n", msec[u], msec[u+1]);
u += 2;
+
+ pa_smoother_resume(s, (pa_usec_t) msec[u] * PA_USEC_PER_MSEC, TRUE);
}
printf("%llu\t%llu\n", (unsigned long long) (x/PA_USEC_PER_MSEC), (unsigned long long) (pa_smoother_get(s, x)/PA_USEC_PER_MSEC));