* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT)
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
/* Called from thread context */
pa_assert_se(u = s->userdata);
/* Just hand this one over to the master sink */
- pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes + pa_memblockq_get_length(u->memblockq), TRUE, FALSE);
+ pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes + pa_memblockq_get_length(u->memblockq), TRUE, FALSE, FALSE);
}
/* Called from I/O thread context */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT) {
pa_log_debug("Requesting rewind due to state change.");
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
}
pa_sink_assert_ref(s);
pa_assert_se(u = s->userdata);
- pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, TRUE, FALSE);
+ pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, TRUE, FALSE, FALSE);
}
/* Called from I/O thread context */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT) {
pa_log_debug("Requesting rewind due to state change.");
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
}
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT)
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
int pa__init(pa_module*m) {
if (pa_memblockq_is_readable(s->memblockq) &&
s->sink_input->thread_info.underrun_for > 0) {
pa_log_debug("Requesting rewind due to end of underrun");
- pa_sink_input_request_rewind(s->sink_input, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(s->sink_input, 0, FALSE, TRUE, FALSE);
}
return 1;
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT)
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
if (pa_memblockq_is_readable(c->input_memblockq) && c->playback.underrun) {
pa_log_debug("Requesting rewind due to end of underrun.");
- pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE, FALSE);
}
/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
pa_log_debug("Requesting rewind due to end of underrun.");
pa_sink_input_request_rewind(s->sink_input,
(size_t) (s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for),
- FALSE, TRUE);
+ FALSE, TRUE, FALSE);
}
} else {
* let's have it usk us again */
pa_log_debug("Requesting rewind due to rewrite.");
- pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE);
+ pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
}
}
if (pa_memblockq_is_readable(c->input_memblockq) && c->playback.underrun) {
pa_log_debug("Requesting rewind due to end of underrun.");
- pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE, FALSE);
}
/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
i->thread_info.requested_sink_latency = (pa_usec_t) -1;
i->thread_info.rewrite_nbytes = 0;
i->thread_info.rewrite_flush = FALSE;
+ i->thread_info.dont_rewind_render = FALSE;
i->thread_info.underrun_for = (uint64_t) -1;
i->thread_info.playing_for = 0;
i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
lbq = pa_memblockq_get_length(i->thread_info.render_memblockq);
- if (nbytes > 0) {
+ if (nbytes > 0 && !i->thread_info.dont_rewind_render) {
pa_log_debug("Have to rewind %lu bytes on render memblockq.", (unsigned long) nbytes);
pa_memblockq_rewind(i->thread_info.render_memblockq, nbytes);
}
i->thread_info.rewrite_nbytes = 0;
i->thread_info.rewrite_flush = FALSE;
+ i->thread_info.dont_rewind_render = FALSE;
}
/* Called from thread context */
/* This will tell the implementing sink input driver to rewind
* so that the unplayed already mixed data is not lost */
- pa_sink_input_request_rewind(i, 0, TRUE, TRUE);
+ pa_sink_input_request_rewind(i, 0, TRUE, TRUE, FALSE);
} else if (uncorking) {
/* OK, we're being uncorked. Make sure we're not rewound when
* the hw buffer is remixed and request a remix. */
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
}
case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
i->thread_info.volume = *((pa_cvolume*) userdata);
- pa_sink_input_request_rewind(i, 0, TRUE, FALSE);
+ pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
return 0;
case PA_SINK_INPUT_MESSAGE_SET_MUTE:
i->thread_info.muted = PA_PTR_TO_UINT(userdata);
- pa_sink_input_request_rewind(i, 0, TRUE, FALSE);
+ pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
return 0;
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
}
/* Called from IO context */
-void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush) {
+void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush, pa_bool_t dont_rewind_render) {
size_t lbq;
/* If 'rewrite' is TRUE the sink is rewound as far as requested
* If 'rewrite' is FALSE the sink is rewound as far as requested
* and possible and the already rendered data is dropped so that
* in the next iteration we read new data from the
- * implementor. This implies 'flush' is TRUE. */
+ * implementor. This implies 'flush' is TRUE. If
+ * dont_rewind_render is TRUE then the render memblockq is not
+ * rewound. */
pa_sink_input_assert_ref(i);
return;
pa_assert(rewrite || flush);
+ pa_assert(!dont_rewind_render || !rewrite);
/* Calculate how much we can rewind locally without having to
* touch the sink */
i->thread_info.rewrite_flush ||
(flush && i->thread_info.rewrite_nbytes != 0);
+ i->thread_info.dont_rewind_render =
+ i->thread_info.dont_rewind_render ||
+ dont_rewind_render;
+
if (nbytes != (size_t) -1) {
/* Transform to sink domain */
/* We maintain a history of resampled audio data here. */
pa_memblockq *render_memblockq;
+ /* 0: rewrite nothing, (size_t) -1: rewrite everything, otherwise how many bytes to rewrite */
size_t rewrite_nbytes;
- pa_bool_t rewrite_flush;
+ pa_bool_t rewrite_flush, dont_rewind_render;
uint64_t underrun_for, playing_for;
pa_sink_input *sync_prev, *sync_next;
sink driver will call ->rewind() and pass the number of bytes that
could be rewound in the HW device. This functionality is required for
implementing the "zero latency" write-through functionality. */
-void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, pa_bool_t rewrite, pa_bool_t flush);
+void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, pa_bool_t rewrite, pa_bool_t flush, pa_bool_t dont_rewind_render);
void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b);
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT)
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
/* Called from IO thread context */