Branch data Line data Source code
1 : : /***
2 : : This file is part of PulseAudio.
3 : :
4 : : Copyright 2004-2006 Lennart Poettering
5 : : Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 : :
7 : : PulseAudio is free software; you can redistribute it and/or modify
8 : : it under the terms of the GNU Lesser General Public License as published
9 : : by the Free Software Foundation; either version 2.1 of the License,
10 : : or (at your option) any later version.
11 : :
12 : : PulseAudio is distributed in the hope that it will be useful, but
13 : : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : General Public License for more details.
16 : :
17 : : You should have received a copy of the GNU Lesser General Public License
18 : : along with PulseAudio; if not, write to the Free Software
19 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 : : USA.
21 : : ***/
22 : :
23 : : #ifdef HAVE_CONFIG_H
24 : : #include <config.h>
25 : : #endif
26 : :
27 : : #include <string.h>
28 : : #include <stdio.h>
29 : : #include <string.h>
30 : :
31 : : #include <pulse/def.h>
32 : : #include <pulse/timeval.h>
33 : : #include <pulse/rtclock.h>
34 : : #include <pulse/xmalloc.h>
35 : : #include <pulse/fork-detect.h>
36 : :
37 : : #include <pulsecore/pstream-util.h>
38 : : #include <pulsecore/log.h>
39 : : #include <pulsecore/hashmap.h>
40 : : #include <pulsecore/macro.h>
41 : : #include <pulsecore/core-rtclock.h>
42 : : #include <pulsecore/core-util.h>
43 : :
44 : : #include "internal.h"
45 : : #include "stream.h"
46 : :
47 : : #define AUTO_TIMING_INTERVAL_START_USEC (10*PA_USEC_PER_MSEC)
48 : : #define AUTO_TIMING_INTERVAL_END_USEC (1500*PA_USEC_PER_MSEC)
49 : :
50 : : #define SMOOTHER_ADJUST_TIME (1000*PA_USEC_PER_MSEC)
51 : : #define SMOOTHER_HISTORY_TIME (5000*PA_USEC_PER_MSEC)
52 : : #define SMOOTHER_MIN_HISTORY (4)
53 : :
54 : 0 : pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) {
55 : 0 : return pa_stream_new_with_proplist(c, name, ss, map, NULL);
56 : : }
57 : :
58 : : static void reset_callbacks(pa_stream *s) {
59 : 0 : s->read_callback = NULL;
60 : 0 : s->read_userdata = NULL;
61 : 0 : s->write_callback = NULL;
62 : 0 : s->write_userdata = NULL;
63 : 0 : s->state_callback = NULL;
64 : 0 : s->state_userdata = NULL;
65 : 0 : s->overflow_callback = NULL;
66 : 0 : s->overflow_userdata = NULL;
67 : 0 : s->underflow_callback = NULL;
68 : 0 : s->underflow_userdata = NULL;
69 : 0 : s->latency_update_callback = NULL;
70 : 0 : s->latency_update_userdata = NULL;
71 : 0 : s->moved_callback = NULL;
72 : 0 : s->moved_userdata = NULL;
73 : 0 : s->suspended_callback = NULL;
74 : 0 : s->suspended_userdata = NULL;
75 : 0 : s->started_callback = NULL;
76 : 0 : s->started_userdata = NULL;
77 : 0 : s->event_callback = NULL;
78 : 0 : s->event_userdata = NULL;
79 : 0 : s->buffer_attr_callback = NULL;
80 : 0 : s->buffer_attr_userdata = NULL;
81 : : }
82 : :
83 : 0 : static pa_stream *pa_stream_new_with_proplist_internal(
84 : : pa_context *c,
85 : : const char *name,
86 : : const pa_sample_spec *ss,
87 : : const pa_channel_map *map,
88 : : pa_format_info * const *formats,
89 : : unsigned int n_formats,
90 : : pa_proplist *p) {
91 : :
92 : : pa_stream *s;
93 : : unsigned int i;
94 : :
95 [ # # ]: 0 : pa_assert(c);
96 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
97 [ # # ][ # # ]: 0 : pa_assert((ss == NULL && map == NULL) || (formats == NULL && n_formats == 0));
98 [ # # ]: 0 : pa_assert(n_formats < PA_MAX_FORMATS);
99 : :
100 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
101 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, name || (p && pa_proplist_contains(p, PA_PROP_MEDIA_NAME)), PA_ERR_INVALID);
[ # # ]
102 : :
103 : 0 : s = pa_xnew(pa_stream, 1);
104 : 0 : PA_REFCNT_INIT(s);
105 : 0 : s->context = c;
106 : 0 : s->mainloop = c->mainloop;
107 : :
108 : 0 : s->direction = PA_STREAM_NODIRECTION;
109 : 0 : s->state = PA_STREAM_UNCONNECTED;
110 : 0 : s->flags = 0;
111 : :
112 [ # # ]: 0 : if (ss)
113 : 0 : s->sample_spec = *ss;
114 : : else
115 : 0 : pa_sample_spec_init(&s->sample_spec);
116 : :
117 [ # # ]: 0 : if (map)
118 : 0 : s->channel_map = *map;
119 : : else
120 : 0 : pa_channel_map_init(&s->channel_map);
121 : :
122 : 0 : s->n_formats = 0;
123 [ # # ]: 0 : if (formats) {
124 : 0 : s->n_formats = n_formats;
125 [ # # ]: 0 : for (i = 0; i < n_formats; i++)
126 : 0 : s->req_formats[i] = pa_format_info_copy(formats[i]);
127 : : }
128 : :
129 : : /* We'll get the final negotiated format after connecting */
130 : 0 : s->format = NULL;
131 : :
132 : 0 : s->direct_on_input = PA_INVALID_INDEX;
133 : :
134 [ # # ]: 0 : s->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
135 [ # # ]: 0 : if (name)
136 : 0 : pa_proplist_sets(s->proplist, PA_PROP_MEDIA_NAME, name);
137 : :
138 : 0 : s->channel = 0;
139 : 0 : s->channel_valid = FALSE;
140 : 0 : s->syncid = c->csyncid++;
141 : 0 : s->stream_index = PA_INVALID_INDEX;
142 : :
143 : 0 : s->requested_bytes = 0;
144 : 0 : memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
145 : :
146 : : /* We initialize the target length here, so that if the user
147 : : * passes no explicit buffering metrics the default is similar to
148 : : * what older PA versions provided. */
149 : :
150 : 0 : s->buffer_attr.maxlength = (uint32_t) -1;
151 [ # # ]: 0 : if (ss)
152 : 0 : s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, ss); /* 250ms of buffering */
153 : : else {
154 : : /* FIXME: We assume a worst-case compressed format corresponding to
155 : : * 48000 Hz, 2 ch, S16 PCM, but this can very well be incorrect */
156 : 0 : pa_sample_spec tmp_ss = {
157 : : .format = PA_SAMPLE_S16NE,
158 : : .rate = 48000,
159 : : .channels = 2,
160 : : };
161 : 0 : s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, &tmp_ss); /* 250ms of buffering */
162 : : }
163 : 0 : s->buffer_attr.minreq = (uint32_t) -1;
164 : 0 : s->buffer_attr.prebuf = (uint32_t) -1;
165 : 0 : s->buffer_attr.fragsize = (uint32_t) -1;
166 : :
167 : 0 : s->device_index = PA_INVALID_INDEX;
168 : 0 : s->device_name = NULL;
169 : 0 : s->suspended = FALSE;
170 : 0 : s->corked = FALSE;
171 : :
172 : 0 : s->write_memblock = NULL;
173 : 0 : s->write_data = NULL;
174 : :
175 : 0 : pa_memchunk_reset(&s->peek_memchunk);
176 : 0 : s->peek_data = NULL;
177 : 0 : s->record_memblockq = NULL;
178 : :
179 : 0 : memset(&s->timing_info, 0, sizeof(s->timing_info));
180 : 0 : s->timing_info_valid = FALSE;
181 : :
182 : 0 : s->previous_time = 0;
183 : 0 : s->latest_underrun_at_index = -1;
184 : :
185 : 0 : s->read_index_not_before = 0;
186 : 0 : s->write_index_not_before = 0;
187 [ # # ]: 0 : for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++)
188 : 0 : s->write_index_corrections[i].valid = 0;
189 : 0 : s->current_write_index_correction = 0;
190 : :
191 : 0 : s->auto_timing_update_event = NULL;
192 : 0 : s->auto_timing_update_requested = FALSE;
193 : 0 : s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
194 : :
195 : : reset_callbacks(s);
196 : :
197 : 0 : s->smoother = NULL;
198 : :
199 : : /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */
200 [ # # ][ # # ]: 0 : PA_LLIST_PREPEND(pa_stream, c->streams, s);
201 : 0 : pa_stream_ref(s);
202 : :
203 : 0 : return s;
204 : : }
205 : :
206 : 0 : pa_stream *pa_stream_new_with_proplist(
207 : : pa_context *c,
208 : : const char *name,
209 : : const pa_sample_spec *ss,
210 : : const pa_channel_map *map,
211 : : pa_proplist *p) {
212 : :
213 : : pa_channel_map tmap;
214 : :
215 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID);
216 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 12 || (ss->format != PA_SAMPLE_S32LE && ss->format != PA_SAMPLE_S32BE), PA_ERR_NOTSUPPORTED);
217 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 15 || (ss->format != PA_SAMPLE_S24LE && ss->format != PA_SAMPLE_S24BE), PA_ERR_NOTSUPPORTED);
218 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 15 || (ss->format != PA_SAMPLE_S24_32LE && ss->format != PA_SAMPLE_S24_32BE), PA_ERR_NOTSUPPORTED);
219 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID);
[ # # ]
220 : :
221 [ # # ]: 0 : if (!map)
222 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, map = pa_channel_map_init_auto(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT), PA_ERR_INVALID);
223 : :
224 : 0 : return pa_stream_new_with_proplist_internal(c, name, ss, map, NULL, 0, p);
225 : : }
226 : :
227 : 0 : pa_stream *pa_stream_new_extended(
228 : : pa_context *c,
229 : : const char *name,
230 : : pa_format_info * const *formats,
231 : : unsigned int n_formats,
232 : : pa_proplist *p) {
233 : :
234 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 21, PA_ERR_NOTSUPPORTED);
235 : :
236 : 0 : return pa_stream_new_with_proplist_internal(c, name, NULL, NULL, formats, n_formats, p);
237 : : }
238 : :
239 : 0 : static void stream_unlink(pa_stream *s) {
240 : : pa_operation *o, *n;
241 [ # # ]: 0 : pa_assert(s);
242 : :
243 [ # # ]: 0 : if (!s->context)
244 : 0 : return;
245 : :
246 : : /* Detach from context */
247 : :
248 : : /* Unref all operation objects that point to us */
249 [ # # ]: 0 : for (o = s->context->operations; o; o = n) {
250 : 0 : n = o->next;
251 : :
252 [ # # ]: 0 : if (o->stream == s)
253 : 0 : pa_operation_cancel(o);
254 : : }
255 : :
256 : : /* Drop all outstanding replies for this stream */
257 [ # # ]: 0 : if (s->context->pdispatch)
258 : 0 : pa_pdispatch_unregister_reply(s->context->pdispatch, s);
259 : :
260 [ # # ]: 0 : if (s->channel_valid) {
261 [ # # ]: 0 : pa_hashmap_remove((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, PA_UINT32_TO_PTR(s->channel));
262 : 0 : s->channel = 0;
263 : 0 : s->channel_valid = FALSE;
264 : : }
265 : :
266 [ # # ][ # # ]: 0 : PA_LLIST_REMOVE(pa_stream, s->context->streams, s);
[ # # ][ # # ]
267 : 0 : pa_stream_unref(s);
268 : :
269 : 0 : s->context = NULL;
270 : :
271 [ # # ]: 0 : if (s->auto_timing_update_event) {
272 [ # # ]: 0 : pa_assert(s->mainloop);
273 : 0 : s->mainloop->time_free(s->auto_timing_update_event);
274 : : }
275 : :
276 : : reset_callbacks(s);
277 : : }
278 : :
279 : 0 : static void stream_free(pa_stream *s) {
280 : : unsigned int i;
281 : :
282 [ # # ]: 0 : pa_assert(s);
283 : :
284 : 0 : stream_unlink(s);
285 : :
286 [ # # ]: 0 : if (s->write_memblock) {
287 [ # # ]: 0 : if (s->write_data)
288 : 0 : pa_memblock_release(s->write_memblock);
289 : 0 : pa_memblock_unref(s->write_memblock);
290 : : }
291 : :
292 [ # # ]: 0 : if (s->peek_memchunk.memblock) {
293 [ # # ]: 0 : if (s->peek_data)
294 : 0 : pa_memblock_release(s->peek_memchunk.memblock);
295 : 0 : pa_memblock_unref(s->peek_memchunk.memblock);
296 : : }
297 : :
298 [ # # ]: 0 : if (s->record_memblockq)
299 : 0 : pa_memblockq_free(s->record_memblockq);
300 : :
301 [ # # ]: 0 : if (s->proplist)
302 : 0 : pa_proplist_free(s->proplist);
303 : :
304 [ # # ]: 0 : if (s->smoother)
305 : 0 : pa_smoother_free(s->smoother);
306 : :
307 [ # # ]: 0 : for (i = 0; i < s->n_formats; i++)
308 : 0 : pa_format_info_free(s->req_formats[i]);
309 : :
310 [ # # ]: 0 : if (s->format)
311 : 0 : pa_format_info_free(s->format);
312 : :
313 : 0 : pa_xfree(s->device_name);
314 : 0 : pa_xfree(s);
315 : 0 : }
316 : :
317 : 0 : void pa_stream_unref(pa_stream *s) {
318 [ # # ]: 0 : pa_assert(s);
319 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
320 : :
321 [ # # ]: 0 : if (PA_REFCNT_DEC(s) <= 0)
322 : 0 : stream_free(s);
323 : 0 : }
324 : :
325 : 0 : pa_stream* pa_stream_ref(pa_stream *s) {
326 [ # # ]: 0 : pa_assert(s);
327 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
328 : :
329 : 0 : PA_REFCNT_INC(s);
330 : 0 : return s;
331 : : }
332 : :
333 : 0 : pa_stream_state_t pa_stream_get_state(pa_stream *s) {
334 [ # # ]: 0 : pa_assert(s);
335 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
336 : :
337 : 0 : return s->state;
338 : : }
339 : :
340 : 0 : pa_context* pa_stream_get_context(pa_stream *s) {
341 [ # # ]: 0 : pa_assert(s);
342 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
343 : :
344 : 0 : return s->context;
345 : : }
346 : :
347 : 0 : uint32_t pa_stream_get_index(pa_stream *s) {
348 [ # # ]: 0 : pa_assert(s);
349 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
350 : :
351 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
352 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
353 : :
354 : 0 : return s->stream_index;
355 : : }
356 : :
357 : 0 : void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) {
358 [ # # ]: 0 : pa_assert(s);
359 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
360 : :
361 [ # # ]: 0 : if (s->state == st)
362 : 0 : return;
363 : :
364 : 0 : pa_stream_ref(s);
365 : :
366 : 0 : s->state = st;
367 : :
368 [ # # ]: 0 : if (s->state_callback)
369 : 0 : s->state_callback(s, s->state_userdata);
370 : :
371 [ # # ]: 0 : if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED))
372 : 0 : stream_unlink(s);
373 : :
374 : 0 : pa_stream_unref(s);
375 : : }
376 : :
377 : 0 : static void request_auto_timing_update(pa_stream *s, pa_bool_t force) {
378 [ # # ]: 0 : pa_assert(s);
379 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
380 : :
381 [ # # ]: 0 : if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE))
382 : 0 : return;
383 : :
384 [ # # ][ # # ]: 0 : if (s->state == PA_STREAM_READY &&
385 [ # # ]: 0 : (force || !s->auto_timing_update_requested)) {
386 : : pa_operation *o;
387 : :
388 : : /* pa_log("Automatically requesting new timing data"); */
389 : :
390 [ # # ]: 0 : if ((o = pa_stream_update_timing_info(s, NULL, NULL))) {
391 : 0 : pa_operation_unref(o);
392 : 0 : s->auto_timing_update_requested = TRUE;
393 : : }
394 : : }
395 : :
396 [ # # ]: 0 : if (s->auto_timing_update_event) {
397 [ # # ][ # # ]: 0 : if (s->suspended && !force) {
398 [ # # ]: 0 : pa_assert(s->mainloop);
399 : 0 : s->mainloop->time_free(s->auto_timing_update_event);
400 : 0 : s->auto_timing_update_event = NULL;
401 : : } else {
402 [ # # ]: 0 : if (force)
403 : 0 : s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
404 : :
405 : 0 : pa_context_rttime_restart(s->context, s->auto_timing_update_event, pa_rtclock_now() + s->auto_timing_interval_usec);
406 : :
407 : 0 : s->auto_timing_interval_usec = PA_MIN(AUTO_TIMING_INTERVAL_END_USEC, s->auto_timing_interval_usec*2);
408 : : }
409 : : }
410 : : }
411 : :
412 : 0 : void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
413 : 0 : pa_context *c = userdata;
414 : : pa_stream *s;
415 : : uint32_t channel;
416 : :
417 [ # # ]: 0 : pa_assert(pd);
418 [ # # ]: 0 : pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED);
419 [ # # ]: 0 : pa_assert(t);
420 [ # # ]: 0 : pa_assert(c);
421 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
422 : :
423 : 0 : pa_context_ref(c);
424 : :
425 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0 ||
426 : 0 : !pa_tagstruct_eof(t)) {
427 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
428 : 0 : goto finish;
429 : : }
430 : :
431 [ # # ][ # # ]: 0 : if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel))))
432 : : goto finish;
433 : :
434 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
435 : : goto finish;
436 : :
437 : 0 : pa_context_set_error(c, PA_ERR_KILLED);
438 : 0 : pa_stream_set_state(s, PA_STREAM_FAILED);
439 : :
440 : : finish:
441 : 0 : pa_context_unref(c);
442 : 0 : }
443 : :
444 : 0 : static void check_smoother_status(pa_stream *s, pa_bool_t aposteriori, pa_bool_t force_start, pa_bool_t force_stop) {
445 : : pa_usec_t x;
446 : :
447 [ # # ]: 0 : pa_assert(s);
448 [ # # ][ # # ]: 0 : pa_assert(!force_start || !force_stop);
449 : :
450 [ # # ]: 0 : if (!s->smoother)
451 : : return;
452 : :
453 : 0 : x = pa_rtclock_now();
454 : :
455 [ # # ]: 0 : if (s->timing_info_valid) {
456 [ # # ]: 0 : if (aposteriori)
457 : 0 : x -= s->timing_info.transport_usec;
458 : : else
459 : 0 : x += s->timing_info.transport_usec;
460 : : }
461 : :
462 [ # # ][ # # ]: 0 : if (s->suspended || s->corked || force_stop)
[ # # ]
463 : 0 : pa_smoother_pause(s->smoother, x);
464 [ # # ][ # # ]: 0 : else if (force_start || s->buffer_attr.prebuf == 0) {
465 : :
466 [ # # ][ # # ]: 0 : if (!s->timing_info_valid &&
467 [ # # ]: 0 : !aposteriori &&
468 [ # # ]: 0 : !force_start &&
469 [ # # ]: 0 : !force_stop &&
470 : 0 : s->context->version >= 13) {
471 : :
472 : : /* If the server supports STARTED events we take them as
473 : : * indications when audio really starts/stops playing, if
474 : : * we don't have any timing info yet -- instead of trying
475 : : * to be smart and guessing the server time. Otherwise the
476 : : * unknown transport delay adds too much noise to our time
477 : : * calculations. */
478 : :
479 : : return;
480 : : }
481 : :
482 : 0 : pa_smoother_resume(s->smoother, x, TRUE);
483 : : }
484 : :
485 : : /* Please note that we have no idea if playback actually started
486 : : * if prebuf is non-zero! */
487 : : }
488 : :
489 : : static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata);
490 : :
491 : 0 : void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
492 : 0 : pa_context *c = userdata;
493 : : pa_stream *s;
494 : : uint32_t channel;
495 : : const char *dn;
496 : : pa_bool_t suspended;
497 : : uint32_t di;
498 : 0 : pa_usec_t usec = 0;
499 : 0 : uint32_t maxlength = 0, fragsize = 0, minreq = 0, tlength = 0, prebuf = 0;
500 : :
501 [ # # ]: 0 : pa_assert(pd);
502 [ # # ]: 0 : pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_MOVED || command == PA_COMMAND_RECORD_STREAM_MOVED);
503 [ # # ]: 0 : pa_assert(t);
504 [ # # ]: 0 : pa_assert(c);
505 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
506 : :
507 : 0 : pa_context_ref(c);
508 : :
509 [ # # ]: 0 : if (c->version < 12) {
510 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
511 : 0 : goto finish;
512 : : }
513 : :
514 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0 ||
515 [ # # ]: 0 : pa_tagstruct_getu32(t, &di) < 0 ||
516 [ # # ]: 0 : pa_tagstruct_gets(t, &dn) < 0 ||
517 : 0 : pa_tagstruct_get_boolean(t, &suspended) < 0) {
518 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
519 : 0 : goto finish;
520 : : }
521 : :
522 [ # # ]: 0 : if (c->version >= 13) {
523 : :
524 [ # # ]: 0 : if (command == PA_COMMAND_RECORD_STREAM_MOVED) {
525 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
526 [ # # ]: 0 : pa_tagstruct_getu32(t, &fragsize) < 0 ||
527 : 0 : pa_tagstruct_get_usec(t, &usec) < 0) {
528 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
529 : 0 : goto finish;
530 : : }
531 : : } else {
532 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
533 [ # # ]: 0 : pa_tagstruct_getu32(t, &tlength) < 0 ||
534 [ # # ]: 0 : pa_tagstruct_getu32(t, &prebuf) < 0 ||
535 [ # # ]: 0 : pa_tagstruct_getu32(t, &minreq) < 0 ||
536 : 0 : pa_tagstruct_get_usec(t, &usec) < 0) {
537 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
538 : 0 : goto finish;
539 : : }
540 : : }
541 : : }
542 : :
543 [ # # ]: 0 : if (!pa_tagstruct_eof(t)) {
544 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
545 : 0 : goto finish;
546 : : }
547 : :
548 [ # # ][ # # ]: 0 : if (!dn || di == PA_INVALID_INDEX) {
549 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
550 : 0 : goto finish;
551 : : }
552 : :
553 [ # # ][ # # ]: 0 : if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_MOVED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel))))
554 : : goto finish;
555 : :
556 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
557 : : goto finish;
558 : :
559 [ # # ]: 0 : if (c->version >= 13) {
560 [ # # ]: 0 : if (s->direction == PA_STREAM_RECORD)
561 : 0 : s->timing_info.configured_source_usec = usec;
562 : : else
563 : 0 : s->timing_info.configured_sink_usec = usec;
564 : :
565 : 0 : s->buffer_attr.maxlength = maxlength;
566 : 0 : s->buffer_attr.fragsize = fragsize;
567 : 0 : s->buffer_attr.tlength = tlength;
568 : 0 : s->buffer_attr.prebuf = prebuf;
569 : 0 : s->buffer_attr.minreq = minreq;
570 : : }
571 : :
572 : 0 : pa_xfree(s->device_name);
573 : 0 : s->device_name = pa_xstrdup(dn);
574 : 0 : s->device_index = di;
575 : :
576 : 0 : s->suspended = suspended;
577 : :
578 [ # # ][ # # ]: 0 : if ((s->flags & PA_STREAM_AUTO_TIMING_UPDATE) && !suspended && !s->auto_timing_update_event) {
[ # # ]
579 : 0 : s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
580 : 0 : s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s);
581 : 0 : request_auto_timing_update(s, TRUE);
582 : : }
583 : :
584 : 0 : check_smoother_status(s, TRUE, FALSE, FALSE);
585 : 0 : request_auto_timing_update(s, TRUE);
586 : :
587 [ # # ]: 0 : if (s->moved_callback)
588 : 0 : s->moved_callback(s, s->moved_userdata);
589 : :
590 : : finish:
591 : 0 : pa_context_unref(c);
592 : 0 : }
593 : :
594 : 0 : void pa_command_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
595 : 0 : pa_context *c = userdata;
596 : : pa_stream *s;
597 : : uint32_t channel;
598 : 0 : pa_usec_t usec = 0;
599 : 0 : uint32_t maxlength = 0, fragsize = 0, minreq = 0, tlength = 0, prebuf = 0;
600 : :
601 [ # # ]: 0 : pa_assert(pd);
602 [ # # ]: 0 : pa_assert(command == PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED || command == PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED);
603 [ # # ]: 0 : pa_assert(t);
604 [ # # ]: 0 : pa_assert(c);
605 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
606 : :
607 : 0 : pa_context_ref(c);
608 : :
609 [ # # ]: 0 : if (c->version < 15) {
610 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
611 : 0 : goto finish;
612 : : }
613 : :
614 [ # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0) {
615 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
616 : 0 : goto finish;
617 : : }
618 : :
619 [ # # ]: 0 : if (command == PA_COMMAND_RECORD_STREAM_MOVED) {
620 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
621 [ # # ]: 0 : pa_tagstruct_getu32(t, &fragsize) < 0 ||
622 : 0 : pa_tagstruct_get_usec(t, &usec) < 0) {
623 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
624 : 0 : goto finish;
625 : : }
626 : : } else {
627 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
628 [ # # ]: 0 : pa_tagstruct_getu32(t, &tlength) < 0 ||
629 [ # # ]: 0 : pa_tagstruct_getu32(t, &prebuf) < 0 ||
630 [ # # ]: 0 : pa_tagstruct_getu32(t, &minreq) < 0 ||
631 : 0 : pa_tagstruct_get_usec(t, &usec) < 0) {
632 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
633 : 0 : goto finish;
634 : : }
635 : : }
636 : :
637 [ # # ]: 0 : if (!pa_tagstruct_eof(t)) {
638 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
639 : 0 : goto finish;
640 : : }
641 : :
642 [ # # ][ # # ]: 0 : if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel))))
643 : : goto finish;
644 : :
645 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
646 : : goto finish;
647 : :
648 [ # # ]: 0 : if (s->direction == PA_STREAM_RECORD)
649 : 0 : s->timing_info.configured_source_usec = usec;
650 : : else
651 : 0 : s->timing_info.configured_sink_usec = usec;
652 : :
653 : 0 : s->buffer_attr.maxlength = maxlength;
654 : 0 : s->buffer_attr.fragsize = fragsize;
655 : 0 : s->buffer_attr.tlength = tlength;
656 : 0 : s->buffer_attr.prebuf = prebuf;
657 : 0 : s->buffer_attr.minreq = minreq;
658 : :
659 : 0 : request_auto_timing_update(s, TRUE);
660 : :
661 [ # # ]: 0 : if (s->buffer_attr_callback)
662 : 0 : s->buffer_attr_callback(s, s->buffer_attr_userdata);
663 : :
664 : : finish:
665 : 0 : pa_context_unref(c);
666 : 0 : }
667 : :
668 : 0 : void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
669 : 0 : pa_context *c = userdata;
670 : : pa_stream *s;
671 : : uint32_t channel;
672 : : pa_bool_t suspended;
673 : :
674 [ # # ]: 0 : pa_assert(pd);
675 [ # # ]: 0 : pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED || command == PA_COMMAND_RECORD_STREAM_SUSPENDED);
676 [ # # ]: 0 : pa_assert(t);
677 [ # # ]: 0 : pa_assert(c);
678 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
679 : :
680 : 0 : pa_context_ref(c);
681 : :
682 [ # # ]: 0 : if (c->version < 12) {
683 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
684 : 0 : goto finish;
685 : : }
686 : :
687 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0 ||
688 [ # # ]: 0 : pa_tagstruct_get_boolean(t, &suspended) < 0 ||
689 : 0 : !pa_tagstruct_eof(t)) {
690 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
691 : 0 : goto finish;
692 : : }
693 : :
694 [ # # ][ # # ]: 0 : if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel))))
695 : : goto finish;
696 : :
697 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
698 : : goto finish;
699 : :
700 : 0 : s->suspended = suspended;
701 : :
702 [ # # ][ # # ]: 0 : if ((s->flags & PA_STREAM_AUTO_TIMING_UPDATE) && !suspended && !s->auto_timing_update_event) {
[ # # ]
703 : 0 : s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
704 : 0 : s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s);
705 : 0 : request_auto_timing_update(s, TRUE);
706 : : }
707 : :
708 : 0 : check_smoother_status(s, TRUE, FALSE, FALSE);
709 : 0 : request_auto_timing_update(s, TRUE);
710 : :
711 [ # # ]: 0 : if (s->suspended_callback)
712 : 0 : s->suspended_callback(s, s->suspended_userdata);
713 : :
714 : : finish:
715 : 0 : pa_context_unref(c);
716 : 0 : }
717 : :
718 : 0 : void pa_command_stream_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
719 : 0 : pa_context *c = userdata;
720 : : pa_stream *s;
721 : : uint32_t channel;
722 : :
723 [ # # ]: 0 : pa_assert(pd);
724 [ # # ]: 0 : pa_assert(command == PA_COMMAND_STARTED);
725 [ # # ]: 0 : pa_assert(t);
726 [ # # ]: 0 : pa_assert(c);
727 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
728 : :
729 : 0 : pa_context_ref(c);
730 : :
731 [ # # ]: 0 : if (c->version < 13) {
732 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
733 : 0 : goto finish;
734 : : }
735 : :
736 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0 ||
737 : 0 : !pa_tagstruct_eof(t)) {
738 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
739 : 0 : goto finish;
740 : : }
741 : :
742 [ # # ]: 0 : if (!(s = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(channel))))
743 : : goto finish;
744 : :
745 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
746 : : goto finish;
747 : :
748 : 0 : check_smoother_status(s, TRUE, TRUE, FALSE);
749 : 0 : request_auto_timing_update(s, TRUE);
750 : :
751 [ # # ]: 0 : if (s->started_callback)
752 : 0 : s->started_callback(s, s->started_userdata);
753 : :
754 : : finish:
755 : 0 : pa_context_unref(c);
756 : 0 : }
757 : :
758 : 0 : void pa_command_stream_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
759 : 0 : pa_context *c = userdata;
760 : : pa_stream *s;
761 : : uint32_t channel;
762 : 0 : pa_proplist *pl = NULL;
763 : : const char *event;
764 : :
765 [ # # ]: 0 : pa_assert(pd);
766 [ # # ]: 0 : pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_EVENT || command == PA_COMMAND_RECORD_STREAM_EVENT);
767 [ # # ]: 0 : pa_assert(t);
768 [ # # ]: 0 : pa_assert(c);
769 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
770 : :
771 : 0 : pa_context_ref(c);
772 : :
773 [ # # ]: 0 : if (c->version < 15) {
774 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
775 : 0 : goto finish;
776 : : }
777 : :
778 : 0 : pl = pa_proplist_new();
779 : :
780 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0 ||
781 [ # # ]: 0 : pa_tagstruct_gets(t, &event) < 0 ||
782 [ # # ]: 0 : pa_tagstruct_get_proplist(t, pl) < 0 ||
783 [ # # ]: 0 : !pa_tagstruct_eof(t) || !event) {
784 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
785 : 0 : goto finish;
786 : : }
787 : :
788 [ # # ][ # # ]: 0 : if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_EVENT ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel))))
789 : : goto finish;
790 : :
791 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
792 : : goto finish;
793 : :
794 [ # # ]: 0 : if (pa_streq(event, PA_STREAM_EVENT_FORMAT_LOST)) {
795 : : /* Let client know what the running time was when the stream had to be killed */
796 : : pa_usec_t stream_time;
797 [ # # ]: 0 : if (pa_stream_get_time(s, &stream_time) == 0)
798 : 0 : pa_proplist_setf(pl, "stream-time", "%llu", (unsigned long long) stream_time);
799 : : }
800 : :
801 [ # # ]: 0 : if (s->event_callback)
802 : 0 : s->event_callback(s, event, pl, s->event_userdata);
803 : :
804 : : finish:
805 : 0 : pa_context_unref(c);
806 : :
807 [ # # ]: 0 : if (pl)
808 : 0 : pa_proplist_free(pl);
809 : 0 : }
810 : :
811 : 0 : void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
812 : : pa_stream *s;
813 : 0 : pa_context *c = userdata;
814 : : uint32_t bytes, channel;
815 : :
816 [ # # ]: 0 : pa_assert(pd);
817 [ # # ]: 0 : pa_assert(command == PA_COMMAND_REQUEST);
818 [ # # ]: 0 : pa_assert(t);
819 [ # # ]: 0 : pa_assert(c);
820 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
821 : :
822 : 0 : pa_context_ref(c);
823 : :
824 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0 ||
825 [ # # ]: 0 : pa_tagstruct_getu32(t, &bytes) < 0 ||
826 : 0 : !pa_tagstruct_eof(t)) {
827 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
828 : 0 : goto finish;
829 : : }
830 : :
831 [ # # ]: 0 : if (!(s = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(channel))))
832 : : goto finish;
833 : :
834 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
835 : : goto finish;
836 : :
837 : 0 : s->requested_bytes += bytes;
838 : :
839 : : /* pa_log("got request for %lli, now at %lli", (long long) bytes, (long long) s->requested_bytes); */
840 : :
841 [ # # ][ # # ]: 0 : if (s->requested_bytes > 0 && s->write_callback)
842 : 0 : s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata);
843 : :
844 : : finish:
845 : 0 : pa_context_unref(c);
846 : 0 : }
847 : :
848 : 0 : int64_t pa_stream_get_underflow_index(pa_stream *p)
849 : : {
850 [ # # ]: 0 : pa_assert(p);
851 : 0 : return p->latest_underrun_at_index;
852 : : }
853 : :
854 : 0 : void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
855 : : pa_stream *s;
856 : 0 : pa_context *c = userdata;
857 : : uint32_t channel;
858 : 0 : int64_t offset = -1;
859 : :
860 [ # # ]: 0 : pa_assert(pd);
861 [ # # ]: 0 : pa_assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW);
862 [ # # ]: 0 : pa_assert(t);
863 [ # # ]: 0 : pa_assert(c);
864 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(c) >= 1);
865 : :
866 : 0 : pa_context_ref(c);
867 : :
868 [ # # ]: 0 : if (pa_tagstruct_getu32(t, &channel) < 0) {
869 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
870 : 0 : goto finish;
871 : : }
872 : :
873 [ # # ]: 0 : if (c->version >= 23 && command == PA_COMMAND_UNDERFLOW) {
874 [ # # ]: 0 : if (pa_tagstruct_gets64(t, &offset) < 0) {
875 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
876 : 0 : goto finish;
877 : : }
878 : : }
879 : :
880 [ # # ]: 0 : if (!pa_tagstruct_eof(t)) {
881 : 0 : pa_context_fail(c, PA_ERR_PROTOCOL);
882 : 0 : goto finish;
883 : : }
884 : :
885 [ # # ]: 0 : if (!(s = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(channel))))
886 : : goto finish;
887 : :
888 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
889 : : goto finish;
890 : :
891 [ # # ]: 0 : if (offset != -1)
892 : 0 : s->latest_underrun_at_index = offset;
893 : :
894 [ # # ]: 0 : if (s->buffer_attr.prebuf > 0)
895 : 0 : check_smoother_status(s, TRUE, FALSE, TRUE);
896 : :
897 : 0 : request_auto_timing_update(s, TRUE);
898 : :
899 [ # # ]: 0 : if (command == PA_COMMAND_OVERFLOW) {
900 [ # # ]: 0 : if (s->overflow_callback)
901 : 0 : s->overflow_callback(s, s->overflow_userdata);
902 [ # # ]: 0 : } else if (command == PA_COMMAND_UNDERFLOW) {
903 [ # # ]: 0 : if (s->underflow_callback)
904 : 0 : s->underflow_callback(s, s->underflow_userdata);
905 : : }
906 : :
907 : : finish:
908 : 0 : pa_context_unref(c);
909 : 0 : }
910 : :
911 : 0 : static void invalidate_indexes(pa_stream *s, pa_bool_t r, pa_bool_t w) {
912 [ # # ]: 0 : pa_assert(s);
913 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
914 : :
915 : : /* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */
916 : :
917 [ # # ]: 0 : if (s->state != PA_STREAM_READY)
918 : 0 : return;
919 : :
920 [ # # ]: 0 : if (w) {
921 : 0 : s->write_index_not_before = s->context->ctag;
922 : :
923 [ # # ]: 0 : if (s->timing_info_valid)
924 : 0 : s->timing_info.write_index_corrupt = TRUE;
925 : :
926 : : /* pa_log("write_index invalidated"); */
927 : : }
928 : :
929 [ # # ]: 0 : if (r) {
930 : 0 : s->read_index_not_before = s->context->ctag;
931 : :
932 [ # # ]: 0 : if (s->timing_info_valid)
933 : 0 : s->timing_info.read_index_corrupt = TRUE;
934 : :
935 : : /* pa_log("read_index invalidated"); */
936 : : }
937 : :
938 : 0 : request_auto_timing_update(s, TRUE);
939 : : }
940 : :
941 : 0 : static void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
942 : 0 : pa_stream *s = userdata;
943 : :
944 [ # # ]: 0 : pa_assert(s);
945 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
946 : :
947 : 0 : pa_stream_ref(s);
948 : 0 : request_auto_timing_update(s, FALSE);
949 : 0 : pa_stream_unref(s);
950 : 0 : }
951 : :
952 : 0 : static void create_stream_complete(pa_stream *s) {
953 [ # # ]: 0 : pa_assert(s);
954 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
955 [ # # ]: 0 : pa_assert(s->state == PA_STREAM_CREATING);
956 : :
957 : 0 : pa_stream_set_state(s, PA_STREAM_READY);
958 : :
959 [ # # ][ # # ]: 0 : if (s->requested_bytes > 0 && s->write_callback)
960 : 0 : s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata);
961 : :
962 [ # # ]: 0 : if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) {
963 : 0 : s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC;
964 [ # # ]: 0 : pa_assert(!s->auto_timing_update_event);
965 : 0 : s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s);
966 : :
967 : 0 : request_auto_timing_update(s, TRUE);
968 : : }
969 : :
970 : 0 : check_smoother_status(s, TRUE, FALSE, FALSE);
971 : 0 : }
972 : :
973 : 0 : static void patch_buffer_attr(pa_stream *s, pa_buffer_attr *attr, pa_stream_flags_t *flags) {
974 : : const char *e;
975 : :
976 [ # # ]: 0 : pa_assert(s);
977 [ # # ]: 0 : pa_assert(attr);
978 : :
979 [ # # ]: 0 : if ((e = getenv("PULSE_LATENCY_MSEC"))) {
980 : : uint32_t ms;
981 : :
982 [ # # ][ # # ]: 0 : if (pa_atou(e, &ms) < 0 || ms <= 0)
983 : 0 : pa_log_debug("Failed to parse $PULSE_LATENCY_MSEC: %s", e);
984 : : else {
985 : 0 : attr->maxlength = (uint32_t) -1;
986 : 0 : attr->tlength = pa_usec_to_bytes(ms * PA_USEC_PER_MSEC, &s->sample_spec);
987 : 0 : attr->minreq = (uint32_t) -1;
988 : 0 : attr->prebuf = (uint32_t) -1;
989 : 0 : attr->fragsize = attr->tlength;
990 : : }
991 : :
992 [ # # ]: 0 : if (flags)
993 : 0 : *flags |= PA_STREAM_ADJUST_LATENCY;
994 : : }
995 : :
996 [ # # ]: 0 : if (s->context->version >= 13)
997 : 0 : return;
998 : :
999 : : /* Version older than 0.9.10 didn't do server side buffer_attr
1000 : : * selection, hence we have to fake it on the client side. */
1001 : :
1002 : : /* We choose fairly conservative values here, to not confuse
1003 : : * old clients with extremely large playback buffers */
1004 : :
1005 [ # # ]: 0 : if (attr->maxlength == (uint32_t) -1)
1006 : 0 : attr->maxlength = 4*1024*1024; /* 4MB is the maximum queue length PulseAudio <= 0.9.9 supported. */
1007 : :
1008 [ # # ]: 0 : if (attr->tlength == (uint32_t) -1)
1009 : 0 : attr->tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, &s->sample_spec); /* 250ms of buffering */
1010 : :
1011 [ # # ]: 0 : if (attr->minreq == (uint32_t) -1)
1012 : 0 : attr->minreq = (attr->tlength)/5; /* Ask for more data when there are only 200ms left in the playback buffer */
1013 : :
1014 [ # # ]: 0 : if (attr->prebuf == (uint32_t) -1)
1015 : 0 : attr->prebuf = attr->tlength; /* Start to play only when the playback is fully filled up once */
1016 : :
1017 [ # # ]: 0 : if (attr->fragsize == (uint32_t) -1)
1018 : 0 : attr->fragsize = attr->tlength; /* Pass data to the app only when the buffer is filled up once */
1019 : : }
1020 : :
1021 : 0 : void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1022 : 0 : pa_stream *s = userdata;
1023 : 0 : uint32_t requested_bytes = 0;
1024 : :
1025 [ # # ]: 0 : pa_assert(pd);
1026 [ # # ]: 0 : pa_assert(s);
1027 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1028 [ # # ]: 0 : pa_assert(s->state == PA_STREAM_CREATING);
1029 : :
1030 : 0 : pa_stream_ref(s);
1031 : :
1032 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
1033 [ # # ]: 0 : if (pa_context_handle_error(s->context, command, t, FALSE) < 0)
1034 : : goto finish;
1035 : :
1036 : 0 : pa_stream_set_state(s, PA_STREAM_FAILED);
1037 : 0 : goto finish;
1038 : : }
1039 : :
1040 [ # # ][ # # ]: 0 : if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
1041 [ # # ]: 0 : s->channel == PA_INVALID_INDEX ||
1042 [ # # ][ # # ]: 0 : ((s->direction != PA_STREAM_UPLOAD) && (pa_tagstruct_getu32(t, &s->stream_index) < 0 || s->stream_index == PA_INVALID_INDEX)) ||
[ # # ]
1043 [ # # ]: 0 : ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &requested_bytes) < 0)) {
1044 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1045 : 0 : goto finish;
1046 : : }
1047 : :
1048 : 0 : s->requested_bytes = (int64_t) requested_bytes;
1049 : :
1050 [ # # ]: 0 : if (s->context->version >= 9) {
1051 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK) {
1052 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 ||
1053 [ # # ]: 0 : pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 ||
1054 [ # # ]: 0 : pa_tagstruct_getu32(t, &s->buffer_attr.prebuf) < 0 ||
1055 : 0 : pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0) {
1056 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1057 : 0 : goto finish;
1058 : : }
1059 [ # # ]: 0 : } else if (s->direction == PA_STREAM_RECORD) {
1060 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 ||
1061 : 0 : pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0) {
1062 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1063 : 0 : goto finish;
1064 : : }
1065 : : }
1066 : : }
1067 : :
1068 [ # # ][ # # ]: 0 : if (s->context->version >= 12 && s->direction != PA_STREAM_UPLOAD) {
1069 : : pa_sample_spec ss;
1070 : : pa_channel_map cm;
1071 : 0 : const char *dn = NULL;
1072 : : pa_bool_t suspended;
1073 : :
1074 [ # # # # ]: 0 : if (pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
1075 [ # # ]: 0 : pa_tagstruct_get_channel_map(t, &cm) < 0 ||
1076 [ # # ]: 0 : pa_tagstruct_getu32(t, &s->device_index) < 0 ||
1077 [ # # ]: 0 : pa_tagstruct_gets(t, &dn) < 0 ||
1078 : 0 : pa_tagstruct_get_boolean(t, &suspended) < 0) {
1079 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1080 : 0 : goto finish;
1081 : : }
1082 : :
1083 [ # # ][ # # ]: 0 : if (!dn || s->device_index == PA_INVALID_INDEX ||
[ # # ]
1084 [ # # ]: 0 : ss.channels != cm.channels ||
1085 [ # # ]: 0 : !pa_channel_map_valid(&cm) ||
1086 [ # # ]: 0 : !pa_sample_spec_valid(&ss) ||
1087 [ # # ]: 0 : (s->n_formats == 0 && (
1088 [ # # ][ # # ]: 0 : (!(s->flags & PA_STREAM_FIX_FORMAT) && ss.format != s->sample_spec.format) ||
1089 [ # # ][ # # ]: 0 : (!(s->flags & PA_STREAM_FIX_RATE) && ss.rate != s->sample_spec.rate) ||
1090 [ # # ]: 0 : (!(s->flags & PA_STREAM_FIX_CHANNELS) && !pa_channel_map_equal(&cm, &s->channel_map))))) {
1091 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1092 : 0 : goto finish;
1093 : : }
1094 : :
1095 : 0 : pa_xfree(s->device_name);
1096 : 0 : s->device_name = pa_xstrdup(dn);
1097 : 0 : s->suspended = suspended;
1098 : :
1099 : 0 : s->channel_map = cm;
1100 : 0 : s->sample_spec = ss;
1101 : : }
1102 : :
1103 [ # # ][ # # ]: 0 : if (s->context->version >= 13 && s->direction != PA_STREAM_UPLOAD) {
1104 : : pa_usec_t usec;
1105 : :
1106 [ # # ]: 0 : if (pa_tagstruct_get_usec(t, &usec) < 0) {
1107 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1108 : 0 : goto finish;
1109 : : }
1110 : :
1111 [ # # ]: 0 : if (s->direction == PA_STREAM_RECORD)
1112 : 0 : s->timing_info.configured_source_usec = usec;
1113 : : else
1114 : 0 : s->timing_info.configured_sink_usec = usec;
1115 : : }
1116 : :
1117 [ # # ][ # # ]: 0 : if ((s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK)
1118 [ # # ]: 0 : || s->context->version >= 22) {
1119 : :
1120 : 0 : pa_format_info *f = pa_format_info_new();
1121 : 0 : pa_tagstruct_get_format_info(t, f);
1122 : :
1123 [ # # ]: 0 : if (pa_format_info_valid(f))
1124 : 0 : s->format = f;
1125 : : else {
1126 : 0 : pa_format_info_free(f);
1127 [ # # ]: 0 : if (s->n_formats > 0) {
1128 : : /* We used the extended API, so we should have got back a proper format */
1129 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1130 : 0 : goto finish;
1131 : : }
1132 : : }
1133 : : }
1134 : :
1135 [ # # ]: 0 : if (!pa_tagstruct_eof(t)) {
1136 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
1137 : 0 : goto finish;
1138 : : }
1139 : :
1140 [ # # ]: 0 : if (s->direction == PA_STREAM_RECORD) {
1141 [ # # ]: 0 : pa_assert(!s->record_memblockq);
1142 : :
1143 : 0 : s->record_memblockq = pa_memblockq_new(
1144 : : "client side record memblockq",
1145 : : 0,
1146 : 0 : s->buffer_attr.maxlength,
1147 : : 0,
1148 : 0 : &s->sample_spec,
1149 : : 1,
1150 : : 0,
1151 : : 0,
1152 : : NULL);
1153 : : }
1154 : :
1155 : 0 : s->channel_valid = TRUE;
1156 [ # # ]: 0 : pa_hashmap_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, PA_UINT32_TO_PTR(s->channel), s);
1157 : :
1158 : 0 : create_stream_complete(s);
1159 : :
1160 : : finish:
1161 : 0 : pa_stream_unref(s);
1162 : 0 : }
1163 : :
1164 : 0 : static int create_stream(
1165 : : pa_stream_direction_t direction,
1166 : : pa_stream *s,
1167 : : const char *dev,
1168 : : const pa_buffer_attr *attr,
1169 : : pa_stream_flags_t flags,
1170 : : const pa_cvolume *volume,
1171 : : pa_stream *sync_stream) {
1172 : :
1173 : : pa_tagstruct *t;
1174 : : uint32_t tag;
1175 : 0 : pa_bool_t volume_set = !!volume;
1176 : : pa_cvolume cv;
1177 : : uint32_t i;
1178 : :
1179 [ # # ]: 0 : pa_assert(s);
1180 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1181 [ # # ]: 0 : pa_assert(direction == PA_STREAM_PLAYBACK || direction == PA_STREAM_RECORD);
1182 : :
1183 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1184 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
1185 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direct_on_input == PA_INVALID_INDEX || direction == PA_STREAM_RECORD, PA_ERR_BADSTATE);
1186 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED|
1187 : : PA_STREAM_INTERPOLATE_TIMING|
1188 : : PA_STREAM_NOT_MONOTONIC|
1189 : : PA_STREAM_AUTO_TIMING_UPDATE|
1190 : : PA_STREAM_NO_REMAP_CHANNELS|
1191 : : PA_STREAM_NO_REMIX_CHANNELS|
1192 : : PA_STREAM_FIX_FORMAT|
1193 : : PA_STREAM_FIX_RATE|
1194 : : PA_STREAM_FIX_CHANNELS|
1195 : : PA_STREAM_DONT_MOVE|
1196 : : PA_STREAM_VARIABLE_RATE|
1197 : : PA_STREAM_PEAK_DETECT|
1198 : : PA_STREAM_START_MUTED|
1199 : : PA_STREAM_ADJUST_LATENCY|
1200 : : PA_STREAM_EARLY_REQUESTS|
1201 : : PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND|
1202 : : PA_STREAM_START_UNMUTED|
1203 : : PA_STREAM_FAIL_ON_SUSPEND|
1204 : : PA_STREAM_RELATIVE_VOLUME|
1205 : : PA_STREAM_PASSTHROUGH)), PA_ERR_INVALID);
1206 : :
1207 : :
1208 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED);
1209 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->context->version >= 13 || !(flags & PA_STREAM_PEAK_DETECT), PA_ERR_NOTSUPPORTED);
1210 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
1211 : : /* Although some of the other flags are not supported on older
1212 : : * version, we don't check for them here, because it doesn't hurt
1213 : : * when they are passed but actually not supported. This makes
1214 : : * client development easier */
1215 : :
1216 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_PLAYBACK || !(flags & (PA_STREAM_START_MUTED)), PA_ERR_INVALID);
1217 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_RECORD || !(flags & (PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID);
1218 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !volume || s->n_formats || (pa_sample_spec_valid(&s->sample_spec) && volume->channels == s->sample_spec.channels), PA_ERR_INVALID);
[ # # ][ # # ]
1219 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID);
[ # # ]
1220 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, (flags & (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS)) != (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS), PA_ERR_INVALID);
1221 : :
1222 : 0 : pa_stream_ref(s);
1223 : :
1224 : 0 : s->direction = direction;
1225 : :
1226 [ # # ]: 0 : if (sync_stream)
1227 : 0 : s->syncid = sync_stream->syncid;
1228 : :
1229 [ # # ]: 0 : if (attr)
1230 : 0 : s->buffer_attr = *attr;
1231 : 0 : patch_buffer_attr(s, &s->buffer_attr, &flags);
1232 : :
1233 : 0 : s->flags = flags;
1234 : 0 : s->corked = !!(flags & PA_STREAM_START_CORKED);
1235 : :
1236 [ # # ]: 0 : if (flags & PA_STREAM_INTERPOLATE_TIMING) {
1237 : : pa_usec_t x;
1238 : :
1239 : 0 : x = pa_rtclock_now();
1240 : :
1241 [ # # ]: 0 : pa_assert(!s->smoother);
1242 : 0 : s->smoother = pa_smoother_new(
1243 : : SMOOTHER_ADJUST_TIME,
1244 : : SMOOTHER_HISTORY_TIME,
1245 : 0 : !(flags & PA_STREAM_NOT_MONOTONIC),
1246 : : TRUE,
1247 : : SMOOTHER_MIN_HISTORY,
1248 : : x,
1249 : : TRUE);
1250 : : }
1251 : :
1252 [ # # ]: 0 : if (!dev)
1253 [ # # ]: 0 : dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source;
1254 : :
1255 [ # # ]: 0 : t = pa_tagstruct_command(
1256 : : s->context,
1257 : 0 : (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM),
1258 : : &tag);
1259 : :
1260 [ # # ]: 0 : if (s->context->version < 13)
1261 : 0 : pa_tagstruct_puts(t, pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME));
1262 : :
1263 : 0 : pa_tagstruct_put(
1264 : : t,
1265 : : PA_TAG_SAMPLE_SPEC, &s->sample_spec,
1266 : : PA_TAG_CHANNEL_MAP, &s->channel_map,
1267 : : PA_TAG_U32, PA_INVALID_INDEX,
1268 : : PA_TAG_STRING, dev,
1269 : : PA_TAG_U32, s->buffer_attr.maxlength,
1270 : 0 : PA_TAG_BOOLEAN, s->corked,
1271 : : PA_TAG_INVALID);
1272 : :
1273 [ # # ]: 0 : if (!volume) {
1274 [ # # ]: 0 : if (pa_sample_spec_valid(&s->sample_spec))
1275 : 0 : volume = pa_cvolume_reset(&cv, s->sample_spec.channels);
1276 : : else {
1277 : : /* This is not really relevant, since no volume was set, and
1278 : : * the real number of channels is embedded in the format_info
1279 : : * structure */
1280 : 0 : volume = pa_cvolume_reset(&cv, PA_CHANNELS_MAX);
1281 : : }
1282 : : }
1283 : :
1284 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK) {
1285 : 0 : pa_tagstruct_put(
1286 : : t,
1287 : : PA_TAG_U32, s->buffer_attr.tlength,
1288 : : PA_TAG_U32, s->buffer_attr.prebuf,
1289 : : PA_TAG_U32, s->buffer_attr.minreq,
1290 : : PA_TAG_U32, s->syncid,
1291 : : PA_TAG_INVALID);
1292 : :
1293 : 0 : pa_tagstruct_put_cvolume(t, volume);
1294 : : } else
1295 : 0 : pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
1296 : :
1297 [ # # ]: 0 : if (s->context->version >= 12) {
1298 : 0 : pa_tagstruct_put(
1299 : : t,
1300 : : PA_TAG_BOOLEAN, flags & PA_STREAM_NO_REMAP_CHANNELS,
1301 : : PA_TAG_BOOLEAN, flags & PA_STREAM_NO_REMIX_CHANNELS,
1302 : : PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_FORMAT,
1303 : : PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_RATE,
1304 : : PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_CHANNELS,
1305 : : PA_TAG_BOOLEAN, flags & PA_STREAM_DONT_MOVE,
1306 : : PA_TAG_BOOLEAN, flags & PA_STREAM_VARIABLE_RATE,
1307 : : PA_TAG_INVALID);
1308 : : }
1309 : :
1310 [ # # ]: 0 : if (s->context->version >= 13) {
1311 : :
1312 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK)
1313 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED);
1314 : : else
1315 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_PEAK_DETECT);
1316 : :
1317 : 0 : pa_tagstruct_put(
1318 : : t,
1319 : : PA_TAG_BOOLEAN, flags & PA_STREAM_ADJUST_LATENCY,
1320 : : PA_TAG_PROPLIST, s->proplist,
1321 : : PA_TAG_INVALID);
1322 : :
1323 [ # # ]: 0 : if (s->direction == PA_STREAM_RECORD)
1324 : 0 : pa_tagstruct_putu32(t, s->direct_on_input);
1325 : : }
1326 : :
1327 [ # # ]: 0 : if (s->context->version >= 14) {
1328 : :
1329 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK)
1330 : 0 : pa_tagstruct_put_boolean(t, volume_set);
1331 : :
1332 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_EARLY_REQUESTS);
1333 : : }
1334 : :
1335 [ # # ]: 0 : if (s->context->version >= 15) {
1336 : :
1337 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK)
1338 : 0 : pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED));
1339 : :
1340 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND);
1341 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_FAIL_ON_SUSPEND);
1342 : : }
1343 : :
1344 [ # # ][ # # ]: 0 : if (s->context->version >= 17 && s->direction == PA_STREAM_PLAYBACK)
1345 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME);
1346 : :
1347 [ # # ][ # # ]: 0 : if (s->context->version >= 18 && s->direction == PA_STREAM_PLAYBACK)
1348 : 0 : pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
1349 : :
1350 [ # # ][ # # ]: 0 : if ((s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK)
1351 [ # # ]: 0 : || s->context->version >= 22) {
1352 : :
1353 : 0 : pa_tagstruct_putu8(t, s->n_formats);
1354 [ # # ]: 0 : for (i = 0; i < s->n_formats; i++)
1355 : 0 : pa_tagstruct_put_format_info(t, s->req_formats[i]);
1356 : : }
1357 : :
1358 [ # # ][ # # ]: 0 : if (s->context->version >= 22 && s->direction == PA_STREAM_RECORD) {
1359 : 0 : pa_tagstruct_put_cvolume(t, volume);
1360 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED);
1361 : 0 : pa_tagstruct_put_boolean(t, volume_set);
1362 : 0 : pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED));
1363 : 0 : pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME);
1364 : 0 : pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH));
1365 : : }
1366 : :
1367 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
1368 : 0 : pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL);
1369 : :
1370 : 0 : pa_stream_set_state(s, PA_STREAM_CREATING);
1371 : :
1372 : 0 : pa_stream_unref(s);
1373 : 0 : return 0;
1374 : : }
1375 : :
1376 : 0 : int pa_stream_connect_playback(
1377 : : pa_stream *s,
1378 : : const char *dev,
1379 : : const pa_buffer_attr *attr,
1380 : : pa_stream_flags_t flags,
1381 : : const pa_cvolume *volume,
1382 : : pa_stream *sync_stream) {
1383 : :
1384 [ # # ]: 0 : pa_assert(s);
1385 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1386 : :
1387 : 0 : return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream);
1388 : : }
1389 : :
1390 : 0 : int pa_stream_connect_record(
1391 : : pa_stream *s,
1392 : : const char *dev,
1393 : : const pa_buffer_attr *attr,
1394 : : pa_stream_flags_t flags) {
1395 : :
1396 [ # # ]: 0 : pa_assert(s);
1397 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1398 : :
1399 : 0 : return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL);
1400 : : }
1401 : :
1402 : 0 : int pa_stream_begin_write(
1403 : : pa_stream *s,
1404 : : void **data,
1405 : : size_t *nbytes) {
1406 : :
1407 [ # # ]: 0 : pa_assert(s);
1408 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1409 : :
1410 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1411 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
1412 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
1413 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, data, PA_ERR_INVALID);
1414 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, nbytes && *nbytes != 0, PA_ERR_INVALID);
1415 : :
1416 [ # # ]: 0 : if (*nbytes != (size_t) -1) {
1417 : : size_t m, fs;
1418 : :
1419 : 0 : m = pa_mempool_block_size_max(s->context->mempool);
1420 : 0 : fs = pa_frame_size(&s->sample_spec);
1421 : :
1422 : 0 : m = (m / fs) * fs;
1423 [ # # ]: 0 : if (*nbytes > m)
1424 : 0 : *nbytes = m;
1425 : : }
1426 : :
1427 [ # # ]: 0 : if (!s->write_memblock) {
1428 : 0 : s->write_memblock = pa_memblock_new(s->context->mempool, *nbytes);
1429 : 0 : s->write_data = pa_memblock_acquire(s->write_memblock);
1430 : : }
1431 : :
1432 : 0 : *data = s->write_data;
1433 : 0 : *nbytes = pa_memblock_get_length(s->write_memblock);
1434 : :
1435 : 0 : return 0;
1436 : : }
1437 : :
1438 : 0 : int pa_stream_cancel_write(
1439 : : pa_stream *s) {
1440 : :
1441 [ # # ]: 0 : pa_assert(s);
1442 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1443 : :
1444 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1445 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
1446 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
1447 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->write_memblock, PA_ERR_BADSTATE);
1448 : :
1449 [ # # ]: 0 : pa_assert(s->write_data);
1450 : :
1451 : 0 : pa_memblock_release(s->write_memblock);
1452 : 0 : pa_memblock_unref(s->write_memblock);
1453 : 0 : s->write_memblock = NULL;
1454 : 0 : s->write_data = NULL;
1455 : :
1456 : 0 : return 0;
1457 : : }
1458 : :
1459 : 0 : int pa_stream_write(
1460 : : pa_stream *s,
1461 : : const void *data,
1462 : : size_t length,
1463 : : pa_free_cb_t free_cb,
1464 : : int64_t offset,
1465 : : pa_seek_mode_t seek) {
1466 : :
1467 [ # # ]: 0 : pa_assert(s);
1468 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1469 [ # # ]: 0 : pa_assert(data);
1470 : :
1471 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1472 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
1473 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
1474 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID);
1475 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID);
1476 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context,
[ # # ]
1477 : : !s->write_memblock ||
1478 : : ((data >= s->write_data) &&
1479 : : ((const char*) data + length <= (const char*) s->write_data + pa_memblock_get_length(s->write_memblock))),
1480 : : PA_ERR_INVALID);
1481 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !free_cb || !s->write_memblock, PA_ERR_INVALID);
1482 : :
1483 [ # # ]: 0 : if (s->write_memblock) {
1484 : : pa_memchunk chunk;
1485 : :
1486 : : /* pa_stream_write_begin() was called before */
1487 : :
1488 : 0 : pa_memblock_release(s->write_memblock);
1489 : :
1490 : 0 : chunk.memblock = s->write_memblock;
1491 : 0 : chunk.index = (const char *) data - (const char *) s->write_data;
1492 : 0 : chunk.length = length;
1493 : :
1494 : 0 : s->write_memblock = NULL;
1495 : 0 : s->write_data = NULL;
1496 : :
1497 : 0 : pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk);
1498 : 0 : pa_memblock_unref(chunk.memblock);
1499 : :
1500 : : } else {
1501 : : pa_seek_mode_t t_seek = seek;
1502 : : int64_t t_offset = offset;
1503 : : size_t t_length = length;
1504 : : const void *t_data = data;
1505 : :
1506 : : /* pa_stream_write_begin() was not called before */
1507 : :
1508 [ # # ]: 0 : while (t_length > 0) {
1509 : : pa_memchunk chunk;
1510 : :
1511 : 0 : chunk.index = 0;
1512 : :
1513 [ # # ][ # # ]: 0 : if (free_cb && !pa_pstream_get_shm(s->context->pstream)) {
1514 : 0 : chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) t_data, t_length, free_cb, 1);
1515 : 0 : chunk.length = t_length;
1516 : : } else {
1517 : : void *d;
1518 : :
1519 : 0 : chunk.length = PA_MIN(t_length, pa_mempool_block_size_max(s->context->mempool));
1520 : 0 : chunk.memblock = pa_memblock_new(s->context->mempool, chunk.length);
1521 : :
1522 : 0 : d = pa_memblock_acquire(chunk.memblock);
1523 : 0 : memcpy(d, t_data, chunk.length);
1524 : 0 : pa_memblock_release(chunk.memblock);
1525 : : }
1526 : :
1527 : 0 : pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk);
1528 : :
1529 : 0 : t_offset = 0;
1530 : 0 : t_seek = PA_SEEK_RELATIVE;
1531 : :
1532 : 0 : t_data = (const uint8_t*) t_data + chunk.length;
1533 : 0 : t_length -= chunk.length;
1534 : :
1535 : 0 : pa_memblock_unref(chunk.memblock);
1536 : : }
1537 : :
1538 [ # # ][ # # ]: 0 : if (free_cb && pa_pstream_get_shm(s->context->pstream))
1539 : 0 : free_cb((void*) data);
1540 : : }
1541 : :
1542 : : /* This is obviously wrong since we ignore the seeking index . But
1543 : : * that's OK, the server side applies the same error */
1544 [ # # ]: 0 : s->requested_bytes -= (seek == PA_SEEK_RELATIVE ? offset : 0) + (int64_t) length;
1545 : :
1546 : : /* pa_log("wrote %lli, now at %lli", (long long) length, (long long) s->requested_bytes); */
1547 : :
1548 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK) {
1549 : :
1550 : : /* Update latency request correction */
1551 [ # # ]: 0 : if (s->write_index_corrections[s->current_write_index_correction].valid) {
1552 : :
1553 [ # # ]: 0 : if (seek == PA_SEEK_ABSOLUTE) {
1554 : 0 : s->write_index_corrections[s->current_write_index_correction].corrupt = FALSE;
1555 : 0 : s->write_index_corrections[s->current_write_index_correction].absolute = TRUE;
1556 : 0 : s->write_index_corrections[s->current_write_index_correction].value = offset + (int64_t) length;
1557 [ # # ]: 0 : } else if (seek == PA_SEEK_RELATIVE) {
1558 [ # # ]: 0 : if (!s->write_index_corrections[s->current_write_index_correction].corrupt)
1559 : 0 : s->write_index_corrections[s->current_write_index_correction].value += offset + (int64_t) length;
1560 : : } else
1561 : 0 : s->write_index_corrections[s->current_write_index_correction].corrupt = TRUE;
1562 : : }
1563 : :
1564 : : /* Update the write index in the already available latency data */
1565 [ # # ]: 0 : if (s->timing_info_valid) {
1566 : :
1567 [ # # ]: 0 : if (seek == PA_SEEK_ABSOLUTE) {
1568 : 0 : s->timing_info.write_index_corrupt = FALSE;
1569 : 0 : s->timing_info.write_index = offset + (int64_t) length;
1570 [ # # ]: 0 : } else if (seek == PA_SEEK_RELATIVE) {
1571 [ # # ]: 0 : if (!s->timing_info.write_index_corrupt)
1572 : 0 : s->timing_info.write_index += offset + (int64_t) length;
1573 : : } else
1574 : 0 : s->timing_info.write_index_corrupt = TRUE;
1575 : : }
1576 : :
1577 [ # # ][ # # ]: 0 : if (!s->timing_info_valid || s->timing_info.write_index_corrupt)
1578 : 0 : request_auto_timing_update(s, TRUE);
1579 : : }
1580 : :
1581 : : return 0;
1582 : : }
1583 : :
1584 : 0 : int pa_stream_peek(pa_stream *s, const void **data, size_t *length) {
1585 [ # # ]: 0 : pa_assert(s);
1586 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1587 [ # # ]: 0 : pa_assert(data);
1588 [ # # ]: 0 : pa_assert(length);
1589 : :
1590 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1591 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
1592 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE);
1593 : :
1594 [ # # ]: 0 : if (!s->peek_memchunk.memblock) {
1595 : :
1596 [ # # ]: 0 : if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) {
1597 : 0 : *data = NULL;
1598 : 0 : *length = 0;
1599 : 0 : return 0;
1600 : : }
1601 : :
1602 : 0 : s->peek_data = pa_memblock_acquire(s->peek_memchunk.memblock);
1603 : : }
1604 : :
1605 [ # # ]: 0 : pa_assert(s->peek_data);
1606 : 0 : *data = (uint8_t*) s->peek_data + s->peek_memchunk.index;
1607 : 0 : *length = s->peek_memchunk.length;
1608 : 0 : return 0;
1609 : : }
1610 : :
1611 : 0 : int pa_stream_drop(pa_stream *s) {
1612 [ # # ]: 0 : pa_assert(s);
1613 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1614 : :
1615 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1616 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
1617 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE);
1618 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE);
1619 : :
1620 : 0 : pa_memblockq_drop(s->record_memblockq, s->peek_memchunk.length);
1621 : :
1622 : : /* Fix the simulated local read index */
1623 [ # # ][ # # ]: 0 : if (s->timing_info_valid && !s->timing_info.read_index_corrupt)
1624 : 0 : s->timing_info.read_index += (int64_t) s->peek_memchunk.length;
1625 : :
1626 [ # # ]: 0 : pa_assert(s->peek_data);
1627 : 0 : pa_memblock_release(s->peek_memchunk.memblock);
1628 : 0 : pa_memblock_unref(s->peek_memchunk.memblock);
1629 : 0 : pa_memchunk_reset(&s->peek_memchunk);
1630 : :
1631 : 0 : return 0;
1632 : : }
1633 : :
1634 : 0 : size_t pa_stream_writable_size(pa_stream *s) {
1635 [ # # ]: 0 : pa_assert(s);
1636 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1637 : :
1638 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1);
1639 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1);
1640 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1);
1641 : :
1642 : 0 : return s->requested_bytes > 0 ? (size_t) s->requested_bytes : 0;
1643 : : }
1644 : :
1645 : 0 : size_t pa_stream_readable_size(pa_stream *s) {
1646 [ # # ]: 0 : pa_assert(s);
1647 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1648 : :
1649 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1);
1650 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1);
1651 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1);
1652 : :
1653 : 0 : return pa_memblockq_get_length(s->record_memblockq);
1654 : : }
1655 : :
1656 : 0 : pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
1657 : : pa_operation *o;
1658 : : pa_tagstruct *t;
1659 : : uint32_t tag;
1660 : :
1661 [ # # ]: 0 : pa_assert(s);
1662 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1663 : :
1664 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1665 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
1666 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
1667 : :
1668 : : /* Ask for a timing update before we cork/uncork to get the best
1669 : : * accuracy for the transport latency suitable for the
1670 : : * check_smoother_status() call in the started callback */
1671 : 0 : request_auto_timing_update(s, TRUE);
1672 : :
1673 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
1674 : :
1675 : 0 : t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag);
1676 : 0 : pa_tagstruct_putu32(t, s->channel);
1677 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
1678 : 0 : 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);
1679 : :
1680 : : /* This might cause the read index to continue again, hence
1681 : : * let's request a timing update */
1682 : 0 : request_auto_timing_update(s, TRUE);
1683 : :
1684 : 0 : return o;
1685 : : }
1686 : :
1687 : 0 : static pa_usec_t calc_time(pa_stream *s, pa_bool_t ignore_transport) {
1688 : : pa_usec_t usec;
1689 : :
1690 [ # # ]: 0 : pa_assert(s);
1691 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1692 [ # # ]: 0 : pa_assert(s->state == PA_STREAM_READY);
1693 [ # # ]: 0 : pa_assert(s->direction != PA_STREAM_UPLOAD);
1694 [ # # ]: 0 : pa_assert(s->timing_info_valid);
1695 [ # # ][ # # ]: 0 : pa_assert(s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt);
1696 [ # # ][ # # ]: 0 : pa_assert(s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt);
1697 : :
1698 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK) {
1699 : : /* The last byte that was written into the output device
1700 : : * had this time value associated */
1701 : 0 : usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec);
1702 : :
1703 [ # # ][ # # ]: 0 : if (!s->corked && !s->suspended) {
1704 : :
1705 [ # # ]: 0 : if (!ignore_transport)
1706 : : /* Because the latency info took a little time to come
1707 : : * to us, we assume that the real output time is actually
1708 : : * a little ahead */
1709 : 0 : usec += s->timing_info.transport_usec;
1710 : :
1711 : : /* However, the output device usually maintains a buffer
1712 : : too, hence the real sample currently played is a little
1713 : : back */
1714 [ # # ]: 0 : if (s->timing_info.sink_usec >= usec)
1715 : : usec = 0;
1716 : : else
1717 : 0 : usec -= s->timing_info.sink_usec;
1718 : : }
1719 : :
1720 : : } else {
1721 [ # # ]: 0 : pa_assert(s->direction == PA_STREAM_RECORD);
1722 : :
1723 : : /* The last byte written into the server side queue had
1724 : : * this time value associated */
1725 : 0 : usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec);
1726 : :
1727 [ # # ][ # # ]: 0 : if (!s->corked && !s->suspended) {
1728 : :
1729 [ # # ]: 0 : if (!ignore_transport)
1730 : : /* Add transport latency */
1731 : 0 : usec += s->timing_info.transport_usec;
1732 : :
1733 : : /* Add latency of data in device buffer */
1734 : 0 : usec += s->timing_info.source_usec;
1735 : :
1736 : : /* If this is a monitor source, we need to correct the
1737 : : * time by the playback device buffer */
1738 [ # # ]: 0 : if (s->timing_info.sink_usec >= usec)
1739 : : usec = 0;
1740 : : else
1741 : 0 : usec -= s->timing_info.sink_usec;
1742 : : }
1743 : : }
1744 : :
1745 : 0 : return usec;
1746 : : }
1747 : :
1748 : 0 : static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1749 : 0 : pa_operation *o = userdata;
1750 : : struct timeval local, remote, now;
1751 : : pa_timing_info *i;
1752 : 0 : pa_bool_t playing = FALSE;
1753 : 0 : uint64_t underrun_for = 0, playing_for = 0;
1754 : :
1755 [ # # ]: 0 : pa_assert(pd);
1756 [ # # ]: 0 : pa_assert(o);
1757 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
1758 : :
1759 [ # # ][ # # ]: 0 : if (!o->context || !o->stream)
1760 : : goto finish;
1761 : :
1762 : 0 : i = &o->stream->timing_info;
1763 : :
1764 : 0 : o->stream->timing_info_valid = FALSE;
1765 : 0 : i->write_index_corrupt = TRUE;
1766 : 0 : i->read_index_corrupt = TRUE;
1767 : :
1768 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
1769 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
1770 : : goto finish;
1771 : :
1772 : : } else {
1773 : :
1774 [ # # # # ]: 0 : if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 ||
1775 [ # # ]: 0 : pa_tagstruct_get_usec(t, &i->source_usec) < 0 ||
1776 [ # # ]: 0 : pa_tagstruct_get_boolean(t, &playing) < 0 ||
1777 [ # # ]: 0 : pa_tagstruct_get_timeval(t, &local) < 0 ||
1778 [ # # ]: 0 : pa_tagstruct_get_timeval(t, &remote) < 0 ||
1779 [ # # ]: 0 : pa_tagstruct_gets64(t, &i->write_index) < 0 ||
1780 : 0 : pa_tagstruct_gets64(t, &i->read_index) < 0) {
1781 : :
1782 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
1783 : 0 : goto finish;
1784 : : }
1785 : :
1786 [ # # ][ # # ]: 0 : if (o->context->version >= 13 &&
1787 : 0 : o->stream->direction == PA_STREAM_PLAYBACK)
1788 [ # # # # ]: 0 : if (pa_tagstruct_getu64(t, &underrun_for) < 0 ||
1789 : 0 : pa_tagstruct_getu64(t, &playing_for) < 0) {
1790 : :
1791 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
1792 : 0 : goto finish;
1793 : : }
1794 : :
1795 : :
1796 [ # # ]: 0 : if (!pa_tagstruct_eof(t)) {
1797 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
1798 : 0 : goto finish;
1799 : : }
1800 : 0 : o->stream->timing_info_valid = TRUE;
1801 : 0 : i->write_index_corrupt = FALSE;
1802 : 0 : i->read_index_corrupt = FALSE;
1803 : :
1804 : 0 : i->playing = (int) playing;
1805 [ # # ]: 0 : i->since_underrun = (int64_t) (playing ? playing_for : underrun_for);
1806 : :
1807 : 0 : pa_gettimeofday(&now);
1808 : :
1809 : : /* Calculate timestamps */
1810 [ # # ][ # # ]: 0 : if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) {
1811 : : /* local and remote seem to have synchronized clocks */
1812 : :
1813 [ # # ]: 0 : if (o->stream->direction == PA_STREAM_PLAYBACK)
1814 : 0 : i->transport_usec = pa_timeval_diff(&remote, &local);
1815 : : else
1816 : 0 : i->transport_usec = pa_timeval_diff(&now, &remote);
1817 : :
1818 : 0 : i->synchronized_clocks = TRUE;
1819 : 0 : i->timestamp = remote;
1820 : : } else {
1821 : : /* clocks are not synchronized, let's estimate latency then */
1822 : 0 : i->transport_usec = pa_timeval_diff(&now, &local)/2;
1823 : 0 : i->synchronized_clocks = FALSE;
1824 : 0 : i->timestamp = local;
1825 : 0 : pa_timeval_add(&i->timestamp, i->transport_usec);
1826 : : }
1827 : :
1828 : : /* Invalidate read and write indexes if necessary */
1829 [ # # ]: 0 : if (tag < o->stream->read_index_not_before)
1830 : 0 : i->read_index_corrupt = TRUE;
1831 : :
1832 [ # # ]: 0 : if (tag < o->stream->write_index_not_before)
1833 : 0 : i->write_index_corrupt = TRUE;
1834 : :
1835 [ # # ]: 0 : if (o->stream->direction == PA_STREAM_PLAYBACK) {
1836 : : /* Write index correction */
1837 : :
1838 : : int n, j;
1839 : 0 : uint32_t ctag = tag;
1840 : :
1841 : : /* Go through the saved correction values and add up the
1842 : : * total correction.*/
1843 [ # # ]: 0 : for (n = 0, j = o->stream->current_write_index_correction+1;
1844 : : n < PA_MAX_WRITE_INDEX_CORRECTIONS;
1845 : 0 : n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) {
1846 : :
1847 : : /* Step over invalid data or out-of-date data */
1848 [ # # ][ # # ]: 0 : if (!o->stream->write_index_corrections[j].valid ||
1849 : 0 : o->stream->write_index_corrections[j].tag < ctag)
1850 : 0 : continue;
1851 : :
1852 : : /* Make sure that everything is in order */
1853 : 0 : ctag = o->stream->write_index_corrections[j].tag+1;
1854 : :
1855 : : /* Now fix the write index */
1856 [ # # ]: 0 : if (o->stream->write_index_corrections[j].corrupt) {
1857 : : /* A corrupting seek was made */
1858 : 0 : i->write_index_corrupt = TRUE;
1859 [ # # ]: 0 : } else if (o->stream->write_index_corrections[j].absolute) {
1860 : : /* An absolute seek was made */
1861 : 0 : i->write_index = o->stream->write_index_corrections[j].value;
1862 : 0 : i->write_index_corrupt = FALSE;
1863 [ # # ]: 0 : } else if (!i->write_index_corrupt) {
1864 : : /* A relative seek was made */
1865 : 0 : i->write_index += o->stream->write_index_corrections[j].value;
1866 : : }
1867 : : }
1868 : :
1869 : : /* Clear old correction entries */
1870 [ # # ]: 0 : for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) {
1871 [ # # ]: 0 : if (!o->stream->write_index_corrections[n].valid)
1872 : 0 : continue;
1873 : :
1874 [ # # ]: 0 : if (o->stream->write_index_corrections[n].tag <= tag)
1875 : 0 : o->stream->write_index_corrections[n].valid = FALSE;
1876 : : }
1877 : : }
1878 : :
1879 [ # # ]: 0 : if (o->stream->direction == PA_STREAM_RECORD) {
1880 : : /* Read index correction */
1881 : :
1882 [ # # ]: 0 : if (!i->read_index_corrupt)
1883 : 0 : i->read_index -= (int64_t) pa_memblockq_get_length(o->stream->record_memblockq);
1884 : : }
1885 : :
1886 : : /* Update smoother if we're not corked */
1887 [ # # ][ # # ]: 0 : if (o->stream->smoother && !o->stream->corked) {
1888 : : pa_usec_t u, x;
1889 : :
1890 : 0 : u = x = pa_rtclock_now() - i->transport_usec;
1891 : :
1892 [ # # ][ # # ]: 0 : if (o->stream->direction == PA_STREAM_PLAYBACK && o->context->version >= 13) {
1893 : : pa_usec_t su;
1894 : :
1895 : : /* If we weren't playing then it will take some time
1896 : : * until the audio will actually come out through the
1897 : : * speakers. Since we follow that timing here, we need
1898 : : * to try to fix this up */
1899 : :
1900 : 0 : su = pa_bytes_to_usec((uint64_t) i->since_underrun, &o->stream->sample_spec);
1901 : :
1902 [ # # ]: 0 : if (su < i->sink_usec)
1903 : 0 : x += i->sink_usec - su;
1904 : : }
1905 : :
1906 [ # # ]: 0 : if (!i->playing)
1907 : 0 : pa_smoother_pause(o->stream->smoother, x);
1908 : :
1909 : : /* Update the smoother */
1910 [ # # ][ # # ]: 0 : if ((o->stream->direction == PA_STREAM_PLAYBACK && !i->read_index_corrupt) ||
[ # # ]
1911 [ # # ]: 0 : (o->stream->direction == PA_STREAM_RECORD && !i->write_index_corrupt))
1912 : 0 : pa_smoother_put(o->stream->smoother, u, calc_time(o->stream, TRUE));
1913 : :
1914 [ # # ]: 0 : if (i->playing)
1915 : 0 : pa_smoother_resume(o->stream->smoother, x, TRUE);
1916 : : }
1917 : : }
1918 : :
1919 : 0 : o->stream->auto_timing_update_requested = FALSE;
1920 : :
1921 [ # # ]: 0 : if (o->stream->latency_update_callback)
1922 : 0 : o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata);
1923 : :
1924 [ # # ][ # # ]: 0 : if (o->callback && o->stream && o->stream->state == PA_STREAM_READY) {
[ # # ]
1925 : 0 : pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback;
1926 : 0 : cb(o->stream, o->stream->timing_info_valid, o->userdata);
1927 : : }
1928 : :
1929 : : finish:
1930 : :
1931 : 0 : pa_operation_done(o);
1932 : 0 : pa_operation_unref(o);
1933 : 0 : }
1934 : :
1935 : 0 : pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
1936 : : uint32_t tag;
1937 : : pa_operation *o;
1938 : : pa_tagstruct *t;
1939 : : struct timeval now;
1940 : 0 : int cidx = 0;
1941 : :
1942 [ # # ]: 0 : pa_assert(s);
1943 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1944 : :
1945 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
1946 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
1947 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
1948 : :
1949 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK) {
1950 : : /* Find a place to store the write_index correction data for this entry */
1951 : 0 : cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS;
1952 : :
1953 : : /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */
1954 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL);
1955 : : }
1956 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
1957 : :
1958 [ # # ]: 0 : t = pa_tagstruct_command(
1959 : : s->context,
1960 : 0 : (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY),
1961 : : &tag);
1962 : 0 : pa_tagstruct_putu32(t, s->channel);
1963 : 0 : pa_tagstruct_put_timeval(t, pa_gettimeofday(&now));
1964 : :
1965 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
1966 : 0 : pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
1967 : :
1968 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK) {
1969 : : /* Fill in initial correction data */
1970 : :
1971 : 0 : s->current_write_index_correction = cidx;
1972 : :
1973 : 0 : s->write_index_corrections[cidx].valid = TRUE;
1974 : 0 : s->write_index_corrections[cidx].absolute = FALSE;
1975 : 0 : s->write_index_corrections[cidx].corrupt = FALSE;
1976 : 0 : s->write_index_corrections[cidx].tag = tag;
1977 : 0 : s->write_index_corrections[cidx].value = 0;
1978 : : }
1979 : :
1980 : : return o;
1981 : : }
1982 : :
1983 : 0 : void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
1984 : 0 : pa_stream *s = userdata;
1985 : :
1986 [ # # ]: 0 : pa_assert(pd);
1987 [ # # ]: 0 : pa_assert(s);
1988 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
1989 : :
1990 : 0 : pa_stream_ref(s);
1991 : :
1992 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
1993 [ # # ]: 0 : if (pa_context_handle_error(s->context, command, t, FALSE) < 0)
1994 : : goto finish;
1995 : :
1996 : 0 : pa_stream_set_state(s, PA_STREAM_FAILED);
1997 : 0 : goto finish;
1998 [ # # ]: 0 : } else if (!pa_tagstruct_eof(t)) {
1999 : 0 : pa_context_fail(s->context, PA_ERR_PROTOCOL);
2000 : 0 : goto finish;
2001 : : }
2002 : :
2003 : 0 : pa_stream_set_state(s, PA_STREAM_TERMINATED);
2004 : :
2005 : : finish:
2006 : 0 : pa_stream_unref(s);
2007 : 0 : }
2008 : :
2009 : 0 : int pa_stream_disconnect(pa_stream *s) {
2010 : : pa_tagstruct *t;
2011 : : uint32_t tag;
2012 : :
2013 [ # # ]: 0 : pa_assert(s);
2014 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2015 : :
2016 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2017 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE);
2018 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
2019 : :
2020 : 0 : pa_stream_ref(s);
2021 : :
2022 [ # # ][ # # ]: 0 : t = pa_tagstruct_command(
2023 : : s->context,
2024 : 0 : (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
2025 : 0 : (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)),
2026 : : &tag);
2027 : 0 : pa_tagstruct_putu32(t, s->channel);
2028 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2029 : 0 : pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL);
2030 : :
2031 : 0 : pa_stream_unref(s);
2032 : 0 : return 0;
2033 : : }
2034 : :
2035 : 0 : void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) {
2036 [ # # ]: 0 : pa_assert(s);
2037 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2038 : :
2039 [ # # ]: 0 : if (pa_detect_fork())
2040 : : return;
2041 : :
2042 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2043 : : return;
2044 : :
2045 : 0 : s->read_callback = cb;
2046 : 0 : s->read_userdata = userdata;
2047 : : }
2048 : :
2049 : 0 : void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) {
2050 [ # # ]: 0 : pa_assert(s);
2051 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2052 : :
2053 [ # # ]: 0 : if (pa_detect_fork())
2054 : : return;
2055 : :
2056 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2057 : : return;
2058 : :
2059 : 0 : s->write_callback = cb;
2060 : 0 : s->write_userdata = userdata;
2061 : : }
2062 : :
2063 : 0 : void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2064 [ # # ]: 0 : pa_assert(s);
2065 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2066 : :
2067 [ # # ]: 0 : if (pa_detect_fork())
2068 : : return;
2069 : :
2070 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2071 : : return;
2072 : :
2073 : 0 : s->state_callback = cb;
2074 : 0 : s->state_userdata = userdata;
2075 : : }
2076 : :
2077 : 0 : void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2078 [ # # ]: 0 : pa_assert(s);
2079 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2080 : :
2081 [ # # ]: 0 : if (pa_detect_fork())
2082 : : return;
2083 : :
2084 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2085 : : return;
2086 : :
2087 : 0 : s->overflow_callback = cb;
2088 : 0 : s->overflow_userdata = userdata;
2089 : : }
2090 : :
2091 : 0 : void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2092 [ # # ]: 0 : pa_assert(s);
2093 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2094 : :
2095 [ # # ]: 0 : if (pa_detect_fork())
2096 : : return;
2097 : :
2098 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2099 : : return;
2100 : :
2101 : 0 : s->underflow_callback = cb;
2102 : 0 : s->underflow_userdata = userdata;
2103 : : }
2104 : :
2105 : 0 : void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2106 [ # # ]: 0 : pa_assert(s);
2107 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2108 : :
2109 [ # # ]: 0 : if (pa_detect_fork())
2110 : : return;
2111 : :
2112 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2113 : : return;
2114 : :
2115 : 0 : s->latency_update_callback = cb;
2116 : 0 : s->latency_update_userdata = userdata;
2117 : : }
2118 : :
2119 : 0 : void pa_stream_set_moved_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2120 [ # # ]: 0 : pa_assert(s);
2121 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2122 : :
2123 [ # # ]: 0 : if (pa_detect_fork())
2124 : : return;
2125 : :
2126 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2127 : : return;
2128 : :
2129 : 0 : s->moved_callback = cb;
2130 : 0 : s->moved_userdata = userdata;
2131 : : }
2132 : :
2133 : 0 : void pa_stream_set_suspended_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2134 [ # # ]: 0 : pa_assert(s);
2135 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2136 : :
2137 [ # # ]: 0 : if (pa_detect_fork())
2138 : : return;
2139 : :
2140 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2141 : : return;
2142 : :
2143 : 0 : s->suspended_callback = cb;
2144 : 0 : s->suspended_userdata = userdata;
2145 : : }
2146 : :
2147 : 0 : void pa_stream_set_started_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2148 [ # # ]: 0 : pa_assert(s);
2149 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2150 : :
2151 [ # # ]: 0 : if (pa_detect_fork())
2152 : : return;
2153 : :
2154 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2155 : : return;
2156 : :
2157 : 0 : s->started_callback = cb;
2158 : 0 : s->started_userdata = userdata;
2159 : : }
2160 : :
2161 : 0 : void pa_stream_set_event_callback(pa_stream *s, pa_stream_event_cb_t cb, void *userdata) {
2162 [ # # ]: 0 : pa_assert(s);
2163 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2164 : :
2165 [ # # ]: 0 : if (pa_detect_fork())
2166 : : return;
2167 : :
2168 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2169 : : return;
2170 : :
2171 : 0 : s->event_callback = cb;
2172 : 0 : s->event_userdata = userdata;
2173 : : }
2174 : :
2175 : 0 : void pa_stream_set_buffer_attr_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
2176 [ # # ]: 0 : pa_assert(s);
2177 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2178 : :
2179 [ # # ]: 0 : if (pa_detect_fork())
2180 : : return;
2181 : :
2182 [ # # ]: 0 : if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
2183 : : return;
2184 : :
2185 : 0 : s->buffer_attr_callback = cb;
2186 : 0 : s->buffer_attr_userdata = userdata;
2187 : : }
2188 : :
2189 : 0 : void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2190 : 0 : pa_operation *o = userdata;
2191 : 0 : int success = 1;
2192 : :
2193 [ # # ]: 0 : pa_assert(pd);
2194 [ # # ]: 0 : pa_assert(o);
2195 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
2196 : :
2197 [ # # ]: 0 : if (!o->context)
2198 : : goto finish;
2199 : :
2200 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
2201 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
2202 : : goto finish;
2203 : :
2204 : : success = 0;
2205 [ # # ]: 0 : } else if (!pa_tagstruct_eof(t)) {
2206 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
2207 : 0 : goto finish;
2208 : : }
2209 : :
2210 [ # # ]: 0 : if (o->callback) {
2211 : 0 : pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback;
2212 : 0 : cb(o->stream, success, o->userdata);
2213 : : }
2214 : :
2215 : : finish:
2216 : 0 : pa_operation_done(o);
2217 : 0 : pa_operation_unref(o);
2218 : 0 : }
2219 : :
2220 : 0 : pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) {
2221 : : pa_operation *o;
2222 : : pa_tagstruct *t;
2223 : : uint32_t tag;
2224 : :
2225 [ # # ]: 0 : pa_assert(s);
2226 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2227 : :
2228 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2229 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2230 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2231 : :
2232 : : /* Ask for a timing update before we cork/uncork to get the best
2233 : : * accuracy for the transport latency suitable for the
2234 : : * check_smoother_status() call in the started callback */
2235 : 0 : request_auto_timing_update(s, TRUE);
2236 : :
2237 : 0 : s->corked = b;
2238 : :
2239 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
2240 : :
2241 [ # # ]: 0 : t = pa_tagstruct_command(
2242 : : s->context,
2243 : 0 : (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM),
2244 : : &tag);
2245 : 0 : pa_tagstruct_putu32(t, s->channel);
2246 : 0 : pa_tagstruct_put_boolean(t, !!b);
2247 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2248 : 0 : 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);
2249 : :
2250 : 0 : check_smoother_status(s, FALSE, FALSE, FALSE);
2251 : :
2252 : : /* This might cause the indexes to hang/start again, hence let's
2253 : : * request a timing update, after the cork/uncork, too */
2254 : 0 : request_auto_timing_update(s, TRUE);
2255 : :
2256 : 0 : return o;
2257 : : }
2258 : :
2259 : 0 : static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_stream_success_cb_t cb, void *userdata) {
2260 : : pa_tagstruct *t;
2261 : : pa_operation *o;
2262 : : uint32_t tag;
2263 : :
2264 [ # # ]: 0 : pa_assert(s);
2265 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2266 : :
2267 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2268 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2269 : :
2270 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
2271 : :
2272 : 0 : t = pa_tagstruct_command(s->context, command, &tag);
2273 : 0 : pa_tagstruct_putu32(t, s->channel);
2274 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2275 : 0 : 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);
2276 : :
2277 : 0 : return o;
2278 : : }
2279 : :
2280 : 0 : pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
2281 : : pa_operation *o;
2282 : :
2283 [ # # ]: 0 : pa_assert(s);
2284 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2285 : :
2286 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2287 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2288 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2289 : :
2290 : : /* Ask for a timing update *before* the flush, so that the
2291 : : * transport usec is as up to date as possible when we get the
2292 : : * underflow message and update the smoother status*/
2293 : 0 : request_auto_timing_update(s, TRUE);
2294 : :
2295 [ # # ][ # # ]: 0 : if (!(o = stream_send_simple_command(s, (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM), cb, userdata)))
2296 : : return NULL;
2297 : :
2298 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK) {
2299 : :
2300 [ # # ]: 0 : if (s->write_index_corrections[s->current_write_index_correction].valid)
2301 : 0 : s->write_index_corrections[s->current_write_index_correction].corrupt = TRUE;
2302 : :
2303 [ # # ]: 0 : if (s->buffer_attr.prebuf > 0)
2304 : 0 : check_smoother_status(s, FALSE, FALSE, TRUE);
2305 : :
2306 : : /* This will change the write index, but leave the
2307 : : * read index untouched. */
2308 : 0 : invalidate_indexes(s, FALSE, TRUE);
2309 : :
2310 : : } else
2311 : : /* For record streams this has no influence on the write
2312 : : * index, but the read index might jump. */
2313 : 0 : invalidate_indexes(s, TRUE, FALSE);
2314 : :
2315 : : /* Note that we do not update requested_bytes here. This is
2316 : : * because we cannot really know how data actually was dropped
2317 : : * from the write index due to this. This 'error' will be applied
2318 : : * by both client and server and hence we should be fine. */
2319 : :
2320 : : return o;
2321 : : }
2322 : :
2323 : 0 : pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
2324 : : pa_operation *o;
2325 : :
2326 [ # # ]: 0 : pa_assert(s);
2327 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2328 : :
2329 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2330 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2331 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
2332 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE);
2333 : :
2334 : : /* Ask for a timing update before we cork/uncork to get the best
2335 : : * accuracy for the transport latency suitable for the
2336 : : * check_smoother_status() call in the started callback */
2337 : 0 : request_auto_timing_update(s, TRUE);
2338 : :
2339 [ # # ]: 0 : if (!(o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata)))
2340 : : return NULL;
2341 : :
2342 : : /* This might cause the read index to hang again, hence
2343 : : * let's request a timing update */
2344 : 0 : request_auto_timing_update(s, TRUE);
2345 : :
2346 : 0 : return o;
2347 : : }
2348 : :
2349 : 0 : pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) {
2350 : : pa_operation *o;
2351 : :
2352 [ # # ]: 0 : pa_assert(s);
2353 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2354 : :
2355 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2356 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2357 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE);
2358 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE);
2359 : :
2360 : : /* Ask for a timing update before we cork/uncork to get the best
2361 : : * accuracy for the transport latency suitable for the
2362 : : * check_smoother_status() call in the started callback */
2363 : 0 : request_auto_timing_update(s, TRUE);
2364 : :
2365 [ # # ]: 0 : if (!(o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata)))
2366 : : return NULL;
2367 : :
2368 : : /* This might cause the read index to start moving again, hence
2369 : : * let's request a timing update */
2370 : 0 : request_auto_timing_update(s, TRUE);
2371 : :
2372 : 0 : return o;
2373 : : }
2374 : :
2375 : 0 : pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) {
2376 : : pa_operation *o;
2377 : :
2378 [ # # ]: 0 : pa_assert(s);
2379 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2380 [ # # ]: 0 : pa_assert(name);
2381 : :
2382 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2383 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2384 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2385 : :
2386 [ # # ]: 0 : if (s->context->version >= 13) {
2387 : 0 : pa_proplist *p = pa_proplist_new();
2388 : :
2389 : 0 : pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
2390 : 0 : o = pa_stream_proplist_update(s, PA_UPDATE_REPLACE, p, cb, userdata);
2391 : 0 : pa_proplist_free(p);
2392 : : } else {
2393 : : pa_tagstruct *t;
2394 : : uint32_t tag;
2395 : :
2396 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
2397 [ # # ]: 0 : t = pa_tagstruct_command(
2398 : : s->context,
2399 : 0 : (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME),
2400 : : &tag);
2401 : 0 : pa_tagstruct_putu32(t, s->channel);
2402 : 0 : pa_tagstruct_puts(t, name);
2403 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2404 : 0 : 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);
2405 : : }
2406 : :
2407 : 0 : return o;
2408 : : }
2409 : :
2410 : 0 : int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) {
2411 : : pa_usec_t usec;
2412 : :
2413 [ # # ]: 0 : pa_assert(s);
2414 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2415 : :
2416 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2417 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2418 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2419 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA);
2420 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA);
2421 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA);
2422 : :
2423 [ # # ]: 0 : if (s->smoother)
2424 : 0 : usec = pa_smoother_get(s->smoother, pa_rtclock_now());
2425 : : else
2426 : 0 : usec = calc_time(s, FALSE);
2427 : :
2428 : : /* Make sure the time runs monotonically */
2429 [ # # ]: 0 : if (!(s->flags & PA_STREAM_NOT_MONOTONIC)) {
2430 [ # # ]: 0 : if (usec < s->previous_time)
2431 : 0 : usec = s->previous_time;
2432 : : else
2433 : 0 : s->previous_time = usec;
2434 : : }
2435 : :
2436 [ # # ]: 0 : if (r_usec)
2437 : 0 : *r_usec = usec;
2438 : :
2439 : : return 0;
2440 : : }
2441 : :
2442 : 0 : static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) {
2443 [ # # ]: 0 : pa_assert(s);
2444 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2445 : :
2446 [ # # ]: 0 : if (negative)
2447 : 0 : *negative = 0;
2448 : :
2449 [ # # ]: 0 : if (a >= b)
2450 : 0 : return a-b;
2451 : : else {
2452 [ # # ][ # # ]: 0 : if (negative && s->direction == PA_STREAM_RECORD) {
2453 : 0 : *negative = 1;
2454 : 0 : return b-a;
2455 : : } else
2456 : : return 0;
2457 : : }
2458 : : }
2459 : :
2460 : 0 : int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) {
2461 : : pa_usec_t t, c;
2462 : : int r;
2463 : : int64_t cindex;
2464 : :
2465 [ # # ]: 0 : pa_assert(s);
2466 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2467 [ # # ]: 0 : pa_assert(r_usec);
2468 : :
2469 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2470 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2471 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2472 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA);
2473 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA);
2474 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA);
2475 : :
2476 [ # # ]: 0 : if ((r = pa_stream_get_time(s, &t)) < 0)
2477 : : return r;
2478 : :
2479 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK)
2480 : 0 : cindex = s->timing_info.write_index;
2481 : : else
2482 : 0 : cindex = s->timing_info.read_index;
2483 : :
2484 [ # # ]: 0 : if (cindex < 0)
2485 : 0 : cindex = 0;
2486 : :
2487 : 0 : c = pa_bytes_to_usec((uint64_t) cindex, &s->sample_spec);
2488 : :
2489 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK)
2490 : 0 : *r_usec = time_counter_diff(s, c, t, negative);
2491 : : else
2492 : 0 : *r_usec = time_counter_diff(s, t, c, negative);
2493 : :
2494 : : return 0;
2495 : : }
2496 : :
2497 : 0 : const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) {
2498 [ # # ]: 0 : pa_assert(s);
2499 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2500 : :
2501 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2502 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2503 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2504 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->timing_info_valid, PA_ERR_NODATA);
2505 : :
2506 : 0 : return &s->timing_info;
2507 : : }
2508 : :
2509 : 0 : const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) {
2510 [ # # ]: 0 : pa_assert(s);
2511 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2512 : :
2513 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2514 : :
2515 : 0 : return &s->sample_spec;
2516 : : }
2517 : :
2518 : 0 : const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) {
2519 [ # # ]: 0 : pa_assert(s);
2520 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2521 : :
2522 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2523 : :
2524 : 0 : return &s->channel_map;
2525 : : }
2526 : :
2527 : 0 : const pa_format_info* pa_stream_get_format_info(pa_stream *s) {
2528 [ # # ]: 0 : pa_assert(s);
2529 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2530 : :
2531 : : /* We don't have the format till routing is done */
2532 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2533 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2534 : :
2535 : 0 : return s->format;
2536 : : }
2537 : 0 : const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) {
2538 [ # # ]: 0 : pa_assert(s);
2539 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2540 : :
2541 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2542 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2543 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 9, PA_ERR_NOTSUPPORTED);
2544 : :
2545 : 0 : return &s->buffer_attr;
2546 : : }
2547 : :
2548 : 0 : static void stream_set_buffer_attr_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2549 : 0 : pa_operation *o = userdata;
2550 : 0 : int success = 1;
2551 : :
2552 [ # # ]: 0 : pa_assert(pd);
2553 [ # # ]: 0 : pa_assert(o);
2554 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
2555 : :
2556 [ # # ]: 0 : if (!o->context)
2557 : : goto finish;
2558 : :
2559 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
2560 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
2561 : : goto finish;
2562 : :
2563 : : success = 0;
2564 : : } else {
2565 [ # # ]: 0 : if (o->stream->direction == PA_STREAM_PLAYBACK) {
2566 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &o->stream->buffer_attr.maxlength) < 0 ||
2567 [ # # ]: 0 : pa_tagstruct_getu32(t, &o->stream->buffer_attr.tlength) < 0 ||
2568 [ # # ]: 0 : pa_tagstruct_getu32(t, &o->stream->buffer_attr.prebuf) < 0 ||
2569 : 0 : pa_tagstruct_getu32(t, &o->stream->buffer_attr.minreq) < 0) {
2570 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
2571 : 0 : goto finish;
2572 : : }
2573 [ # # ]: 0 : } else if (o->stream->direction == PA_STREAM_RECORD) {
2574 [ # # # # ]: 0 : if (pa_tagstruct_getu32(t, &o->stream->buffer_attr.maxlength) < 0 ||
2575 : 0 : pa_tagstruct_getu32(t, &o->stream->buffer_attr.fragsize) < 0) {
2576 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
2577 : 0 : goto finish;
2578 : : }
2579 : : }
2580 : :
2581 [ # # ]: 0 : if (o->stream->context->version >= 13) {
2582 : : pa_usec_t usec;
2583 : :
2584 [ # # ]: 0 : if (pa_tagstruct_get_usec(t, &usec) < 0) {
2585 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
2586 : 0 : goto finish;
2587 : : }
2588 : :
2589 [ # # ]: 0 : if (o->stream->direction == PA_STREAM_RECORD)
2590 : 0 : o->stream->timing_info.configured_source_usec = usec;
2591 : : else
2592 : 0 : o->stream->timing_info.configured_sink_usec = usec;
2593 : : }
2594 : :
2595 [ # # ]: 0 : if (!pa_tagstruct_eof(t)) {
2596 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
2597 : 0 : goto finish;
2598 : : }
2599 : : }
2600 : :
2601 [ # # ]: 0 : if (o->callback) {
2602 : 0 : pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback;
2603 : 0 : cb(o->stream, success, o->userdata);
2604 : : }
2605 : :
2606 : : finish:
2607 : 0 : pa_operation_done(o);
2608 : 0 : pa_operation_unref(o);
2609 : 0 : }
2610 : :
2611 : :
2612 : 0 : pa_operation* pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata) {
2613 : : pa_operation *o;
2614 : : pa_tagstruct *t;
2615 : : uint32_t tag;
2616 : : pa_buffer_attr copy;
2617 : :
2618 [ # # ]: 0 : pa_assert(s);
2619 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2620 [ # # ]: 0 : pa_assert(attr);
2621 : :
2622 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2623 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2624 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2625 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED);
2626 : :
2627 : : /* Ask for a timing update before we cork/uncork to get the best
2628 : : * accuracy for the transport latency suitable for the
2629 : : * check_smoother_status() call in the started callback */
2630 : 0 : request_auto_timing_update(s, TRUE);
2631 : :
2632 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
2633 : :
2634 [ # # ]: 0 : t = pa_tagstruct_command(
2635 : : s->context,
2636 : 0 : (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR : PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR),
2637 : : &tag);
2638 : 0 : pa_tagstruct_putu32(t, s->channel);
2639 : :
2640 : 0 : copy = *attr;
2641 : 0 : patch_buffer_attr(s, ©, NULL);
2642 : 0 : attr = ©
2643 : :
2644 : 0 : pa_tagstruct_putu32(t, attr->maxlength);
2645 : :
2646 [ # # ]: 0 : if (s->direction == PA_STREAM_PLAYBACK)
2647 : 0 : pa_tagstruct_put(
2648 : : t,
2649 : : PA_TAG_U32, attr->tlength,
2650 : : PA_TAG_U32, attr->prebuf,
2651 : : PA_TAG_U32, attr->minreq,
2652 : : PA_TAG_INVALID);
2653 : : else
2654 : 0 : pa_tagstruct_putu32(t, attr->fragsize);
2655 : :
2656 [ # # ]: 0 : if (s->context->version >= 13)
2657 : 0 : pa_tagstruct_put_boolean(t, !!(s->flags & PA_STREAM_ADJUST_LATENCY));
2658 : :
2659 [ # # ]: 0 : if (s->context->version >= 14)
2660 : 0 : pa_tagstruct_put_boolean(t, !!(s->flags & PA_STREAM_EARLY_REQUESTS));
2661 : :
2662 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2663 : 0 : pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_set_buffer_attr_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
2664 : :
2665 : : /* This might cause changes in the read/write index, hence let's
2666 : : * request a timing update */
2667 : 0 : request_auto_timing_update(s, TRUE);
2668 : :
2669 : 0 : return o;
2670 : : }
2671 : :
2672 : 0 : uint32_t pa_stream_get_device_index(pa_stream *s) {
2673 [ # # ]: 0 : pa_assert(s);
2674 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2675 : :
2676 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
2677 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
2678 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, PA_INVALID_INDEX);
2679 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
2680 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->device_index != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX);
2681 : :
2682 : 0 : return s->device_index;
2683 : : }
2684 : :
2685 : 0 : const char *pa_stream_get_device_name(pa_stream *s) {
2686 [ # # ]: 0 : pa_assert(s);
2687 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2688 : :
2689 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2690 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2691 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2692 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED);
2693 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->device_name, PA_ERR_BADSTATE);
2694 : :
2695 : 0 : return s->device_name;
2696 : : }
2697 : :
2698 : 0 : int pa_stream_is_suspended(pa_stream *s) {
2699 [ # # ]: 0 : pa_assert(s);
2700 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2701 : :
2702 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2703 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2704 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2705 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED);
2706 : :
2707 : 0 : return s->suspended;
2708 : : }
2709 : :
2710 : 0 : int pa_stream_is_corked(pa_stream *s) {
2711 [ # # ]: 0 : pa_assert(s);
2712 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2713 : :
2714 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2715 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2716 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2717 : :
2718 : 0 : return s->corked;
2719 : : }
2720 : :
2721 : 0 : static void stream_update_sample_rate_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
2722 : 0 : pa_operation *o = userdata;
2723 : 0 : int success = 1;
2724 : :
2725 [ # # ]: 0 : pa_assert(pd);
2726 [ # # ]: 0 : pa_assert(o);
2727 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(o) >= 1);
2728 : :
2729 [ # # ]: 0 : if (!o->context)
2730 : : goto finish;
2731 : :
2732 [ # # ]: 0 : if (command != PA_COMMAND_REPLY) {
2733 [ # # ]: 0 : if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
2734 : : goto finish;
2735 : :
2736 : : success = 0;
2737 : : } else {
2738 : :
2739 [ # # ]: 0 : if (!pa_tagstruct_eof(t)) {
2740 : 0 : pa_context_fail(o->context, PA_ERR_PROTOCOL);
2741 : 0 : goto finish;
2742 : : }
2743 : : }
2744 : :
2745 : 0 : o->stream->sample_spec.rate = PA_PTR_TO_UINT(o->private);
2746 [ # # ]: 0 : pa_assert(pa_sample_spec_valid(&o->stream->sample_spec));
2747 : :
2748 [ # # ]: 0 : if (o->callback) {
2749 : 0 : pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback;
2750 : 0 : cb(o->stream, success, o->userdata);
2751 : : }
2752 : :
2753 : : finish:
2754 : 0 : pa_operation_done(o);
2755 : 0 : pa_operation_unref(o);
2756 : 0 : }
2757 : :
2758 : :
2759 : 0 : pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata) {
2760 : : pa_operation *o;
2761 : : pa_tagstruct *t;
2762 : : uint32_t tag;
2763 : :
2764 [ # # ]: 0 : pa_assert(s);
2765 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2766 : :
2767 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2768 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, rate > 0 && rate <= PA_RATE_MAX, PA_ERR_INVALID);
2769 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2770 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2771 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->flags & PA_STREAM_VARIABLE_RATE, PA_ERR_BADSTATE);
2772 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED);
2773 : :
2774 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
2775 : 0 : o->private = PA_UINT_TO_PTR(rate);
2776 : :
2777 [ # # ]: 0 : t = pa_tagstruct_command(
2778 : : s->context,
2779 : 0 : (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE : PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE),
2780 : : &tag);
2781 : 0 : pa_tagstruct_putu32(t, s->channel);
2782 : 0 : pa_tagstruct_putu32(t, rate);
2783 : :
2784 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2785 : 0 : pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_update_sample_rate_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
2786 : :
2787 : 0 : return o;
2788 : : }
2789 : :
2790 : 0 : pa_operation *pa_stream_proplist_update(pa_stream *s, pa_update_mode_t mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata) {
2791 : : pa_operation *o;
2792 : : pa_tagstruct *t;
2793 : : uint32_t tag;
2794 : :
2795 [ # # ]: 0 : pa_assert(s);
2796 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2797 : :
2798 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2799 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
2800 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2801 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2802 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED);
2803 : :
2804 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
2805 : :
2806 [ # # ]: 0 : t = pa_tagstruct_command(
2807 : : s->context,
2808 : 0 : (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST : PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST),
2809 : : &tag);
2810 : 0 : pa_tagstruct_putu32(t, s->channel);
2811 : 0 : pa_tagstruct_putu32(t, (uint32_t) mode);
2812 : 0 : pa_tagstruct_put_proplist(t, p);
2813 : :
2814 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2815 : 0 : 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);
2816 : :
2817 : : /* Please note that we don't update s->proplist here, because we
2818 : : * don't export that field */
2819 : :
2820 : 0 : return o;
2821 : : }
2822 : :
2823 : 0 : pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata) {
2824 : : pa_operation *o;
2825 : : pa_tagstruct *t;
2826 : : uint32_t tag;
2827 : : const char * const*k;
2828 : :
2829 [ # # ]: 0 : pa_assert(s);
2830 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2831 : :
2832 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2833 [ # # ][ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, keys && keys[0], PA_ERR_INVALID);
2834 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE);
2835 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE);
2836 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED);
2837 : :
2838 : 0 : o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata);
2839 : :
2840 [ # # ]: 0 : t = pa_tagstruct_command(
2841 : : s->context,
2842 : 0 : (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST : PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST),
2843 : : &tag);
2844 : 0 : pa_tagstruct_putu32(t, s->channel);
2845 : :
2846 [ # # ]: 0 : for (k = keys; *k; k++)
2847 : 0 : pa_tagstruct_puts(t, *k);
2848 : :
2849 : 0 : pa_tagstruct_puts(t, NULL);
2850 : :
2851 : 0 : pa_pstream_send_tagstruct(s->context->pstream, t);
2852 : 0 : 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);
2853 : :
2854 : : /* Please note that we don't update s->proplist here, because we
2855 : : * don't export that field */
2856 : :
2857 : 0 : return o;
2858 : : }
2859 : :
2860 : 0 : int pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) {
2861 [ # # ]: 0 : pa_assert(s);
2862 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2863 : :
2864 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
2865 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, sink_input_idx != PA_INVALID_INDEX, PA_ERR_INVALID);
2866 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
2867 [ # # ]: 0 : PA_CHECK_VALIDITY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED);
2868 : :
2869 : 0 : s->direct_on_input = sink_input_idx;
2870 : :
2871 : 0 : return 0;
2872 : : }
2873 : :
2874 : 0 : uint32_t pa_stream_get_monitor_stream(pa_stream *s) {
2875 [ # # ]: 0 : pa_assert(s);
2876 [ # # ]: 0 : pa_assert(PA_REFCNT_VALUE(s) >= 1);
2877 : :
2878 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX);
2879 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direct_on_input != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX);
2880 [ # # ]: 0 : PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
2881 : :
2882 : 0 : return s->direct_on_input;
2883 : : }
|