4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 #include <pulse/def.h>
34 #include <pulse/timeval.h>
35 #include <pulse/xmalloc.h>
37 #include <pulsecore/pstream-util.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/hashmap.h>
40 #include <pulsecore/macro.h>
44 #define LATENCY_IPOL_INTERVAL_USEC (100000L)
46 pa_stream
*pa_stream_new(pa_context
*c
, const char *name
, const pa_sample_spec
*ss
, const pa_channel_map
*map
) {
47 return pa_stream_new_with_proplist(c
, name
, ss
, map
, NULL
);
50 pa_stream
*pa_stream_new_with_proplist(pa_context
*c
, const char *name
, const pa_sample_spec
*ss
, const pa_channel_map
*map
, pa_proplist
*p
) {
56 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
58 PA_CHECK_VALIDITY_RETURN_NULL(c
, ss
&& pa_sample_spec_valid(ss
), PA_ERR_INVALID
);
59 PA_CHECK_VALIDITY_RETURN_NULL(c
, c
->version
>= 12 || (ss
->format
!= PA_SAMPLE_S32LE
|| ss
->format
!= PA_SAMPLE_S32NE
), PA_ERR_NOTSUPPORTED
);
60 PA_CHECK_VALIDITY_RETURN_NULL(c
, !map
|| (pa_channel_map_valid(map
) && map
->channels
== ss
->channels
), PA_ERR_INVALID
);
61 PA_CHECK_VALIDITY_RETURN_NULL(c
, name
|| pa_proplist_contains(p
, PA_PROP_MEDIA_NAME
), PA_ERR_INVALID
);
64 PA_CHECK_VALIDITY_RETURN_NULL(c
, map
= pa_channel_map_init_auto(&tmap
, ss
->channels
, PA_CHANNEL_MAP_DEFAULT
), PA_ERR_INVALID
);
66 s
= pa_xnew(pa_stream
, 1);
69 s
->mainloop
= c
->mainloop
;
71 s
->read_callback
= NULL
;
72 s
->read_userdata
= NULL
;
73 s
->write_callback
= NULL
;
74 s
->write_userdata
= NULL
;
75 s
->state_callback
= NULL
;
76 s
->state_userdata
= NULL
;
77 s
->overflow_callback
= NULL
;
78 s
->overflow_userdata
= NULL
;
79 s
->underflow_callback
= NULL
;
80 s
->underflow_userdata
= NULL
;
81 s
->latency_update_callback
= NULL
;
82 s
->latency_update_userdata
= NULL
;
83 s
->moved_callback
= NULL
;
84 s
->moved_userdata
= NULL
;
85 s
->suspended_callback
= NULL
;
86 s
->suspended_userdata
= NULL
;
88 s
->direction
= PA_STREAM_NODIRECTION
;
90 s
->channel_map
= *map
;
93 s
->proplist
= p
? pa_proplist_copy(p
) : pa_proplist_new();
96 pa_proplist_sets(s
->proplist
, PA_PROP_MEDIA_NAME
, name
);
100 s
->syncid
= c
->csyncid
++;
101 s
->stream_index
= PA_INVALID_INDEX
;
102 s
->requested_bytes
= 0;
103 s
->state
= PA_STREAM_UNCONNECTED
;
105 s
->manual_buffer_attr
= FALSE
;
106 memset(&s
->buffer_attr
, 0, sizeof(s
->buffer_attr
));
108 s
->device_index
= PA_INVALID_INDEX
;
109 s
->device_name
= NULL
;
110 s
->suspended
= FALSE
;
112 s
->peek_memchunk
.index
= 0;
113 s
->peek_memchunk
.length
= 0;
114 s
->peek_memchunk
.memblock
= NULL
;
117 s
->record_memblockq
= NULL
;
119 s
->previous_time
= 0;
120 memset(&s
->timing_info
, 0, sizeof(s
->timing_info
));
121 s
->timing_info_valid
= FALSE
;
122 s
->read_index_not_before
= 0;
123 s
->write_index_not_before
= 0;
125 for (i
= 0; i
< PA_MAX_WRITE_INDEX_CORRECTIONS
; i
++)
126 s
->write_index_corrections
[i
].valid
= 0;
127 s
->current_write_index_correction
= 0;
131 s
->cached_time_valid
= 0;
133 s
->auto_timing_update_event
= NULL
;
134 s
->auto_timing_update_requested
= 0;
136 /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */
137 PA_LLIST_PREPEND(pa_stream
, c
->streams
, s
);
143 static void stream_free(pa_stream
*s
) {
145 pa_assert(!s
->context
);
146 pa_assert(!s
->channel_valid
);
148 if (s
->auto_timing_update_event
) {
149 pa_assert(s
->mainloop
);
150 s
->mainloop
->time_free(s
->auto_timing_update_event
);
153 if (s
->peek_memchunk
.memblock
) {
155 pa_memblock_release(s
->peek_memchunk
.memblock
);
156 pa_memblock_unref(s
->peek_memchunk
.memblock
);
159 if (s
->record_memblockq
)
160 pa_memblockq_free(s
->record_memblockq
);
163 pa_proplist_free(s
->proplist
);
165 pa_xfree(s
->device_name
);
169 void pa_stream_unref(pa_stream
*s
) {
171 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
173 if (PA_REFCNT_DEC(s
) <= 0)
177 pa_stream
* pa_stream_ref(pa_stream
*s
) {
179 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
185 pa_stream_state_t
pa_stream_get_state(pa_stream
*s
) {
187 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
192 pa_context
* pa_stream_get_context(pa_stream
*s
) {
194 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
199 uint32_t pa_stream_get_index(pa_stream
*s
) {
201 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
203 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
, PA_INVALID_INDEX
);
205 return s
->stream_index
;
208 void pa_stream_set_state(pa_stream
*s
, pa_stream_state_t st
) {
210 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
218 if (s
->state_callback
)
219 s
->state_callback(s
, s
->state_userdata
);
221 if ((st
== PA_STREAM_FAILED
|| st
== PA_STREAM_TERMINATED
) && s
->context
) {
223 /* Detach from context */
226 /* Unref all operatio object that point to us */
227 for (o
= s
->context
->operations
; o
; o
= n
) {
231 pa_operation_cancel(o
);
234 /* Drop all outstanding replies for this stream */
235 if (s
->context
->pdispatch
)
236 pa_pdispatch_unregister_reply(s
->context
->pdispatch
, s
);
238 if (s
->channel_valid
)
239 pa_dynarray_put((s
->direction
== PA_STREAM_PLAYBACK
) ? s
->context
->playback_streams
: s
->context
->record_streams
, s
->channel
, NULL
);
241 PA_LLIST_REMOVE(pa_stream
, s
->context
->streams
, s
);
245 s
->channel_valid
= 0;
249 s
->read_callback
= NULL
;
250 s
->write_callback
= NULL
;
251 s
->state_callback
= NULL
;
252 s
->overflow_callback
= NULL
;
253 s
->underflow_callback
= NULL
;
254 s
->latency_update_callback
= NULL
;
260 void pa_command_stream_killed(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
261 pa_context
*c
= userdata
;
266 pa_assert(command
== PA_COMMAND_PLAYBACK_STREAM_KILLED
|| command
== PA_COMMAND_RECORD_STREAM_KILLED
);
269 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
273 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
274 !pa_tagstruct_eof(t
)) {
275 pa_context_fail(c
, PA_ERR_PROTOCOL
);
279 if (!(s
= pa_dynarray_get(command
== PA_COMMAND_PLAYBACK_STREAM_KILLED
? c
->playback_streams
: c
->record_streams
, channel
)))
282 pa_context_set_error(c
, PA_ERR_KILLED
);
283 pa_stream_set_state(s
, PA_STREAM_FAILED
);
289 void pa_command_stream_moved(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
290 pa_context
*c
= userdata
;
298 pa_assert(command
== PA_COMMAND_PLAYBACK_STREAM_MOVED
|| command
== PA_COMMAND_RECORD_STREAM_MOVED
);
301 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
305 if (c
->version
< 12) {
306 pa_context_fail(c
, PA_ERR_PROTOCOL
);
310 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
311 pa_tagstruct_getu32(t
, &di
) < 0 ||
312 pa_tagstruct_gets(t
, &dn
) < 0 ||
313 pa_tagstruct_get_boolean(t
, &suspended
) < 0 ||
314 !pa_tagstruct_eof(t
)) {
315 pa_context_fail(c
, PA_ERR_PROTOCOL
);
319 if (!dn
|| di
== PA_INVALID_INDEX
) {
320 pa_context_fail(c
, PA_ERR_PROTOCOL
);
324 if (!(s
= pa_dynarray_get(command
== PA_COMMAND_PLAYBACK_STREAM_MOVED
? c
->playback_streams
: c
->record_streams
, channel
)))
327 pa_xfree(s
->device_name
);
328 s
->device_name
= pa_xstrdup(dn
);
329 s
->device_index
= di
;
331 s
->suspended
= suspended
;
333 if (s
->moved_callback
)
334 s
->moved_callback(s
, s
->moved_userdata
);
340 void pa_command_stream_suspended(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
341 pa_context
*c
= userdata
;
347 pa_assert(command
== PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
|| command
== PA_COMMAND_RECORD_STREAM_SUSPENDED
);
350 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
354 if (c
->version
< 12) {
355 pa_context_fail(c
, PA_ERR_PROTOCOL
);
359 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
360 pa_tagstruct_get_boolean(t
, &suspended
) < 0 ||
361 !pa_tagstruct_eof(t
)) {
362 pa_context_fail(c
, PA_ERR_PROTOCOL
);
366 if (!(s
= pa_dynarray_get(command
== PA_COMMAND_PLAYBACK_STREAM_SUSPENDED
? c
->playback_streams
: c
->record_streams
, channel
)))
369 s
->suspended
= suspended
;
371 if (s
->suspended_callback
)
372 s
->suspended_callback(s
, s
->suspended_userdata
);
378 void pa_command_request(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
380 pa_context
*c
= userdata
;
381 uint32_t bytes
, channel
;
384 pa_assert(command
== PA_COMMAND_REQUEST
);
387 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
391 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
392 pa_tagstruct_getu32(t
, &bytes
) < 0 ||
393 !pa_tagstruct_eof(t
)) {
394 pa_context_fail(c
, PA_ERR_PROTOCOL
);
398 if (!(s
= pa_dynarray_get(c
->playback_streams
, channel
)))
401 if (s
->state
== PA_STREAM_READY
) {
402 s
->requested_bytes
+= bytes
;
404 if (s
->requested_bytes
> 0 && s
->write_callback
)
405 s
->write_callback(s
, s
->requested_bytes
, s
->write_userdata
);
412 void pa_command_overflow_or_underflow(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
414 pa_context
*c
= userdata
;
418 pa_assert(command
== PA_COMMAND_OVERFLOW
|| command
== PA_COMMAND_UNDERFLOW
);
421 pa_assert(PA_REFCNT_VALUE(c
) >= 1);
425 if (pa_tagstruct_getu32(t
, &channel
) < 0 ||
426 !pa_tagstruct_eof(t
)) {
427 pa_context_fail(c
, PA_ERR_PROTOCOL
);
431 if (!(s
= pa_dynarray_get(c
->playback_streams
, channel
)))
434 if (s
->state
== PA_STREAM_READY
) {
436 if (command
== PA_COMMAND_OVERFLOW
) {
437 if (s
->overflow_callback
)
438 s
->overflow_callback(s
, s
->overflow_userdata
);
439 } else if (command
== PA_COMMAND_UNDERFLOW
) {
440 if (s
->underflow_callback
)
441 s
->underflow_callback(s
, s
->underflow_userdata
);
449 static void request_auto_timing_update(pa_stream
*s
, int force
) {
451 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
453 if (!(s
->flags
& PA_STREAM_AUTO_TIMING_UPDATE
))
456 if (s
->state
== PA_STREAM_READY
&&
457 (force
|| !s
->auto_timing_update_requested
)) {
460 /* pa_log("automatically requesting new timing data"); */
462 if ((o
= pa_stream_update_timing_info(s
, NULL
, NULL
))) {
463 pa_operation_unref(o
);
464 s
->auto_timing_update_requested
= TRUE
;
468 if (s
->auto_timing_update_event
) {
470 pa_gettimeofday(&next
);
471 pa_timeval_add(&next
, LATENCY_IPOL_INTERVAL_USEC
);
472 s
->mainloop
->time_restart(s
->auto_timing_update_event
, &next
);
476 static void invalidate_indexes(pa_stream
*s
, int r
, int w
) {
478 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
480 /* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */
482 if (s
->state
!= PA_STREAM_READY
)
486 s
->write_index_not_before
= s
->context
->ctag
;
488 if (s
->timing_info_valid
)
489 s
->timing_info
.write_index_corrupt
= 1;
491 /* pa_log("write_index invalidated"); */
495 s
->read_index_not_before
= s
->context
->ctag
;
497 if (s
->timing_info_valid
)
498 s
->timing_info
.read_index_corrupt
= 1;
500 /* pa_log("read_index invalidated"); */
503 if ((s
->direction
== PA_STREAM_PLAYBACK
&& r
) ||
504 (s
->direction
== PA_STREAM_RECORD
&& w
))
505 s
->cached_time_valid
= 0;
507 request_auto_timing_update(s
, 1);
510 static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api
*m
, PA_GCC_UNUSED pa_time_event
*e
, PA_GCC_UNUSED
const struct timeval
*tv
, void *userdata
) {
511 pa_stream
*s
= userdata
;
514 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
516 /* pa_log("time event"); */
519 request_auto_timing_update(s
, 0);
523 static void create_stream_complete(pa_stream
*s
) {
525 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
526 pa_assert(s
->state
== PA_STREAM_CREATING
);
528 pa_stream_set_state(s
, PA_STREAM_READY
);
530 if (s
->requested_bytes
> 0 && s
->write_callback
)
531 s
->write_callback(s
, s
->requested_bytes
, s
->write_userdata
);
533 if (s
->flags
& PA_STREAM_AUTO_TIMING_UPDATE
) {
535 pa_gettimeofday(&tv
);
536 tv
.tv_usec
+= LATENCY_IPOL_INTERVAL_USEC
; /* every 100 ms */
537 pa_assert(!s
->auto_timing_update_event
);
538 s
->auto_timing_update_event
= s
->mainloop
->time_new(s
->mainloop
, &tv
, &auto_timing_update_callback
, s
);
542 static void automatic_buffer_attr(pa_stream
*s
, pa_buffer_attr
*attr
, const pa_sample_spec
*ss
) {
547 if (s
->context
->version
>= 13)
550 /* Version older than 0.9.10 didn't do server side buffer_attr
551 * selection, hence we have to fake it on the client side */
553 if (!attr
->maxlength
<= 0)
554 attr
->maxlength
= 4*1024*1024; /* 4MB is the maximum queue length PulseAudio <= 0.9.9 supported. */
556 if (!attr
->tlength
<= 0)
557 attr
->tlength
= pa_bytes_per_second(ss
)*2; /* 2s of buffering */
559 if (!attr
->minreq
<= 0)
560 attr
->minreq
= (2*attr
->tlength
)/10; /* Ask for more data when there are only 200ms left in the playback buffer */
563 attr
->prebuf
= attr
->tlength
; /* Start to play only when the playback is fully filled up once */
566 attr
->fragsize
= attr
->tlength
; /* Pass data to the app only when the buffer is filled up once */
569 void pa_create_stream_callback(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
570 pa_stream
*s
= userdata
;
574 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
575 pa_assert(s
->state
== PA_STREAM_CREATING
);
579 if (command
!= PA_COMMAND_REPLY
) {
580 if (pa_context_handle_error(s
->context
, command
, t
) < 0)
583 pa_stream_set_state(s
, PA_STREAM_FAILED
);
587 if (pa_tagstruct_getu32(t
, &s
->channel
) < 0 ||
588 ((s
->direction
!= PA_STREAM_UPLOAD
) && pa_tagstruct_getu32(t
, &s
->stream_index
) < 0) ||
589 ((s
->direction
!= PA_STREAM_RECORD
) && pa_tagstruct_getu32(t
, &s
->requested_bytes
) < 0)) {
590 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
594 if (s
->context
->version
>= 9) {
595 if (s
->direction
== PA_STREAM_PLAYBACK
) {
596 if (pa_tagstruct_getu32(t
, &s
->buffer_attr
.maxlength
) < 0 ||
597 pa_tagstruct_getu32(t
, &s
->buffer_attr
.tlength
) < 0 ||
598 pa_tagstruct_getu32(t
, &s
->buffer_attr
.prebuf
) < 0 ||
599 pa_tagstruct_getu32(t
, &s
->buffer_attr
.minreq
) < 0) {
600 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
603 } else if (s
->direction
== PA_STREAM_RECORD
) {
604 if (pa_tagstruct_getu32(t
, &s
->buffer_attr
.maxlength
) < 0 ||
605 pa_tagstruct_getu32(t
, &s
->buffer_attr
.fragsize
) < 0) {
606 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
612 if (s
->context
->version
>= 12 && s
->direction
!= PA_STREAM_UPLOAD
) {
615 const char *dn
= NULL
;
618 if (pa_tagstruct_get_sample_spec(t
, &ss
) < 0 ||
619 pa_tagstruct_get_channel_map(t
, &cm
) < 0 ||
620 pa_tagstruct_getu32(t
, &s
->device_index
) < 0 ||
621 pa_tagstruct_gets(t
, &dn
) < 0 ||
622 pa_tagstruct_get_boolean(t
, &suspended
) < 0) {
623 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
627 if (!dn
|| s
->device_index
== PA_INVALID_INDEX
||
628 ss
.channels
!= cm
.channels
||
629 !pa_channel_map_valid(&cm
) ||
630 !pa_sample_spec_valid(&ss
) ||
631 (!(s
->flags
& PA_STREAM_FIX_FORMAT
) && ss
.format
!= s
->sample_spec
.format
) ||
632 (!(s
->flags
& PA_STREAM_FIX_RATE
) && ss
.rate
!= s
->sample_spec
.rate
) ||
633 (!(s
->flags
& PA_STREAM_FIX_CHANNELS
) && !pa_channel_map_equal(&cm
, &s
->channel_map
))) {
634 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
638 pa_xfree(s
->device_name
);
639 s
->device_name
= pa_xstrdup(dn
);
640 s
->suspended
= suspended
;
646 if (s
->context
->version
>= 13 && s
->direction
!= PA_STREAM_UPLOAD
) {
649 if (pa_tagstruct_get_usec(t
, &usec
) < 0) {
650 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
654 if (s
->direction
== PA_STREAM_RECORD
)
655 s
->timing_info
.configured_source_usec
= usec
;
657 s
->timing_info
.configured_sink_usec
= usec
;
660 if (!pa_tagstruct_eof(t
)) {
661 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
665 if (s
->direction
== PA_STREAM_RECORD
) {
666 pa_assert(!s
->record_memblockq
);
668 s
->record_memblockq
= pa_memblockq_new(
670 s
->buffer_attr
.maxlength
,
672 pa_frame_size(&s
->sample_spec
),
679 s
->channel_valid
= 1;
680 pa_dynarray_put((s
->direction
== PA_STREAM_RECORD
) ? s
->context
->record_streams
: s
->context
->playback_streams
, s
->channel
, s
);
682 create_stream_complete(s
);
688 static int create_stream(
689 pa_stream_direction_t direction
,
692 const pa_buffer_attr
*attr
,
693 pa_stream_flags_t flags
,
694 const pa_cvolume
*volume
,
695 pa_stream
*sync_stream
) {
701 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
702 pa_assert(direction
== PA_STREAM_PLAYBACK
|| direction
== PA_STREAM_RECORD
);
704 PA_CHECK_VALIDITY(s
->context
, s
->state
== PA_STREAM_UNCONNECTED
, PA_ERR_BADSTATE
);
705 PA_CHECK_VALIDITY(s
->context
, !(flags
& ~(PA_STREAM_START_CORKED
|
706 PA_STREAM_INTERPOLATE_TIMING
|
707 PA_STREAM_NOT_MONOTONOUS
|
708 PA_STREAM_AUTO_TIMING_UPDATE
|
709 PA_STREAM_NO_REMAP_CHANNELS
|
710 PA_STREAM_NO_REMIX_CHANNELS
|
711 PA_STREAM_FIX_FORMAT
|
713 PA_STREAM_FIX_CHANNELS
|
715 PA_STREAM_VARIABLE_RATE
|
716 PA_STREAM_PEAK_DETECT
|
717 PA_STREAM_START_MUTED
|
718 PA_STREAM_ADJUST_LATENCY
)), PA_ERR_INVALID
);
720 PA_CHECK_VALIDITY(s
->context
, s
->context
->version
>= 12 || !(flags
& PA_STREAM_VARIABLE_RATE
), PA_ERR_NOTSUPPORTED
);
721 PA_CHECK_VALIDITY(s
->context
, s
->context
->version
>= 13 || !(flags
& PA_STREAM_PEAK_DETECT
), PA_ERR_NOTSUPPORTED
);
722 /* Althought some of the other flags are not supported on older
723 * version, we don't check for them here, because it doesn't hurt
724 * when they are passed but actually not supported. This makes
725 * client development easier */
727 PA_CHECK_VALIDITY(s
->context
, direction
!= PA_STREAM_PLAYBACK
|| !(flags
& (PA_STREAM_START_MUTED
)), PA_ERR_INVALID
);
728 PA_CHECK_VALIDITY(s
->context
, direction
!= PA_STREAM_RECORD
|| !(flags
& (PA_STREAM_PEAK_DETECT
)), PA_ERR_INVALID
);
729 PA_CHECK_VALIDITY(s
->context
, !volume
|| volume
->channels
== s
->sample_spec
.channels
, PA_ERR_INVALID
);
730 PA_CHECK_VALIDITY(s
->context
, !sync_stream
|| (direction
== PA_STREAM_PLAYBACK
&& sync_stream
->direction
== PA_STREAM_PLAYBACK
), PA_ERR_INVALID
);
734 s
->direction
= direction
;
738 s
->syncid
= sync_stream
->syncid
;
741 s
->buffer_attr
= *attr
;
742 s
->manual_buffer_attr
= TRUE
;
744 memset(&s
->buffer_attr
, 0, sizeof(s
->buffer_attr
));
745 s
->manual_buffer_attr
= FALSE
;
748 automatic_buffer_attr(s
, &s
->buffer_attr
, &s
->sample_spec
);
751 dev
= s
->direction
== PA_STREAM_PLAYBACK
? s
->context
->conf
->default_sink
: s
->context
->conf
->default_source
;
753 t
= pa_tagstruct_command(
755 s
->direction
== PA_STREAM_PLAYBACK
? PA_COMMAND_CREATE_PLAYBACK_STREAM
: PA_COMMAND_CREATE_RECORD_STREAM
,
758 if (s
->context
->version
< 13)
759 pa_tagstruct_puts(t
, pa_proplist_gets(s
->proplist
, PA_PROP_MEDIA_NAME
));
763 PA_TAG_SAMPLE_SPEC
, &s
->sample_spec
,
764 PA_TAG_CHANNEL_MAP
, &s
->channel_map
,
765 PA_TAG_U32
, PA_INVALID_INDEX
,
767 PA_TAG_U32
, s
->buffer_attr
.maxlength
,
768 PA_TAG_BOOLEAN
, !!(flags
& PA_STREAM_START_CORKED
),
771 if (s
->direction
== PA_STREAM_PLAYBACK
) {
776 PA_TAG_U32
, s
->buffer_attr
.tlength
,
777 PA_TAG_U32
, s
->buffer_attr
.prebuf
,
778 PA_TAG_U32
, s
->buffer_attr
.minreq
,
779 PA_TAG_U32
, s
->syncid
,
783 volume
= pa_cvolume_reset(&cv
, s
->sample_spec
.channels
);
785 pa_tagstruct_put_cvolume(t
, volume
);
787 pa_tagstruct_putu32(t
, s
->buffer_attr
.fragsize
);
789 if (s
->context
->version
>= 12) {
792 PA_TAG_BOOLEAN
, flags
& PA_STREAM_NO_REMAP_CHANNELS
,
793 PA_TAG_BOOLEAN
, flags
& PA_STREAM_NO_REMIX_CHANNELS
,
794 PA_TAG_BOOLEAN
, flags
& PA_STREAM_FIX_FORMAT
,
795 PA_TAG_BOOLEAN
, flags
& PA_STREAM_FIX_RATE
,
796 PA_TAG_BOOLEAN
, flags
& PA_STREAM_FIX_CHANNELS
,
797 PA_TAG_BOOLEAN
, flags
& PA_STREAM_DONT_MOVE
,
798 PA_TAG_BOOLEAN
, flags
& PA_STREAM_VARIABLE_RATE
,
802 if (s
->context
->version
>= 13) {
804 if (s
->direction
== PA_STREAM_PLAYBACK
)
805 pa_tagstruct_put_boolean(t
, flags
& PA_STREAM_START_MUTED
);
807 pa_tagstruct_put_boolean(t
, flags
& PA_STREAM_PEAK_DETECT
);
811 PA_TAG_BOOLEAN
, flags
& PA_STREAM_ADJUST_LATENCY
,
812 PA_TAG_PROPLIST
, s
->proplist
,
816 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
817 pa_pdispatch_register_reply(s
->context
->pdispatch
, tag
, DEFAULT_TIMEOUT
, pa_create_stream_callback
, s
, NULL
);
819 pa_stream_set_state(s
, PA_STREAM_CREATING
);
825 int pa_stream_connect_playback(
828 const pa_buffer_attr
*attr
,
829 pa_stream_flags_t flags
,
831 pa_stream
*sync_stream
) {
834 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
836 return create_stream(PA_STREAM_PLAYBACK
, s
, dev
, attr
, flags
, volume
, sync_stream
);
839 int pa_stream_connect_record(
842 const pa_buffer_attr
*attr
,
843 pa_stream_flags_t flags
) {
846 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
848 return create_stream(PA_STREAM_RECORD
, s
, dev
, attr
, flags
, NULL
, NULL
);
855 void (*free_cb
)(void *p
),
857 pa_seek_mode_t seek
) {
860 pa_seek_mode_t t_seek
;
866 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
869 PA_CHECK_VALIDITY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
870 PA_CHECK_VALIDITY(s
->context
, s
->direction
== PA_STREAM_PLAYBACK
|| s
->direction
== PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
871 PA_CHECK_VALIDITY(s
->context
, seek
<= PA_SEEK_RELATIVE_END
, PA_ERR_INVALID
);
872 PA_CHECK_VALIDITY(s
->context
, s
->direction
== PA_STREAM_PLAYBACK
|| (seek
== PA_SEEK_RELATIVE
&& offset
== 0), PA_ERR_INVALID
);
882 while (t_length
> 0) {
886 if (free_cb
&& !pa_pstream_get_shm(s
->context
->pstream
)) {
887 chunk
.memblock
= pa_memblock_new_user(s
->context
->mempool
, (void*) t_data
, t_length
, free_cb
, 1);
888 chunk
.length
= t_length
;
892 chunk
.length
= PA_MIN(t_length
, pa_mempool_block_size_max(s
->context
->mempool
));
893 chunk
.memblock
= pa_memblock_new(s
->context
->mempool
, chunk
.length
);
895 d
= pa_memblock_acquire(chunk
.memblock
);
896 memcpy(d
, t_data
, chunk
.length
);
897 pa_memblock_release(chunk
.memblock
);
900 pa_pstream_send_memblock(s
->context
->pstream
, s
->channel
, t_offset
, t_seek
, &chunk
);
903 t_seek
= PA_SEEK_RELATIVE
;
905 t_data
= (const uint8_t*) t_data
+ chunk
.length
;
906 t_length
-= chunk
.length
;
908 pa_memblock_unref(chunk
.memblock
);
911 if (free_cb
&& pa_pstream_get_shm(s
->context
->pstream
))
912 free_cb((void*) data
);
914 if (length
< s
->requested_bytes
)
915 s
->requested_bytes
-= length
;
917 s
->requested_bytes
= 0;
919 if (s
->direction
== PA_STREAM_PLAYBACK
) {
921 /* Update latency request correction */
922 if (s
->write_index_corrections
[s
->current_write_index_correction
].valid
) {
924 if (seek
== PA_SEEK_ABSOLUTE
) {
925 s
->write_index_corrections
[s
->current_write_index_correction
].corrupt
= 0;
926 s
->write_index_corrections
[s
->current_write_index_correction
].absolute
= 1;
927 s
->write_index_corrections
[s
->current_write_index_correction
].value
= offset
+ length
;
928 } else if (seek
== PA_SEEK_RELATIVE
) {
929 if (!s
->write_index_corrections
[s
->current_write_index_correction
].corrupt
)
930 s
->write_index_corrections
[s
->current_write_index_correction
].value
+= offset
+ length
;
932 s
->write_index_corrections
[s
->current_write_index_correction
].corrupt
= 1;
935 /* Update the write index in the already available latency data */
936 if (s
->timing_info_valid
) {
938 if (seek
== PA_SEEK_ABSOLUTE
) {
939 s
->timing_info
.write_index_corrupt
= 0;
940 s
->timing_info
.write_index
= offset
+ length
;
941 } else if (seek
== PA_SEEK_RELATIVE
) {
942 if (!s
->timing_info
.write_index_corrupt
)
943 s
->timing_info
.write_index
+= offset
+ length
;
945 s
->timing_info
.write_index_corrupt
= 1;
948 if (!s
->timing_info_valid
|| s
->timing_info
.write_index_corrupt
)
949 request_auto_timing_update(s
, 1);
955 int pa_stream_peek(pa_stream
*s
, const void **data
, size_t *length
) {
957 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
961 PA_CHECK_VALIDITY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
962 PA_CHECK_VALIDITY(s
->context
, s
->direction
== PA_STREAM_RECORD
, PA_ERR_BADSTATE
);
964 if (!s
->peek_memchunk
.memblock
) {
966 if (pa_memblockq_peek(s
->record_memblockq
, &s
->peek_memchunk
) < 0) {
972 s
->peek_data
= pa_memblock_acquire(s
->peek_memchunk
.memblock
);
975 pa_assert(s
->peek_data
);
976 *data
= (uint8_t*) s
->peek_data
+ s
->peek_memchunk
.index
;
977 *length
= s
->peek_memchunk
.length
;
981 int pa_stream_drop(pa_stream
*s
) {
983 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
985 PA_CHECK_VALIDITY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
986 PA_CHECK_VALIDITY(s
->context
, s
->direction
== PA_STREAM_RECORD
, PA_ERR_BADSTATE
);
987 PA_CHECK_VALIDITY(s
->context
, s
->peek_memchunk
.memblock
, PA_ERR_BADSTATE
);
989 pa_memblockq_drop(s
->record_memblockq
, s
->peek_memchunk
.length
);
991 /* Fix the simulated local read index */
992 if (s
->timing_info_valid
&& !s
->timing_info
.read_index_corrupt
)
993 s
->timing_info
.read_index
+= s
->peek_memchunk
.length
;
995 pa_assert(s
->peek_data
);
996 pa_memblock_release(s
->peek_memchunk
.memblock
);
997 pa_memblock_unref(s
->peek_memchunk
.memblock
);
998 s
->peek_memchunk
.length
= 0;
999 s
->peek_memchunk
.index
= 0;
1000 s
->peek_memchunk
.memblock
= NULL
;
1005 size_t pa_stream_writable_size(pa_stream
*s
) {
1007 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1009 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
, (size_t) -1);
1010 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->direction
!= PA_STREAM_RECORD
, PA_ERR_BADSTATE
, (size_t) -1);
1012 return s
->requested_bytes
;
1015 size_t pa_stream_readable_size(pa_stream
*s
) {
1017 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1019 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
, (size_t) -1);
1020 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->direction
== PA_STREAM_RECORD
, PA_ERR_BADSTATE
, (size_t) -1);
1022 return pa_memblockq_get_length(s
->record_memblockq
);
1025 pa_operation
* pa_stream_drain(pa_stream
*s
, pa_stream_success_cb_t cb
, void *userdata
) {
1031 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1033 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1034 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
== PA_STREAM_PLAYBACK
, PA_ERR_BADSTATE
);
1036 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1038 t
= pa_tagstruct_command(s
->context
, PA_COMMAND_DRAIN_PLAYBACK_STREAM
, &tag
);
1039 pa_tagstruct_putu32(t
, s
->channel
);
1040 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1041 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
);
1046 static void stream_get_timing_info_callback(pa_pdispatch
*pd
, uint32_t command
, uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1047 pa_operation
*o
= userdata
;
1048 struct timeval local
, remote
, now
;
1050 pa_bool_t playing
= FALSE
;
1054 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
1056 if (!o
->context
|| !o
->stream
)
1059 i
= &o
->stream
->timing_info
;
1061 /* pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); */
1063 o
->stream
->timing_info_valid
= FALSE
;
1064 i
->write_index_corrupt
= 0;
1065 i
->read_index_corrupt
= 0;
1067 /* pa_log("timing update %u\n", tag); */
1069 if (command
!= PA_COMMAND_REPLY
) {
1070 if (pa_context_handle_error(o
->context
, command
, t
) < 0)
1073 } else if (pa_tagstruct_get_usec(t
, &i
->sink_usec
) < 0 ||
1074 pa_tagstruct_get_usec(t
, &i
->source_usec
) < 0 ||
1075 pa_tagstruct_get_boolean(t
, &playing
) < 0 ||
1076 pa_tagstruct_get_timeval(t
, &local
) < 0 ||
1077 pa_tagstruct_get_timeval(t
, &remote
) < 0 ||
1078 pa_tagstruct_gets64(t
, &i
->write_index
) < 0 ||
1079 pa_tagstruct_gets64(t
, &i
->read_index
) < 0 ||
1080 !pa_tagstruct_eof(t
)) {
1081 pa_context_fail(o
->context
, PA_ERR_PROTOCOL
);
1085 o
->stream
->timing_info_valid
= 1;
1086 i
->playing
= (int) playing
;
1088 pa_gettimeofday(&now
);
1090 /* Calculcate timestamps */
1091 if (pa_timeval_cmp(&local
, &remote
) <= 0 && pa_timeval_cmp(&remote
, &now
) <= 0) {
1092 /* local and remote seem to have synchronized clocks */
1094 if (o
->stream
->direction
== PA_STREAM_PLAYBACK
)
1095 i
->transport_usec
= pa_timeval_diff(&remote
, &local
);
1097 i
->transport_usec
= pa_timeval_diff(&now
, &remote
);
1099 i
->synchronized_clocks
= 1;
1100 i
->timestamp
= remote
;
1102 /* clocks are not synchronized, let's estimate latency then */
1103 i
->transport_usec
= pa_timeval_diff(&now
, &local
)/2;
1104 i
->synchronized_clocks
= 0;
1105 i
->timestamp
= local
;
1106 pa_timeval_add(&i
->timestamp
, i
->transport_usec
);
1109 /* Invalidate read and write indexes if necessary */
1110 if (tag
< o
->stream
->read_index_not_before
)
1111 i
->read_index_corrupt
= 1;
1113 if (tag
< o
->stream
->write_index_not_before
)
1114 i
->write_index_corrupt
= 1;
1116 if (o
->stream
->direction
== PA_STREAM_PLAYBACK
) {
1117 /* Write index correction */
1120 uint32_t ctag
= tag
;
1122 /* Go through the saved correction values and add up the total correction.*/
1124 for (n
= 0, j
= o
->stream
->current_write_index_correction
+1;
1125 n
< PA_MAX_WRITE_INDEX_CORRECTIONS
;
1126 n
++, j
= (j
+ 1) % PA_MAX_WRITE_INDEX_CORRECTIONS
) {
1128 /* Step over invalid data or out-of-date data */
1129 if (!o
->stream
->write_index_corrections
[j
].valid
||
1130 o
->stream
->write_index_corrections
[j
].tag
< ctag
)
1133 /* Make sure that everything is in order */
1134 ctag
= o
->stream
->write_index_corrections
[j
].tag
+1;
1136 /* Now fix the write index */
1137 if (o
->stream
->write_index_corrections
[j
].corrupt
) {
1138 /* A corrupting seek was made */
1140 i
->write_index_corrupt
= 1;
1141 } else if (o
->stream
->write_index_corrections
[j
].absolute
) {
1142 /* An absolute seek was made */
1143 i
->write_index
= o
->stream
->write_index_corrections
[j
].value
;
1144 i
->write_index_corrupt
= 0;
1145 } else if (!i
->write_index_corrupt
) {
1146 /* A relative seek was made */
1147 i
->write_index
+= o
->stream
->write_index_corrections
[j
].value
;
1152 if (o
->stream
->direction
== PA_STREAM_RECORD
) {
1153 /* Read index correction */
1155 if (!i
->read_index_corrupt
)
1156 i
->read_index
-= pa_memblockq_get_length(o
->stream
->record_memblockq
);
1159 o
->stream
->cached_time_valid
= 0;
1162 o
->stream
->auto_timing_update_requested
= 0;
1163 /* pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); */
1165 /* Clear old correction entries */
1166 if (o
->stream
->direction
== PA_STREAM_PLAYBACK
) {
1169 for (n
= 0; n
< PA_MAX_WRITE_INDEX_CORRECTIONS
; n
++) {
1170 if (!o
->stream
->write_index_corrections
[n
].valid
)
1173 if (o
->stream
->write_index_corrections
[n
].tag
<= tag
)
1174 o
->stream
->write_index_corrections
[n
].valid
= 0;
1178 if (o
->stream
->latency_update_callback
)
1179 o
->stream
->latency_update_callback(o
->stream
, o
->stream
->latency_update_userdata
);
1181 if (o
->callback
&& o
->stream
&& o
->stream
->state
== PA_STREAM_READY
) {
1182 pa_stream_success_cb_t cb
= (pa_stream_success_cb_t
) o
->callback
;
1183 cb(o
->stream
, o
->stream
->timing_info_valid
, o
->userdata
);
1188 pa_operation_done(o
);
1189 pa_operation_unref(o
);
1192 pa_operation
* pa_stream_update_timing_info(pa_stream
*s
, pa_stream_success_cb_t cb
, void *userdata
) {
1200 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1202 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1203 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1205 if (s
->direction
== PA_STREAM_PLAYBACK
) {
1206 /* Find a place to store the write_index correction data for this entry */
1207 cidx
= (s
->current_write_index_correction
+ 1) % PA_MAX_WRITE_INDEX_CORRECTIONS
;
1209 /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */
1210 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, !s
->write_index_corrections
[cidx
].valid
, PA_ERR_INTERNAL
);
1212 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1214 t
= pa_tagstruct_command(
1216 s
->direction
== PA_STREAM_PLAYBACK
? PA_COMMAND_GET_PLAYBACK_LATENCY
: PA_COMMAND_GET_RECORD_LATENCY
,
1218 pa_tagstruct_putu32(t
, s
->channel
);
1219 pa_tagstruct_put_timeval(t
, pa_gettimeofday(&now
));
1221 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1222 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
);
1224 if (s
->direction
== PA_STREAM_PLAYBACK
) {
1225 /* Fill in initial correction data */
1226 o
->stream
->current_write_index_correction
= cidx
;
1227 o
->stream
->write_index_corrections
[cidx
].valid
= 1;
1228 o
->stream
->write_index_corrections
[cidx
].tag
= tag
;
1229 o
->stream
->write_index_corrections
[cidx
].absolute
= 0;
1230 o
->stream
->write_index_corrections
[cidx
].value
= 0;
1231 o
->stream
->write_index_corrections
[cidx
].corrupt
= 0;
1234 /* pa_log("requesting update %u\n", tag); */
1239 void pa_stream_disconnect_callback(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1240 pa_stream
*s
= userdata
;
1244 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1248 if (command
!= PA_COMMAND_REPLY
) {
1249 if (pa_context_handle_error(s
->context
, command
, t
) < 0)
1252 pa_stream_set_state(s
, PA_STREAM_FAILED
);
1254 } else if (!pa_tagstruct_eof(t
)) {
1255 pa_context_fail(s
->context
, PA_ERR_PROTOCOL
);
1259 pa_stream_set_state(s
, PA_STREAM_TERMINATED
);
1265 int pa_stream_disconnect(pa_stream
*s
) {
1270 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1272 PA_CHECK_VALIDITY(s
->context
, s
->channel_valid
, PA_ERR_BADSTATE
);
1273 PA_CHECK_VALIDITY(s
->context
, s
->context
->state
== PA_CONTEXT_READY
, PA_ERR_BADSTATE
);
1277 t
= pa_tagstruct_command(
1279 s
->direction
== PA_STREAM_PLAYBACK
? PA_COMMAND_DELETE_PLAYBACK_STREAM
:
1280 (s
->direction
== PA_STREAM_RECORD
? PA_COMMAND_DELETE_RECORD_STREAM
: PA_COMMAND_DELETE_UPLOAD_STREAM
),
1282 pa_tagstruct_putu32(t
, s
->channel
);
1283 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1284 pa_pdispatch_register_reply(s
->context
->pdispatch
, tag
, DEFAULT_TIMEOUT
, pa_stream_disconnect_callback
, s
, NULL
);
1290 void pa_stream_set_read_callback(pa_stream
*s
, pa_stream_request_cb_t cb
, void *userdata
) {
1292 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1294 s
->read_callback
= cb
;
1295 s
->read_userdata
= userdata
;
1298 void pa_stream_set_write_callback(pa_stream
*s
, pa_stream_request_cb_t cb
, void *userdata
) {
1300 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1302 s
->write_callback
= cb
;
1303 s
->write_userdata
= userdata
;
1306 void pa_stream_set_state_callback(pa_stream
*s
, pa_stream_notify_cb_t cb
, void *userdata
) {
1308 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1310 s
->state_callback
= cb
;
1311 s
->state_userdata
= userdata
;
1314 void pa_stream_set_overflow_callback(pa_stream
*s
, pa_stream_notify_cb_t cb
, void *userdata
) {
1316 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1318 s
->overflow_callback
= cb
;
1319 s
->overflow_userdata
= userdata
;
1322 void pa_stream_set_underflow_callback(pa_stream
*s
, pa_stream_notify_cb_t cb
, void *userdata
) {
1324 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1326 s
->underflow_callback
= cb
;
1327 s
->underflow_userdata
= userdata
;
1330 void pa_stream_set_latency_update_callback(pa_stream
*s
, pa_stream_notify_cb_t cb
, void *userdata
) {
1332 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1334 s
->latency_update_callback
= cb
;
1335 s
->latency_update_userdata
= userdata
;
1338 void pa_stream_set_moved_callback(pa_stream
*s
, pa_stream_notify_cb_t cb
, void *userdata
) {
1340 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1342 s
->moved_callback
= cb
;
1343 s
->moved_userdata
= userdata
;
1346 void pa_stream_set_suspended_callback(pa_stream
*s
, pa_stream_notify_cb_t cb
, void *userdata
) {
1348 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1350 s
->suspended_callback
= cb
;
1351 s
->suspended_userdata
= userdata
;
1354 void pa_stream_simple_ack_callback(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1355 pa_operation
*o
= userdata
;
1360 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
1365 if (command
!= PA_COMMAND_REPLY
) {
1366 if (pa_context_handle_error(o
->context
, command
, t
) < 0)
1370 } else if (!pa_tagstruct_eof(t
)) {
1371 pa_context_fail(o
->context
, PA_ERR_PROTOCOL
);
1376 pa_stream_success_cb_t cb
= (pa_stream_success_cb_t
) o
->callback
;
1377 cb(o
->stream
, success
, o
->userdata
);
1381 pa_operation_done(o
);
1382 pa_operation_unref(o
);
1385 pa_operation
* pa_stream_cork(pa_stream
*s
, int b
, pa_stream_success_cb_t cb
, void *userdata
) {
1391 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1393 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1394 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1398 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1400 t
= pa_tagstruct_command(
1402 s
->direction
== PA_STREAM_PLAYBACK
? PA_COMMAND_CORK_PLAYBACK_STREAM
: PA_COMMAND_CORK_RECORD_STREAM
,
1404 pa_tagstruct_putu32(t
, s
->channel
);
1405 pa_tagstruct_put_boolean(t
, !!b
);
1406 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1407 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
);
1409 if (s
->direction
== PA_STREAM_PLAYBACK
)
1410 invalidate_indexes(s
, 1, 0);
1415 static pa_operation
* stream_send_simple_command(pa_stream
*s
, uint32_t command
, pa_stream_success_cb_t cb
, void *userdata
) {
1421 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1423 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1425 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1427 t
= pa_tagstruct_command(s
->context
, command
, &tag
);
1428 pa_tagstruct_putu32(t
, s
->channel
);
1429 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1430 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
);
1435 pa_operation
* pa_stream_flush(pa_stream
*s
, pa_stream_success_cb_t cb
, void *userdata
) {
1439 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1441 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1443 if ((o
= stream_send_simple_command(s
, s
->direction
== PA_STREAM_PLAYBACK
? PA_COMMAND_FLUSH_PLAYBACK_STREAM
: PA_COMMAND_FLUSH_RECORD_STREAM
, cb
, userdata
))) {
1445 if (s
->direction
== PA_STREAM_PLAYBACK
) {
1446 if (s
->write_index_corrections
[s
->current_write_index_correction
].valid
)
1447 s
->write_index_corrections
[s
->current_write_index_correction
].corrupt
= 1;
1449 if (s
->timing_info_valid
)
1450 s
->timing_info
.write_index_corrupt
= 1;
1452 if (s
->buffer_attr
.prebuf
> 0)
1453 invalidate_indexes(s
, 1, 0);
1455 request_auto_timing_update(s
, 1);
1457 invalidate_indexes(s
, 0, 1);
1463 pa_operation
* pa_stream_prebuf(pa_stream
*s
, pa_stream_success_cb_t cb
, void *userdata
) {
1467 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1469 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
== PA_STREAM_PLAYBACK
, PA_ERR_BADSTATE
);
1470 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->buffer_attr
.prebuf
> 0, PA_ERR_BADSTATE
);
1472 if ((o
= stream_send_simple_command(s
, PA_COMMAND_PREBUF_PLAYBACK_STREAM
, cb
, userdata
)))
1473 invalidate_indexes(s
, 1, 0);
1478 pa_operation
* pa_stream_trigger(pa_stream
*s
, pa_stream_success_cb_t cb
, void *userdata
) {
1482 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1484 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
== PA_STREAM_PLAYBACK
, PA_ERR_BADSTATE
);
1485 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->buffer_attr
.prebuf
> 0, PA_ERR_BADSTATE
);
1487 if ((o
= stream_send_simple_command(s
, PA_COMMAND_TRIGGER_PLAYBACK_STREAM
, cb
, userdata
)))
1488 invalidate_indexes(s
, 1, 0);
1493 pa_operation
* pa_stream_set_name(pa_stream
*s
, const char *name
, pa_stream_success_cb_t cb
, void *userdata
) {
1499 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1502 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1503 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1505 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1507 t
= pa_tagstruct_command(
1509 s
->direction
== PA_STREAM_RECORD
? PA_COMMAND_SET_RECORD_STREAM_NAME
: PA_COMMAND_SET_PLAYBACK_STREAM_NAME
,
1511 pa_tagstruct_putu32(t
, s
->channel
);
1512 pa_tagstruct_puts(t
, name
);
1513 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1514 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
);
1519 int pa_stream_get_time(pa_stream
*s
, pa_usec_t
*r_usec
) {
1523 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1525 PA_CHECK_VALIDITY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1526 PA_CHECK_VALIDITY(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1527 PA_CHECK_VALIDITY(s
->context
, s
->timing_info_valid
, PA_ERR_NODATA
);
1528 PA_CHECK_VALIDITY(s
->context
, s
->direction
!= PA_STREAM_PLAYBACK
|| !s
->timing_info
.read_index_corrupt
, PA_ERR_NODATA
);
1529 PA_CHECK_VALIDITY(s
->context
, s
->direction
!= PA_STREAM_RECORD
|| !s
->timing_info
.write_index_corrupt
, PA_ERR_NODATA
);
1531 if (s
->cached_time_valid
)
1532 /* We alredy calculated the time value for this timing info, so let's reuse it */
1533 usec
= s
->cached_time
;
1535 if (s
->direction
== PA_STREAM_PLAYBACK
) {
1536 /* The last byte that was written into the output device
1537 * had this time value associated */
1538 usec
= pa_bytes_to_usec(s
->timing_info
.read_index
< 0 ? 0 : (uint64_t) s
->timing_info
.read_index
, &s
->sample_spec
);
1541 /* Because the latency info took a little time to come
1542 * to us, we assume that the real output time is actually
1544 usec
+= s
->timing_info
.transport_usec
;
1546 /* However, the output device usually maintains a buffer
1547 too, hence the real sample currently played is a little
1549 if (s
->timing_info
.sink_usec
>= usec
)
1552 usec
-= s
->timing_info
.sink_usec
;
1555 } else if (s
->direction
== PA_STREAM_RECORD
) {
1556 /* The last byte written into the server side queue had
1557 * this time value associated */
1558 usec
= pa_bytes_to_usec(s
->timing_info
.write_index
< 0 ? 0 : (uint64_t) s
->timing_info
.write_index
, &s
->sample_spec
);
1561 /* Add transport latency */
1562 usec
+= s
->timing_info
.transport_usec
;
1564 /* Add latency of data in device buffer */
1565 usec
+= s
->timing_info
.source_usec
;
1567 /* If this is a monitor source, we need to correct the
1568 * time by the playback device buffer */
1569 if (s
->timing_info
.sink_usec
>= usec
)
1572 usec
-= s
->timing_info
.sink_usec
;
1576 s
->cached_time
= usec
;
1577 s
->cached_time_valid
= 1;
1580 /* Interpolate if requested */
1581 if (s
->flags
& PA_STREAM_INTERPOLATE_TIMING
) {
1583 /* We just add the time that passed since the latency info was
1585 if (!s
->corked
&& s
->timing_info
.playing
) {
1587 usec
+= pa_timeval_diff(pa_gettimeofday(&now
), &s
->timing_info
.timestamp
);
1591 /* Make sure the time runs monotonically */
1592 if (!(s
->flags
& PA_STREAM_NOT_MONOTONOUS
)) {
1593 if (usec
< s
->previous_time
)
1594 usec
= s
->previous_time
;
1596 s
->previous_time
= usec
;
1605 static pa_usec_t
time_counter_diff(pa_stream
*s
, pa_usec_t a
, pa_usec_t b
, int *negative
) {
1607 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1615 if (negative
&& s
->direction
== PA_STREAM_RECORD
) {
1623 int pa_stream_get_latency(pa_stream
*s
, pa_usec_t
*r_usec
, int *negative
) {
1629 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1632 PA_CHECK_VALIDITY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1633 PA_CHECK_VALIDITY(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1634 PA_CHECK_VALIDITY(s
->context
, s
->timing_info_valid
, PA_ERR_NODATA
);
1635 PA_CHECK_VALIDITY(s
->context
, s
->direction
!= PA_STREAM_PLAYBACK
|| !s
->timing_info
.write_index_corrupt
, PA_ERR_NODATA
);
1636 PA_CHECK_VALIDITY(s
->context
, s
->direction
!= PA_STREAM_RECORD
|| !s
->timing_info
.read_index_corrupt
, PA_ERR_NODATA
);
1638 if ((r
= pa_stream_get_time(s
, &t
)) < 0)
1641 if (s
->direction
== PA_STREAM_PLAYBACK
)
1642 cindex
= s
->timing_info
.write_index
;
1644 cindex
= s
->timing_info
.read_index
;
1649 c
= pa_bytes_to_usec(cindex
, &s
->sample_spec
);
1651 if (s
->direction
== PA_STREAM_PLAYBACK
)
1652 *r_usec
= time_counter_diff(s
, c
, t
, negative
);
1654 *r_usec
= time_counter_diff(s
, t
, c
, negative
);
1659 const pa_timing_info
* pa_stream_get_timing_info(pa_stream
*s
) {
1661 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1663 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1664 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1665 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->timing_info_valid
, PA_ERR_BADSTATE
);
1667 return &s
->timing_info
;
1670 const pa_sample_spec
* pa_stream_get_sample_spec(pa_stream
*s
) {
1672 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1674 return &s
->sample_spec
;
1677 const pa_channel_map
* pa_stream_get_channel_map(pa_stream
*s
) {
1679 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1681 return &s
->channel_map
;
1684 const pa_buffer_attr
* pa_stream_get_buffer_attr(pa_stream
*s
) {
1686 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1688 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1689 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1690 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->context
->version
>= 9, PA_ERR_NODATA
);
1692 return &s
->buffer_attr
;
1695 static void stream_set_buffer_attr_callback(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1696 pa_operation
*o
= userdata
;
1701 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
1706 if (command
!= PA_COMMAND_REPLY
) {
1707 if (pa_context_handle_error(o
->context
, command
, t
) < 0)
1713 if (o
->stream
->direction
== PA_STREAM_PLAYBACK
) {
1714 if (pa_tagstruct_getu32(t
, &o
->stream
->buffer_attr
.maxlength
) < 0 ||
1715 pa_tagstruct_getu32(t
, &o
->stream
->buffer_attr
.tlength
) < 0 ||
1716 pa_tagstruct_getu32(t
, &o
->stream
->buffer_attr
.prebuf
) < 0 ||
1717 pa_tagstruct_getu32(t
, &o
->stream
->buffer_attr
.minreq
) < 0) {
1718 pa_context_fail(o
->context
, PA_ERR_PROTOCOL
);
1721 } else if (o
->stream
->direction
== PA_STREAM_RECORD
) {
1722 if (pa_tagstruct_getu32(t
, &o
->stream
->buffer_attr
.maxlength
) < 0 ||
1723 pa_tagstruct_getu32(t
, &o
->stream
->buffer_attr
.fragsize
) < 0) {
1724 pa_context_fail(o
->context
, PA_ERR_PROTOCOL
);
1729 if (!pa_tagstruct_eof(t
)) {
1730 pa_context_fail(o
->context
, PA_ERR_PROTOCOL
);
1734 o
->stream
->manual_buffer_attr
= TRUE
;
1738 pa_stream_success_cb_t cb
= (pa_stream_success_cb_t
) o
->callback
;
1739 cb(o
->stream
, success
, o
->userdata
);
1743 pa_operation_done(o
);
1744 pa_operation_unref(o
);
1748 pa_operation
* pa_stream_set_buffer_attr(pa_stream
*s
, const pa_buffer_attr
*attr
, pa_stream_success_cb_t cb
, void *userdata
) {
1754 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1757 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1758 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1759 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->context
->version
>= 12, PA_ERR_NOTSUPPORTED
);
1761 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1763 t
= pa_tagstruct_command(
1765 s
->direction
== PA_STREAM_RECORD
? PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR
: PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR
,
1767 pa_tagstruct_putu32(t
, s
->channel
);
1769 pa_tagstruct_putu32(t
, attr
->maxlength
);
1771 if (s
->direction
== PA_STREAM_PLAYBACK
)
1774 PA_TAG_U32
, attr
->tlength
,
1775 PA_TAG_U32
, attr
->prebuf
,
1776 PA_TAG_U32
, attr
->minreq
,
1779 pa_tagstruct_putu32(t
, attr
->fragsize
);
1781 if (s
->context
->version
>= 13)
1782 pa_tagstruct_put_boolean(t
, !!(s
->flags
& PA_STREAM_ADJUST_LATENCY
));
1784 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1785 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
);
1790 uint32_t pa_stream_get_device_index(pa_stream
*s
) {
1792 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1794 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
, PA_INVALID_INDEX
);
1795 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
, PA_INVALID_INDEX
);
1796 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->context
->version
>= 12, PA_ERR_NOTSUPPORTED
, PA_INVALID_INDEX
);
1797 PA_CHECK_VALIDITY_RETURN_ANY(s
->context
, s
->device_index
!= PA_INVALID_INDEX
, PA_ERR_BADSTATE
, PA_INVALID_INDEX
);
1799 return s
->device_index
;
1802 const char *pa_stream_get_device_name(pa_stream
*s
) {
1804 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1806 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1807 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1808 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->context
->version
>= 12, PA_ERR_NOTSUPPORTED
);
1809 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->device_name
, PA_ERR_BADSTATE
);
1811 return s
->device_name
;
1814 int pa_stream_is_suspended(pa_stream
*s
) {
1816 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1818 PA_CHECK_VALIDITY(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1819 PA_CHECK_VALIDITY(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1820 PA_CHECK_VALIDITY(s
->context
, s
->context
->version
>= 12, PA_ERR_NOTSUPPORTED
);
1822 return s
->suspended
;
1825 static void stream_update_sample_rate_callback(pa_pdispatch
*pd
, uint32_t command
, PA_GCC_UNUSED
uint32_t tag
, pa_tagstruct
*t
, void *userdata
) {
1826 pa_operation
*o
= userdata
;
1831 pa_assert(PA_REFCNT_VALUE(o
) >= 1);
1836 if (command
!= PA_COMMAND_REPLY
) {
1837 if (pa_context_handle_error(o
->context
, command
, t
) < 0)
1843 if (!pa_tagstruct_eof(t
)) {
1844 pa_context_fail(o
->context
, PA_ERR_PROTOCOL
);
1849 o
->stream
->sample_spec
.rate
= PA_PTR_TO_UINT(o
->private);
1850 pa_assert(pa_sample_spec_valid(&o
->stream
->sample_spec
));
1853 pa_stream_success_cb_t cb
= (pa_stream_success_cb_t
) o
->callback
;
1854 cb(o
->stream
, success
, o
->userdata
);
1858 pa_operation_done(o
);
1859 pa_operation_unref(o
);
1863 pa_operation
*pa_stream_update_sample_rate(pa_stream
*s
, uint32_t rate
, pa_stream_success_cb_t cb
, void *userdata
) {
1869 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1871 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, rate
> 0 && rate
<= PA_RATE_MAX
, PA_ERR_INVALID
);
1872 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1873 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1874 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->flags
& PA_STREAM_VARIABLE_RATE
, PA_ERR_BADSTATE
);
1875 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->context
->version
>= 12, PA_ERR_NOTSUPPORTED
);
1877 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1878 o
->private = PA_UINT_TO_PTR(rate
);
1880 t
= pa_tagstruct_command(
1882 s
->direction
== PA_STREAM_RECORD
? PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE
: PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE
,
1884 pa_tagstruct_putu32(t
, s
->channel
);
1885 pa_tagstruct_putu32(t
, rate
);
1887 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1888 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
);
1893 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
) {
1899 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1901 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, mode
== PA_UPDATE_SET
|| mode
== PA_UPDATE_MERGE
|| mode
== PA_UPDATE_REPLACE
, PA_ERR_INVALID
);
1902 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1903 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1904 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->context
->version
>= 13, PA_ERR_NOTSUPPORTED
);
1906 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1908 t
= pa_tagstruct_command(
1910 s
->direction
== PA_STREAM_RECORD
? PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST
: PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST
,
1912 pa_tagstruct_putu32(t
, s
->channel
);
1913 pa_tagstruct_putu32(t
, (uint32_t) mode
);
1914 pa_tagstruct_put_proplist(t
, p
);
1916 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1917 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
);
1919 /* Please note that we don't update s->proplist here, because we
1920 * don't export that field */
1925 pa_operation
*pa_stream_proplist_remove(pa_stream
*s
, const char *const keys
[], pa_stream_success_cb_t cb
, void *userdata
) {
1929 const char * const*k
;
1932 pa_assert(PA_REFCNT_VALUE(s
) >= 1);
1934 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, keys
&& keys
[0], PA_ERR_INVALID
);
1935 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->state
== PA_STREAM_READY
, PA_ERR_BADSTATE
);
1936 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->direction
!= PA_STREAM_UPLOAD
, PA_ERR_BADSTATE
);
1937 PA_CHECK_VALIDITY_RETURN_NULL(s
->context
, s
->context
->version
>= 13, PA_ERR_NOTSUPPORTED
);
1939 o
= pa_operation_new(s
->context
, s
, (pa_operation_cb_t
) cb
, userdata
);
1941 t
= pa_tagstruct_command(
1943 s
->direction
== PA_STREAM_RECORD
? PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST
: PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST
,
1945 pa_tagstruct_putu32(t
, s
->channel
);
1947 for (k
= keys
; *k
; k
++)
1948 pa_tagstruct_puts(t
, *k
);
1950 pa_tagstruct_puts(t
, NULL
);
1952 pa_pstream_send_tagstruct(s
->context
->pstream
, t
);
1953 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
);
1955 /* Please note that we don't update s->proplist here, because we
1956 * don't export that field */