This patch introduces some extra protocol information, so protocol
version is bumped. This functionality is primarily needed to solve
a long standing issue in alsa-plugins, which should ignore underruns
if and only if it is obsolete, i e, if more data has been written to
the pipe in the meantime (which will automatically end the underrun).
BugLink: http://bugs.launchpad.net/bugs/805940
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
AC_SUBST(PA_API_VERSION, 12)
-AC_SUBST(PA_PROTOCOL_VERSION, 22)
+AC_SUBST(PA_PROTOCOL_VERSION, 23)
# The stable ABI for client applications, for the version info x:y:z
# always will hold y=z
pa_stream_get_state;
pa_stream_get_time;
pa_stream_get_timing_info;
+pa_stream_get_underflow_index;
pa_stream_is_corked;
pa_stream_is_suspended;
pa_stream_new;
/* playback */
pa_memblock *write_memblock;
void *write_data;
+ int64_t latest_underrun_at_index;
/* recording */
pa_memchunk peek_memchunk;
s->timing_info_valid = FALSE;
s->previous_time = 0;
+ s->latest_underrun_at_index = -1;
s->read_index_not_before = 0;
s->write_index_not_before = 0;
pa_context_unref(c);
}
+int64_t pa_stream_get_underflow_index(pa_stream *p)
+{
+ pa_assert(p);
+ return p->latest_underrun_at_index;
+}
+
void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
pa_stream *s;
pa_context *c = userdata;
uint32_t channel;
+ int64_t offset = -1;
pa_assert(pd);
pa_assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW);
pa_context_ref(c);
- if (pa_tagstruct_getu32(t, &channel) < 0 ||
- !pa_tagstruct_eof(t)) {
+ if (pa_tagstruct_getu32(t, &channel) < 0) {
+ pa_context_fail(c, PA_ERR_PROTOCOL);
+ goto finish;
+ }
+
+ if (c->version >= 23 && command == PA_COMMAND_UNDERFLOW) {
+ if (pa_tagstruct_gets64(t, &offset) < 0) {
+ pa_context_fail(c, PA_ERR_PROTOCOL);
+ goto finish;
+ }
+ }
+
+ if (!pa_tagstruct_eof(t)) {
pa_context_fail(c, PA_ERR_PROTOCOL);
goto finish;
}
if (s->state != PA_STREAM_READY)
goto finish;
+ if (offset != -1)
+ s->latest_underrun_at_index = offset;
+
if (s->buffer_attr.prebuf > 0)
check_smoother_status(s, TRUE, FALSE, TRUE);
/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) */
void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
+/** Return at what position the latest underflow occurred, or -1 if this information is not
+ * known (e g if no underflow has occurred, or server is older than 1.0).
+ * Can be used inside the underflow callback to get information about the current underflow.
+ * (Only for playback streams) \since 1.0 */
+int64_t pa_stream_get_underflow_index(pa_stream *p);
+
/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) */
void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW);
pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
pa_tagstruct_putu32(t, s->index);
+ if (s->connection->version >= 23)
+ pa_tagstruct_puts64(t, offset);
pa_pstream_send_tagstruct(s->connection->pstream, t);
break;
}
s->drain_request = FALSE;
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, PA_UINT_TO_PTR(s->drain_tag), 0, NULL, NULL);
} else if (!s->is_underrun)
- pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, 0, NULL, NULL);
+ pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL);
s->is_underrun = TRUE;