s->buffer_attr.maxlength = (uint32_t) -1;
if (ss)
s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, ss); /* 250ms of buffering */
- else
- /* XXX: How do we apply worst case conversion here? */
+ else {
+ /* FIXME: We assume a worst-case compressed format corresponding to
+ * 48000 Hz, 2 ch, S16 PCM, but this can very well be incorrect */
+ pa_sample_spec tmp_ss = {
+ .format = PA_SAMPLE_S16NE,
+ .rate = 48000,
+ .channels = 2,
+ };
+ s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, &tmp_ss); /* 250ms of buffering */
+ }
s->buffer_attr.minreq = (uint32_t) -1;
s->buffer_attr.prebuf = (uint32_t) -1;
s->buffer_attr.fragsize = (uint32_t) -1;
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 21, PA_ERR_NOTSUPPORTED);
- /* XXX: For the single-format PCM case, pass ss/map instead of formats */
-
return pa_stream_new_with_proplist_internal(c, name, NULL, NULL, formats, p);
}
}
if (s->auto_timing_update_event) {
- if (force)
- s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
+ if (s->suspended && !force) {
+ pa_assert(s->mainloop);
+ s->mainloop->time_free(s->auto_timing_update_event);
+ s->auto_timing_update_event = NULL;
+ } else {
+ if (force)
+ s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
- pa_context_rttime_restart(s->context, s->auto_timing_update_event, pa_rtclock_now() + s->auto_timing_interval_usec);
+ pa_context_rttime_restart(s->context, s->auto_timing_update_event, pa_rtclock_now() + s->auto_timing_interval_usec);
- s->auto_timing_interval_usec = PA_MIN(AUTO_TIMING_INTERVAL_END_USEC, s->auto_timing_interval_usec*2);
+ s->auto_timing_interval_usec = PA_MIN(AUTO_TIMING_INTERVAL_END_USEC, s->auto_timing_interval_usec*2);
+ }
}
}
* if prebuf is non-zero! */
}
+static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata);
+
void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
pa_context *c = userdata;
pa_stream *s;
s->suspended = suspended;
+ if ((s->flags & PA_STREAM_AUTO_TIMING_UPDATE) && !suspended && !s->auto_timing_update_event) {
+ s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
+ s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s);
+ request_auto_timing_update(s, TRUE);
+ }
+
check_smoother_status(s, TRUE, FALSE, FALSE);
request_auto_timing_update(s, TRUE);
s->suspended = suspended;
+ if ((s->flags & PA_STREAM_AUTO_TIMING_UPDATE) && !suspended && !s->auto_timing_update_event) {
+ s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
+ s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s);
+ request_auto_timing_update(s, TRUE);
+ }
+
check_smoother_status(s, TRUE, FALSE, FALSE);
request_auto_timing_update(s, TRUE);
if (s->state != PA_STREAM_READY)
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);
+ }
+
if (s->event_callback)
s->event_callback(s, event, pl, s->event_userdata);
(!(s->flags & PA_STREAM_FIX_FORMAT) && ss.format != s->sample_spec.format) ||
(!(s->flags & PA_STREAM_FIX_RATE) && ss.rate != s->sample_spec.rate) ||
(!(s->flags & PA_STREAM_FIX_CHANNELS) && !pa_channel_map_equal(&cm, &s->channel_map))))) {
- /* XXX: checks for the n_formats > 0 case? */
pa_context_fail(s->context, PA_ERR_PROTOCOL);
goto finish;
}
if (pa_format_info_valid(f))
s->format = f;
- else
+ else {
pa_format_info_free(f);
+ if (s->n_formats > 0) {
+ /* We used the extended API, so we should have got back a proper format */
+ pa_context_fail(s->context, PA_ERR_PROTOCOL);
+ goto finish;
+ }
+ }
}
if (!pa_tagstruct_eof(t)) {
return &s->channel_map;
}
+const pa_format_info* pa_stream_get_format_info(pa_stream *s) {
+ pa_assert(s);
+ pa_assert(PA_REFCNT_VALUE(s) >= 1);
+
+ /* We don't have the format till routing is done */
+ PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
+ PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
+
+ return s->format;
+}
const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) {
pa_assert(s);
pa_assert(PA_REFCNT_VALUE(s) >= 1);