const pa_sample_spec *ss,
const pa_channel_map *map,
pa_format_info * const *formats,
+ unsigned int n_formats,
pa_proplist *p) {
pa_stream *s;
- int i;
+ unsigned int i;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
- pa_assert((ss == NULL && map == NULL) || formats == NULL);
+ pa_assert((ss == NULL && map == NULL) || (formats == NULL && n_formats == 0));
+ pa_assert(n_formats < PA_MAX_FORMATS);
PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
PA_CHECK_VALIDITY_RETURN_NULL(c, name || (p && pa_proplist_contains(p, PA_PROP_MEDIA_NAME)), PA_ERR_INVALID);
s->n_formats = 0;
if (formats) {
- for (i = 0; formats[i] && i < PA_MAX_FORMATS; i++) {
- s->n_formats++;
+ s->n_formats = n_formats;
+ for (i = 0; i < n_formats; i++)
s->req_formats[i] = pa_format_info_copy(formats[i]);
- }
- /* Make sure the input array was NULL-terminated */
- pa_assert(formats[i] == NULL);
}
/* We'll get the final negotiated format after connecting */
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;
if (!map)
PA_CHECK_VALIDITY_RETURN_NULL(c, map = pa_channel_map_init_auto(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT), PA_ERR_INVALID);
- return pa_stream_new_with_proplist_internal(c, name, ss, map, NULL, p);
+ return pa_stream_new_with_proplist_internal(c, name, ss, map, NULL, 0, p);
}
pa_stream *pa_stream_new_extended(
pa_context *c,
const char *name,
pa_format_info * const *formats,
+ unsigned int n_formats,
pa_proplist *p) {
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 21, PA_ERR_NOTSUPPORTED);
- return pa_stream_new_with_proplist_internal(c, name, NULL, NULL, formats, p);
+ return pa_stream_new_with_proplist_internal(c, name, NULL, NULL, formats, n_formats, p);
}
static void stream_unlink(pa_stream *s) {
pa_smoother_free(s->smoother);
for (i = 0; i < s->n_formats; i++)
- pa_xfree(s->req_formats[i]);
+ pa_format_info_free(s->req_formats[i]);
+
+ if (s->format)
+ pa_format_info_free(s->format);
pa_xfree(s->device_name);
pa_xfree(s);
goto finish;
if (pa_streq(event, PA_STREAM_EVENT_FORMAT_LOST)) {
- /* Let client know what the running time was when the stream had to be
- * killed */
- pa_usec_t time;
- if (pa_stream_get_time(s, &time) == 0)
- pa_proplist_setf(pl, "stream-time", "%llu", (unsigned long long) time);
+ /* Let client know what the running time was when the stream had to be killed */
+ pa_usec_t stream_time;
+ if (pa_stream_get_time(s, &stream_time) == 0)
+ pa_proplist_setf(pl, "stream-time", "%llu", (unsigned long long) stream_time);
}
if (s->event_callback)
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);
s->timing_info.configured_sink_usec = usec;
}
- if (s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK) {
+ if ((s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK)
+ || s->context->version >= 22) {
+
pa_format_info *f = pa_format_info_new();
pa_tagstruct_get_format_info(t, f);
pa_tagstruct *t;
uint32_t tag;
- pa_bool_t volume_set = FALSE;
+ pa_bool_t volume_set = !!volume;
+ pa_cvolume cv;
uint32_t i;
pa_assert(s);
PA_TAG_BOOLEAN, s->corked,
PA_TAG_INVALID);
- if (s->direction == PA_STREAM_PLAYBACK) {
- pa_cvolume cv;
+ if (!volume) {
+ if (pa_sample_spec_valid(&s->sample_spec))
+ volume = pa_cvolume_reset(&cv, s->sample_spec.channels);
+ else {
+ /* This is not really relevant, since no volume was set, and
+ * the real number of channels is embedded in the format_info
+ * structure */
+ volume = pa_cvolume_reset(&cv, PA_CHANNELS_MAX);
+ }
+ }
+ if (s->direction == PA_STREAM_PLAYBACK) {
pa_tagstruct_put(
t,
PA_TAG_U32, s->buffer_attr.tlength,
PA_TAG_U32, s->syncid,
PA_TAG_INVALID);
- volume_set = !!volume;
-
- if (!volume) {
- if (pa_sample_spec_valid(&s->sample_spec))
- volume = pa_cvolume_reset(&cv, s->sample_spec.channels);
- else {
- /* This is not really relevant, since no volume was set, and
- * the real number of channels is embedded in the format_info
- * structure */
- volume = pa_cvolume_reset(&cv, PA_CHANNELS_MAX);
- }
- }
-
pa_tagstruct_put_cvolume(t, volume);
} else
pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
pa_tagstruct_put_boolean(t, flags & PA_STREAM_FAIL_ON_SUSPEND);
}
- if (s->context->version >= 17) {
+ if (s->context->version >= 17 && s->direction == PA_STREAM_PLAYBACK)
+ pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME);
- if (s->direction == PA_STREAM_PLAYBACK)
- pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME);
+ if (s->context->version >= 18 && s->direction == PA_STREAM_PLAYBACK)
+ pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
- }
+ if ((s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK)
+ || s->context->version >= 22) {
- if (s->context->version >= 18) {
-
- if (s->direction == PA_STREAM_PLAYBACK)
- pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
+ pa_tagstruct_putu8(t, s->n_formats);
+ for (i = 0; i < s->n_formats; i++)
+ pa_tagstruct_put_format_info(t, s->req_formats[i]);
}
- if (s->context->version >= 21) {
-
- if (s->direction == PA_STREAM_PLAYBACK) {
- pa_tagstruct_putu8(t, s->n_formats);
- for (i = 0; i < s->n_formats; i++)
- pa_tagstruct_put_format_info(t, s->req_formats[i]);
- }
+ if (s->context->version >= 22 && s->direction == PA_STREAM_RECORD) {
+ pa_tagstruct_put_cvolume(t, volume);
+ pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED);
+ pa_tagstruct_put_boolean(t, volume_set);
+ pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED));
+ pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME);
+ pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
}
pa_pstream_send_tagstruct(s->context->pstream, t);
pa_pstream_send_tagstruct(s->context->pstream, t);
pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
- /* This might cause the read index to conitnue again, hence
+ /* This might cause the read index to continue again, hence
* let's request a timing update */
request_auto_timing_update(s, TRUE);