2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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
31 #include <pulse/introspect.h>
32 #include <pulse/utf8.h>
33 #include <pulse/xmalloc.h>
34 #include <pulse/timeval.h>
35 #include <pulse/util.h>
36 #include <pulse/i18n.h>
38 #include <pulsecore/sink-input.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/sample-util.h>
42 #include <pulsecore/core-subscribe.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/play-memblockq.h>
49 #define MAX_MIX_CHANNELS 32
50 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
51 #define ABSOLUTE_MIN_LATENCY (500)
52 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
53 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
55 static PA_DEFINE_CHECK_TYPE(pa_sink
, pa_msgobject
);
57 static void sink_free(pa_object
*s
);
59 pa_sink_new_data
* pa_sink_new_data_init(pa_sink_new_data
*data
) {
62 memset(data
, 0, sizeof(*data
));
63 data
->proplist
= pa_proplist_new();
68 void pa_sink_new_data_set_name(pa_sink_new_data
*data
, const char *name
) {
72 data
->name
= pa_xstrdup(name
);
75 void pa_sink_new_data_set_sample_spec(pa_sink_new_data
*data
, const pa_sample_spec
*spec
) {
78 if ((data
->sample_spec_is_set
= !!spec
))
79 data
->sample_spec
= *spec
;
82 void pa_sink_new_data_set_channel_map(pa_sink_new_data
*data
, const pa_channel_map
*map
) {
85 if ((data
->channel_map_is_set
= !!map
))
86 data
->channel_map
= *map
;
89 void pa_sink_new_data_set_volume(pa_sink_new_data
*data
, const pa_cvolume
*volume
) {
92 if ((data
->volume_is_set
= !!volume
))
93 data
->volume
= *volume
;
96 void pa_sink_new_data_set_muted(pa_sink_new_data
*data
, pa_bool_t mute
) {
99 data
->muted_is_set
= TRUE
;
100 data
->muted
= !!mute
;
103 void pa_sink_new_data_done(pa_sink_new_data
*data
) {
106 pa_xfree(data
->name
);
107 pa_proplist_free(data
->proplist
);
110 /* Called from main context */
111 static void reset_callbacks(pa_sink
*s
) {
115 s
->get_volume
= NULL
;
116 s
->set_volume
= NULL
;
119 s
->request_rewind
= NULL
;
120 s
->update_requested_latency
= NULL
;
123 /* Called from main context */
124 pa_sink
* pa_sink_new(
126 pa_sink_new_data
*data
,
127 pa_sink_flags_t flags
) {
131 char st
[PA_SAMPLE_SPEC_SNPRINT_MAX
], cm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
132 pa_source_new_data source_data
;
138 pa_assert(data
->name
);
140 s
= pa_msgobject_new(pa_sink
);
142 if (!(name
= pa_namereg_register(core
, data
->name
, PA_NAMEREG_SINK
, s
, data
->namereg_fail
))) {
147 pa_sink_new_data_set_name(data
, name
);
149 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SINK_NEW
], data
) < 0) {
151 pa_namereg_unregister(core
, name
);
155 pa_return_null_if_fail(!data
->driver
|| pa_utf8_valid(data
->driver
));
156 pa_return_null_if_fail(data
->name
&& pa_utf8_valid(data
->name
) && data
->name
[0]);
158 pa_return_null_if_fail(data
->sample_spec_is_set
&& pa_sample_spec_valid(&data
->sample_spec
));
160 if (!data
->channel_map_is_set
)
161 pa_return_null_if_fail(pa_channel_map_init_auto(&data
->channel_map
, data
->sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
));
163 pa_return_null_if_fail(pa_channel_map_valid(&data
->channel_map
));
164 pa_return_null_if_fail(data
->channel_map
.channels
== data
->sample_spec
.channels
);
166 if (!data
->volume_is_set
)
167 pa_cvolume_reset(&data
->volume
, data
->sample_spec
.channels
);
169 pa_return_null_if_fail(pa_cvolume_valid(&data
->volume
));
170 pa_return_null_if_fail(data
->volume
.channels
== data
->sample_spec
.channels
);
172 if (!data
->muted_is_set
)
176 pa_proplist_update(data
->proplist
, PA_UPDATE_MERGE
, data
->card
->proplist
);
178 pa_device_init_description(data
->proplist
);
179 pa_device_init_icon(data
->proplist
, TRUE
);
181 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SINK_FIXATE
], data
) < 0) {
183 pa_namereg_unregister(core
, name
);
187 s
->parent
.parent
.free
= sink_free
;
188 s
->parent
.process_msg
= pa_sink_process_msg
;
191 s
->state
= PA_SINK_INIT
;
193 s
->suspend_cause
= 0;
194 s
->name
= pa_xstrdup(name
);
195 s
->proplist
= pa_proplist_copy(data
->proplist
);
196 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
197 s
->module
= data
->module
;
198 s
->card
= data
->card
;
200 s
->sample_spec
= data
->sample_spec
;
201 s
->channel_map
= data
->channel_map
;
203 s
->inputs
= pa_idxset_new(NULL
, NULL
);
206 s
->reference_volume
= s
->virtual_volume
= data
->volume
;
207 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
208 s
->base_volume
= PA_VOLUME_NORM
;
209 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
210 s
->muted
= data
->muted
;
211 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
213 s
->fixed_latency
= flags
& PA_SINK_DYNAMIC_LATENCY
? 0 : DEFAULT_FIXED_LATENCY
;
221 pa_silence_memchunk_get(
222 &core
->silence_cache
,
228 s
->thread_info
.inputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
229 s
->thread_info
.soft_volume
= s
->soft_volume
;
230 s
->thread_info
.soft_muted
= s
->muted
;
231 s
->thread_info
.state
= s
->state
;
232 s
->thread_info
.rewind_nbytes
= 0;
233 s
->thread_info
.rewind_requested
= FALSE
;
234 s
->thread_info
.max_rewind
= 0;
235 s
->thread_info
.max_request
= 0;
236 s
->thread_info
.requested_latency_valid
= FALSE
;
237 s
->thread_info
.requested_latency
= 0;
238 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
239 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
241 pa_assert_se(pa_idxset_put(core
->sinks
, s
, &s
->index
) >= 0);
244 pa_assert_se(pa_idxset_put(s
->card
->sinks
, s
, NULL
) >= 0);
246 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
247 pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
250 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
251 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
255 pa_source_new_data_init(&source_data
);
256 pa_source_new_data_set_sample_spec(&source_data
, &s
->sample_spec
);
257 pa_source_new_data_set_channel_map(&source_data
, &s
->channel_map
);
258 source_data
.name
= pa_sprintf_malloc("%s.monitor", name
);
259 source_data
.driver
= data
->driver
;
260 source_data
.module
= data
->module
;
261 source_data
.card
= data
->card
;
263 dn
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
264 pa_proplist_setf(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Monitor of %s", dn
? dn
: s
->name
);
265 pa_proplist_sets(source_data
.proplist
, PA_PROP_DEVICE_CLASS
, "monitor");
267 s
->monitor_source
= pa_source_new(core
, &source_data
,
268 ((flags
& PA_SINK_LATENCY
) ? PA_SOURCE_LATENCY
: 0) |
269 ((flags
& PA_SINK_DYNAMIC_LATENCY
) ? PA_SOURCE_DYNAMIC_LATENCY
: 0));
271 pa_source_new_data_done(&source_data
);
273 if (!s
->monitor_source
) {
279 s
->monitor_source
->monitor_of
= s
;
281 pa_source_set_latency_range(s
->monitor_source
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
282 pa_source_set_max_rewind(s
->monitor_source
, s
->thread_info
.max_rewind
);
287 /* Called from main context */
288 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
290 pa_bool_t suspend_change
;
291 pa_sink_state_t original_state
;
295 if (s
->state
== state
)
298 original_state
= s
->state
;
301 (original_state
== PA_SINK_SUSPENDED
&& PA_SINK_IS_OPENED(state
)) ||
302 (PA_SINK_IS_OPENED(original_state
) && state
== PA_SINK_SUSPENDED
);
305 if ((ret
= s
->set_state(s
, state
)) < 0)
309 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
312 s
->set_state(s
, original_state
);
319 if (state
!= PA_SINK_UNLINKED
) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
320 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SINK_STATE_CHANGED
], s
);
321 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
324 if (suspend_change
) {
328 /* We're suspending or resuming, tell everyone about it */
330 for (i
= PA_SINK_INPUT(pa_idxset_first(s
->inputs
, &idx
)); i
; i
= PA_SINK_INPUT(pa_idxset_next(s
->inputs
, &idx
)))
331 if (s
->state
== PA_SINK_SUSPENDED
&&
332 (i
->flags
& PA_SINK_INPUT_FAIL_ON_SUSPEND
))
333 pa_sink_input_kill(i
);
335 i
->suspend(i
, state
== PA_SINK_SUSPENDED
);
337 if (s
->monitor_source
)
338 pa_source_sync_suspend(s
->monitor_source
);
344 /* Called from main context */
345 void pa_sink_put(pa_sink
* s
) {
346 pa_sink_assert_ref(s
);
348 pa_assert(s
->state
== PA_SINK_INIT
);
350 /* The following fields must be initialized properly when calling _put() */
351 pa_assert(s
->asyncmsgq
);
352 pa_assert(s
->rtpoll
);
353 pa_assert(s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
355 /* Generally, flags should be initialized via pa_sink_new(). As a
356 * special exception we allow volume related flags to be set
357 * between _new() and _put(). */
359 if (!(s
->flags
& PA_SINK_HW_VOLUME_CTRL
))
360 s
->flags
|= PA_SINK_DECIBEL_VOLUME
;
362 if ((s
->flags
& PA_SINK_DECIBEL_VOLUME
) && s
->core
->flat_volumes
)
363 s
->flags
|= PA_SINK_FLAT_VOLUME
;
365 s
->thread_info
.soft_volume
= s
->soft_volume
;
366 s
->thread_info
.soft_muted
= s
->muted
;
368 pa_assert((s
->flags
& PA_SINK_HW_VOLUME_CTRL
) || (s
->base_volume
== PA_VOLUME_NORM
&& s
->flags
& PA_SINK_DECIBEL_VOLUME
));
369 pa_assert(!(s
->flags
& PA_SINK_DECIBEL_VOLUME
) || s
->n_volume_steps
== PA_VOLUME_NORM
+1);
370 pa_assert(!(s
->flags
& PA_SINK_DYNAMIC_LATENCY
) == (s
->fixed_latency
!= 0));
371 pa_assert(!(s
->flags
& PA_SINK_LATENCY
) == !(s
->monitor_source
->flags
& PA_SOURCE_LATENCY
));
372 pa_assert(!(s
->flags
& PA_SINK_DYNAMIC_LATENCY
) == !(s
->monitor_source
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
374 pa_assert(s
->monitor_source
->fixed_latency
== s
->fixed_latency
);
375 pa_assert(s
->monitor_source
->thread_info
.min_latency
== s
->thread_info
.min_latency
);
376 pa_assert(s
->monitor_source
->thread_info
.max_latency
== s
->thread_info
.max_latency
);
378 pa_assert_se(sink_set_state(s
, PA_SINK_IDLE
) == 0);
380 pa_source_put(s
->monitor_source
);
382 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
383 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SINK_PUT
], s
);
386 /* Called from main context */
387 void pa_sink_unlink(pa_sink
* s
) {
389 pa_sink_input
*i
, *j
= NULL
;
393 /* Please note that pa_sink_unlink() does more than simply
394 * reversing pa_sink_put(). It also undoes the registrations
395 * already done in pa_sink_new()! */
397 /* All operations here shall be idempotent, i.e. pa_sink_unlink()
398 * may be called multiple times on the same sink without bad
401 linked
= PA_SINK_IS_LINKED(s
->state
);
404 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SINK_UNLINK
], s
);
406 if (s
->state
!= PA_SINK_UNLINKED
)
407 pa_namereg_unregister(s
->core
, s
->name
);
408 pa_idxset_remove_by_data(s
->core
->sinks
, s
, NULL
);
411 pa_idxset_remove_by_data(s
->card
->sinks
, s
, NULL
);
413 while ((i
= pa_idxset_first(s
->inputs
, NULL
))) {
415 pa_sink_input_kill(i
);
420 sink_set_state(s
, PA_SINK_UNLINKED
);
422 s
->state
= PA_SINK_UNLINKED
;
426 if (s
->monitor_source
)
427 pa_source_unlink(s
->monitor_source
);
430 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
431 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SINK_UNLINK_POST
], s
);
435 /* Called from main context */
436 static void sink_free(pa_object
*o
) {
437 pa_sink
*s
= PA_SINK(o
);
441 pa_assert(pa_sink_refcnt(s
) == 0);
443 if (PA_SINK_IS_LINKED(s
->state
))
446 pa_log_info("Freeing sink %u \"%s\"", s
->index
, s
->name
);
448 if (s
->monitor_source
) {
449 pa_source_unref(s
->monitor_source
);
450 s
->monitor_source
= NULL
;
453 pa_idxset_free(s
->inputs
, NULL
, NULL
);
455 while ((i
= pa_hashmap_steal_first(s
->thread_info
.inputs
)))
456 pa_sink_input_unref(i
);
458 pa_hashmap_free(s
->thread_info
.inputs
, NULL
, NULL
);
460 if (s
->silence
.memblock
)
461 pa_memblock_unref(s
->silence
.memblock
);
467 pa_proplist_free(s
->proplist
);
472 /* Called from main context */
473 void pa_sink_set_asyncmsgq(pa_sink
*s
, pa_asyncmsgq
*q
) {
474 pa_sink_assert_ref(s
);
478 if (s
->monitor_source
)
479 pa_source_set_asyncmsgq(s
->monitor_source
, q
);
482 /* Called from main context */
483 void pa_sink_set_rtpoll(pa_sink
*s
, pa_rtpoll
*p
) {
484 pa_sink_assert_ref(s
);
487 if (s
->monitor_source
)
488 pa_source_set_rtpoll(s
->monitor_source
, p
);
491 /* Called from main context */
492 int pa_sink_update_status(pa_sink
*s
) {
493 pa_sink_assert_ref(s
);
494 pa_assert(PA_SINK_IS_LINKED(s
->state
));
496 if (s
->state
== PA_SINK_SUSPENDED
)
499 return sink_set_state(s
, pa_sink_used_by(s
) ? PA_SINK_RUNNING
: PA_SINK_IDLE
);
502 /* Called from main context */
503 int pa_sink_suspend(pa_sink
*s
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
504 pa_sink_assert_ref(s
);
505 pa_assert(PA_SINK_IS_LINKED(s
->state
));
506 pa_assert(cause
!= 0);
509 s
->suspend_cause
|= cause
;
511 s
->suspend_cause
&= ~cause
;
513 pa_log_debug("Suspend cause of sink %s is 0x%04x, %s", s
->name
, s
->suspend_cause
, s
->suspend_cause
? "suspending" : "resuming");
515 if (s
->suspend_cause
)
516 return sink_set_state(s
, PA_SINK_SUSPENDED
);
518 return sink_set_state(s
, pa_sink_used_by(s
) ? PA_SINK_RUNNING
: PA_SINK_IDLE
);
521 /* Called from main context */
522 pa_queue
*pa_sink_move_all_start(pa_sink
*s
) {
524 pa_sink_input
*i
, *n
;
527 pa_sink_assert_ref(s
);
528 pa_assert(PA_SINK_IS_LINKED(s
->state
));
532 for (i
= PA_SINK_INPUT(pa_idxset_first(s
->inputs
, &idx
)); i
; i
= n
) {
533 n
= PA_SINK_INPUT(pa_idxset_next(s
->inputs
, &idx
));
535 pa_sink_input_ref(i
);
537 if (pa_sink_input_start_move(i
) >= 0)
540 pa_sink_input_unref(i
);
546 /* Called from main context */
547 void pa_sink_move_all_finish(pa_sink
*s
, pa_queue
*q
, pa_bool_t save
) {
550 pa_sink_assert_ref(s
);
551 pa_assert(PA_SINK_IS_LINKED(s
->state
));
554 while ((i
= PA_SINK_INPUT(pa_queue_pop(q
)))) {
555 if (pa_sink_input_finish_move(i
, s
, save
) < 0)
556 pa_sink_input_kill(i
);
558 pa_sink_input_unref(i
);
561 pa_queue_free(q
, NULL
, NULL
);
564 /* Called from main context */
565 void pa_sink_move_all_fail(pa_queue
*q
) {
569 while ((i
= PA_SINK_INPUT(pa_queue_pop(q
)))) {
570 if (pa_hook_fire(&i
->core
->hooks
[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL
], i
) == PA_HOOK_OK
) {
571 pa_sink_input_kill(i
);
572 pa_sink_input_unref(i
);
576 pa_queue_free(q
, NULL
, NULL
);
579 /* Called from IO thread context */
580 void pa_sink_process_rewind(pa_sink
*s
, size_t nbytes
) {
583 pa_sink_assert_ref(s
);
584 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
586 /* If nobody requested this and this is actually no real rewind
587 * then we can short cut this */
588 if (!s
->thread_info
.rewind_requested
&& nbytes
<= 0)
591 s
->thread_info
.rewind_nbytes
= 0;
592 s
->thread_info
.rewind_requested
= FALSE
;
594 if (s
->thread_info
.state
== PA_SINK_SUSPENDED
)
598 pa_log_debug("Processing rewind...");
600 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
))) {
601 pa_sink_input_assert_ref(i
);
602 pa_sink_input_process_rewind(i
, nbytes
);
606 if (s
->monitor_source
&& PA_SOURCE_IS_LINKED(s
->monitor_source
->thread_info
.state
))
607 pa_source_process_rewind(s
->monitor_source
, nbytes
);
610 /* Called from IO thread context */
611 static unsigned fill_mix_info(pa_sink
*s
, size_t *length
, pa_mix_info
*info
, unsigned maxinfo
) {
615 size_t mixlength
= *length
;
617 pa_sink_assert_ref(s
);
620 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)) && maxinfo
> 0) {
621 pa_sink_input_assert_ref(i
);
623 pa_sink_input_peek(i
, *length
, &info
->chunk
, &info
->volume
);
625 if (mixlength
== 0 || info
->chunk
.length
< mixlength
)
626 mixlength
= info
->chunk
.length
;
628 if (pa_memblock_is_silence(info
->chunk
.memblock
)) {
629 pa_memblock_unref(info
->chunk
.memblock
);
633 info
->userdata
= pa_sink_input_ref(i
);
635 pa_assert(info
->chunk
.memblock
);
636 pa_assert(info
->chunk
.length
> 0);
649 /* Called from IO thread context */
650 static void inputs_drop(pa_sink
*s
, pa_mix_info
*info
, unsigned n
, pa_memchunk
*result
) {
654 unsigned n_unreffed
= 0;
656 pa_sink_assert_ref(s
);
658 pa_assert(result
->memblock
);
659 pa_assert(result
->length
> 0);
661 /* We optimize for the case where the order of the inputs has not changed */
663 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
))) {
665 pa_mix_info
* m
= NULL
;
667 pa_sink_input_assert_ref(i
);
669 /* Let's try to find the matching entry info the pa_mix_info array */
670 for (j
= 0; j
< n
; j
++) {
672 if (info
[p
].userdata
== i
) {
683 pa_sink_input_drop(i
, result
->length
);
685 if (s
->monitor_source
&& PA_SOURCE_IS_LINKED(s
->monitor_source
->thread_info
.state
)) {
687 if (pa_hashmap_size(i
->thread_info
.direct_outputs
) > 0) {
692 if (m
&& m
->chunk
.memblock
) {
694 pa_memblock_ref(c
.memblock
);
695 pa_assert(result
->length
<= c
.length
);
696 c
.length
= result
->length
;
698 pa_memchunk_make_writable(&c
, 0);
699 pa_volume_memchunk(&c
, &s
->sample_spec
, &m
->volume
);
702 pa_memblock_ref(c
.memblock
);
703 pa_assert(result
->length
<= c
.length
);
704 c
.length
= result
->length
;
707 while ((o
= pa_hashmap_iterate(i
->thread_info
.direct_outputs
, &ostate
, NULL
))) {
708 pa_source_output_assert_ref(o
);
709 pa_assert(o
->direct_on_input
== i
);
710 pa_source_post_direct(s
->monitor_source
, o
, &c
);
713 pa_memblock_unref(c
.memblock
);
718 if (m
->chunk
.memblock
)
719 pa_memblock_unref(m
->chunk
.memblock
);
720 pa_memchunk_reset(&m
->chunk
);
722 pa_sink_input_unref(m
->userdata
);
729 /* Now drop references to entries that are included in the
730 * pa_mix_info array but don't exist anymore */
732 if (n_unreffed
< n
) {
733 for (; n
> 0; info
++, n
--) {
735 pa_sink_input_unref(info
->userdata
);
736 if (info
->chunk
.memblock
)
737 pa_memblock_unref(info
->chunk
.memblock
);
741 if (s
->monitor_source
&& PA_SOURCE_IS_LINKED(s
->monitor_source
->thread_info
.state
))
742 pa_source_post(s
->monitor_source
, result
);
745 /* Called from IO thread context */
746 void pa_sink_render(pa_sink
*s
, size_t length
, pa_memchunk
*result
) {
747 pa_mix_info info
[MAX_MIX_CHANNELS
];
749 size_t block_size_max
;
751 pa_sink_assert_ref(s
);
752 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
753 pa_assert(pa_frame_aligned(length
, &s
->sample_spec
));
758 pa_assert(!s
->thread_info
.rewind_requested
);
759 pa_assert(s
->thread_info
.rewind_nbytes
== 0);
761 if (s
->thread_info
.state
== PA_SINK_SUSPENDED
) {
762 result
->memblock
= pa_memblock_ref(s
->silence
.memblock
);
763 result
->index
= s
->silence
.index
;
764 result
->length
= PA_MIN(s
->silence
.length
, length
);
769 length
= pa_frame_align(MIX_BUFFER_LENGTH
, &s
->sample_spec
);
771 block_size_max
= pa_mempool_block_size_max(s
->core
->mempool
);
772 if (length
> block_size_max
)
773 length
= pa_frame_align(block_size_max
, &s
->sample_spec
);
775 pa_assert(length
> 0);
777 n
= fill_mix_info(s
, &length
, info
, MAX_MIX_CHANNELS
);
781 *result
= s
->silence
;
782 pa_memblock_ref(result
->memblock
);
784 if (result
->length
> length
)
785 result
->length
= length
;
790 *result
= info
[0].chunk
;
791 pa_memblock_ref(result
->memblock
);
793 if (result
->length
> length
)
794 result
->length
= length
;
796 pa_sw_cvolume_multiply(&volume
, &s
->thread_info
.soft_volume
, &info
[0].volume
);
798 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&volume
)) {
799 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&volume
)) {
800 pa_memblock_unref(result
->memblock
);
801 pa_silence_memchunk_get(&s
->core
->silence_cache
,
807 pa_memchunk_make_writable(result
, 0);
808 pa_volume_memchunk(result
, &s
->sample_spec
, &volume
);
813 result
->memblock
= pa_memblock_new(s
->core
->mempool
, length
);
815 ptr
= pa_memblock_acquire(result
->memblock
);
816 result
->length
= pa_mix(info
, n
,
819 &s
->thread_info
.soft_volume
,
820 s
->thread_info
.soft_muted
);
821 pa_memblock_release(result
->memblock
);
826 inputs_drop(s
, info
, n
, result
);
831 /* Called from IO thread context */
832 void pa_sink_render_into(pa_sink
*s
, pa_memchunk
*target
) {
833 pa_mix_info info
[MAX_MIX_CHANNELS
];
835 size_t length
, block_size_max
;
837 pa_sink_assert_ref(s
);
838 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
840 pa_assert(target
->memblock
);
841 pa_assert(target
->length
> 0);
842 pa_assert(pa_frame_aligned(target
->length
, &s
->sample_spec
));
846 pa_assert(!s
->thread_info
.rewind_requested
);
847 pa_assert(s
->thread_info
.rewind_nbytes
== 0);
849 if (s
->thread_info
.state
== PA_SINK_SUSPENDED
) {
850 pa_silence_memchunk(target
, &s
->sample_spec
);
854 length
= target
->length
;
855 block_size_max
= pa_mempool_block_size_max(s
->core
->mempool
);
856 if (length
> block_size_max
)
857 length
= pa_frame_align(block_size_max
, &s
->sample_spec
);
859 pa_assert(length
> 0);
861 n
= fill_mix_info(s
, &length
, info
, MAX_MIX_CHANNELS
);
864 if (target
->length
> length
)
865 target
->length
= length
;
867 pa_silence_memchunk(target
, &s
->sample_spec
);
871 if (target
->length
> length
)
872 target
->length
= length
;
874 pa_sw_cvolume_multiply(&volume
, &s
->thread_info
.soft_volume
, &info
[0].volume
);
876 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&volume
))
877 pa_silence_memchunk(target
, &s
->sample_spec
);
881 vchunk
= info
[0].chunk
;
882 pa_memblock_ref(vchunk
.memblock
);
884 if (vchunk
.length
> length
)
885 vchunk
.length
= length
;
887 if (!pa_cvolume_is_norm(&volume
)) {
888 pa_memchunk_make_writable(&vchunk
, 0);
889 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &volume
);
892 pa_memchunk_memcpy(target
, &vchunk
);
893 pa_memblock_unref(vchunk
.memblock
);
899 ptr
= pa_memblock_acquire(target
->memblock
);
901 target
->length
= pa_mix(info
, n
,
902 (uint8_t*) ptr
+ target
->index
, length
,
904 &s
->thread_info
.soft_volume
,
905 s
->thread_info
.soft_muted
);
907 pa_memblock_release(target
->memblock
);
910 inputs_drop(s
, info
, n
, target
);
915 /* Called from IO thread context */
916 void pa_sink_render_into_full(pa_sink
*s
, pa_memchunk
*target
) {
920 pa_sink_assert_ref(s
);
921 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
923 pa_assert(target
->memblock
);
924 pa_assert(target
->length
> 0);
925 pa_assert(pa_frame_aligned(target
->length
, &s
->sample_spec
));
929 pa_assert(!s
->thread_info
.rewind_requested
);
930 pa_assert(s
->thread_info
.rewind_nbytes
== 0);
939 pa_sink_render_into(s
, &chunk
);
948 /* Called from IO thread context */
949 void pa_sink_render_full(pa_sink
*s
, size_t length
, pa_memchunk
*result
) {
950 pa_mix_info info
[MAX_MIX_CHANNELS
];
951 size_t length1st
= length
;
954 pa_sink_assert_ref(s
);
955 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
956 pa_assert(length
> 0);
957 pa_assert(pa_frame_aligned(length
, &s
->sample_spec
));
962 pa_assert(!s
->thread_info
.rewind_requested
);
963 pa_assert(s
->thread_info
.rewind_nbytes
== 0);
965 pa_assert(length
> 0);
967 n
= fill_mix_info(s
, &length1st
, info
, MAX_MIX_CHANNELS
);
970 pa_silence_memchunk_get(&s
->core
->silence_cache
,
978 *result
= info
[0].chunk
;
979 pa_memblock_ref(result
->memblock
);
981 if (result
->length
> length
)
982 result
->length
= length
;
984 pa_sw_cvolume_multiply(&volume
, &s
->thread_info
.soft_volume
, &info
[0].volume
);
986 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&volume
)) {
987 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&volume
)) {
988 pa_memblock_unref(result
->memblock
);
989 pa_silence_memchunk_get(&s
->core
->silence_cache
,
995 pa_memchunk_make_writable(result
, length
);
996 pa_volume_memchunk(result
, &s
->sample_spec
, &volume
);
1003 result
->memblock
= pa_memblock_new(s
->core
->mempool
, length
);
1005 ptr
= pa_memblock_acquire(result
->memblock
);
1007 result
->length
= pa_mix(info
, n
,
1008 (uint8_t*) ptr
+ result
->index
, length1st
,
1010 &s
->thread_info
.soft_volume
,
1011 s
->thread_info
.soft_muted
);
1013 pa_memblock_release(result
->memblock
);
1016 inputs_drop(s
, info
, n
, result
);
1018 if (result
->length
< length
) {
1021 pa_memchunk_make_writable(result
, length
);
1022 result
->length
= length
;
1024 l
= length
- result
->length
;
1025 d
= result
->index
+ result
->length
;
1029 chunk
.length
-= d
- result
->index
;
1031 pa_sink_render_into(s
, &chunk
);
1036 result
->length
= length
;
1042 /* Called from main thread */
1043 pa_usec_t
pa_sink_get_latency(pa_sink
*s
) {
1046 pa_sink_assert_ref(s
);
1047 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1049 /* The returned value is supposed to be in the time domain of the sound card! */
1051 if (s
->state
== PA_SINK_SUSPENDED
)
1054 if (!(s
->flags
& PA_SINK_LATENCY
))
1057 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
1062 /* Called from IO thread */
1063 pa_usec_t
pa_sink_get_latency_within_thread(pa_sink
*s
) {
1067 pa_sink_assert_ref(s
);
1068 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
1070 /* The returned value is supposed to be in the time domain of the sound card! */
1072 if (s
->thread_info
.state
== PA_SINK_SUSPENDED
)
1075 if (!(s
->flags
& PA_SINK_LATENCY
))
1078 o
= PA_MSGOBJECT(s
);
1080 /* We probably should make this a proper vtable callback instead of going through process_msg() */
1082 if (o
->process_msg(o
, PA_SINK_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
1088 static void compute_new_soft_volume(pa_sink_input
*i
, const pa_cvolume
*new_volume
) {
1091 pa_sink_input_assert_ref(i
);
1092 pa_assert(new_volume
->channels
== i
->sample_spec
.channels
);
1095 * This basically calculates:
1097 * i->relative_volume := i->virtual_volume / new_volume
1098 * i->soft_volume := i->relative_volume * i->volume_factor
1101 /* The new sink volume passed in here must already be remapped to
1102 * the sink input's channel map! */
1104 i
->soft_volume
.channels
= i
->sample_spec
.channels
;
1106 for (c
= 0; c
< i
->sample_spec
.channels
; c
++)
1108 if (new_volume
->values
[c
] <= PA_VOLUME_MUTED
)
1109 /* We leave i->relative_volume untouched */
1110 i
->soft_volume
.values
[c
] = PA_VOLUME_MUTED
;
1112 i
->relative_volume
[c
] =
1113 pa_sw_volume_to_linear(i
->virtual_volume
.values
[c
]) /
1114 pa_sw_volume_to_linear(new_volume
->values
[c
]);
1116 i
->soft_volume
.values
[c
] = pa_sw_volume_from_linear(
1117 i
->relative_volume
[c
] *
1118 pa_sw_volume_to_linear(i
->volume_factor
.values
[c
]));
1121 /* Hooks have the ability to play games with i->soft_volume */
1122 pa_hook_fire(&i
->core
->hooks
[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME
], i
);
1124 /* We don't copy the soft_volume to the thread_info data
1125 * here. That must be done by the caller */
1128 /* Called from main thread */
1129 void pa_sink_update_flat_volume(pa_sink
*s
, pa_cvolume
*new_volume
) {
1133 pa_sink_assert_ref(s
);
1134 pa_assert(new_volume
);
1135 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1136 pa_assert(s
->flags
& PA_SINK_FLAT_VOLUME
);
1138 /* This is called whenever a sink input volume changes or a sink
1139 * input is added/removed and we might need to fix up the sink
1140 * volume accordingly. Please note that we don't actually update
1141 * the sinks volume here, we only return how it needs to be
1142 * updated. The caller should then call pa_sink_set_volume().*/
1144 if (pa_idxset_isempty(s
->inputs
)) {
1145 /* In the special case that we have no sink input we leave the
1146 * volume unmodified. */
1147 *new_volume
= s
->reference_volume
;
1151 pa_cvolume_mute(new_volume
, s
->channel_map
.channels
);
1153 /* First let's determine the new maximum volume of all inputs
1154 * connected to this sink */
1155 for (i
= PA_SINK_INPUT(pa_idxset_first(s
->inputs
, &idx
)); i
; i
= PA_SINK_INPUT(pa_idxset_next(s
->inputs
, &idx
))) {
1157 pa_cvolume remapped_volume
;
1159 remapped_volume
= i
->virtual_volume
;
1160 pa_cvolume_remap(&remapped_volume
, &i
->channel_map
, &s
->channel_map
);
1162 for (c
= 0; c
< new_volume
->channels
; c
++)
1163 if (remapped_volume
.values
[c
] > new_volume
->values
[c
])
1164 new_volume
->values
[c
] = remapped_volume
.values
[c
];
1167 /* Then, let's update the soft volumes of all inputs connected
1169 for (i
= PA_SINK_INPUT(pa_idxset_first(s
->inputs
, &idx
)); i
; i
= PA_SINK_INPUT(pa_idxset_next(s
->inputs
, &idx
))) {
1170 pa_cvolume remapped_new_volume
;
1172 remapped_new_volume
= *new_volume
;
1173 pa_cvolume_remap(&remapped_new_volume
, &s
->channel_map
, &i
->channel_map
);
1174 compute_new_soft_volume(i
, &remapped_new_volume
);
1176 /* We don't copy soft_volume to the thread_info data here
1177 * (i.e. issue PA_SINK_INPUT_MESSAGE_SET_VOLUME) because we
1178 * want the update to be atomically with the sink volume
1179 * update, hence we do it within the pa_sink_set_volume() call
1184 /* Called from main thread */
1185 void pa_sink_propagate_flat_volume(pa_sink
*s
) {
1189 pa_sink_assert_ref(s
);
1190 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1191 pa_assert(s
->flags
& PA_SINK_FLAT_VOLUME
);
1193 /* This is called whenever the sink volume changes that is not
1194 * caused by a sink input volume change. We need to fix up the
1195 * sink input volumes accordingly */
1197 for (i
= PA_SINK_INPUT(pa_idxset_first(s
->inputs
, &idx
)); i
; i
= PA_SINK_INPUT(pa_idxset_next(s
->inputs
, &idx
))) {
1198 pa_cvolume sink_volume
, new_virtual_volume
;
1201 /* This basically calculates i->virtual_volume := i->relative_volume * s->virtual_volume */
1203 sink_volume
= s
->virtual_volume
;
1204 pa_cvolume_remap(&sink_volume
, &s
->channel_map
, &i
->channel_map
);
1206 for (c
= 0; c
< i
->sample_spec
.channels
; c
++)
1207 new_virtual_volume
.values
[c
] = pa_sw_volume_from_linear(
1208 i
->relative_volume
[c
] *
1209 pa_sw_volume_to_linear(sink_volume
.values
[c
]));
1211 new_virtual_volume
.channels
= i
->sample_spec
.channels
;
1213 if (!pa_cvolume_equal(&new_virtual_volume
, &i
->virtual_volume
)) {
1214 i
->virtual_volume
= new_virtual_volume
;
1216 /* Hmm, the soft volume might no longer actually match
1217 * what has been chosen as new virtual volume here,
1218 * especially when the old volume was
1219 * PA_VOLUME_MUTED. Hence let's recalculate the soft
1221 compute_new_soft_volume(i
, &sink_volume
);
1223 /* The virtual volume changed, let's tell people so */
1224 pa_subscription_post(i
->core
, PA_SUBSCRIPTION_EVENT_SINK_INPUT
|PA_SUBSCRIPTION_EVENT_CHANGE
, i
->index
);
1228 /* If the soft_volume of any of the sink inputs got changed, let's
1229 * make sure the thread copies are synced up. */
1230 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SYNC_VOLUMES
, NULL
, 0, NULL
) == 0);
1233 /* Called from main thread */
1234 void pa_sink_set_volume(pa_sink
*s
, const pa_cvolume
*volume
, pa_bool_t propagate
, pa_bool_t sendmsg
, pa_bool_t become_reference
) {
1235 pa_bool_t virtual_volume_changed
;
1237 pa_sink_assert_ref(s
);
1238 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1240 pa_assert(pa_cvolume_valid(volume
));
1241 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
1243 virtual_volume_changed
= !pa_cvolume_equal(volume
, &s
->virtual_volume
);
1244 s
->virtual_volume
= *volume
;
1246 if (become_reference
)
1247 s
->reference_volume
= s
->virtual_volume
;
1249 /* Propagate this volume change back to the inputs */
1250 if (virtual_volume_changed
)
1251 if (propagate
&& (s
->flags
& PA_SINK_FLAT_VOLUME
))
1252 pa_sink_propagate_flat_volume(s
);
1254 if (s
->set_volume
) {
1255 /* If we have a function set_volume(), then we do not apply a
1256 * soft volume by default. However, set_volume() is free to
1257 * apply one to s->soft_volume */
1259 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
1263 /* If we have no function set_volume(), then the soft volume
1264 * becomes the virtual volume */
1265 s
->soft_volume
= s
->virtual_volume
;
1267 /* This tells the sink that soft and/or virtual volume changed */
1269 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
1271 if (virtual_volume_changed
)
1272 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1275 /* Called from main thread. Only to be called by sink implementor */
1276 void pa_sink_set_soft_volume(pa_sink
*s
, const pa_cvolume
*volume
) {
1277 pa_sink_assert_ref(s
);
1280 s
->soft_volume
= *volume
;
1282 if (PA_SINK_IS_LINKED(s
->state
))
1283 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
1285 s
->thread_info
.soft_volume
= *volume
;
1288 /* Called from main thread */
1289 const pa_cvolume
*pa_sink_get_volume(pa_sink
*s
, pa_bool_t force_refresh
, pa_bool_t reference
) {
1290 pa_sink_assert_ref(s
);
1292 if (s
->refresh_volume
|| force_refresh
) {
1293 struct pa_cvolume old_virtual_volume
= s
->virtual_volume
;
1298 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
1300 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
)) {
1302 s
->reference_volume
= s
->virtual_volume
;
1304 if (s
->flags
& PA_SINK_FLAT_VOLUME
)
1305 pa_sink_propagate_flat_volume(s
);
1307 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1311 return reference
? &s
->reference_volume
: &s
->virtual_volume
;
1314 /* Called from main thread */
1315 void pa_sink_volume_changed(pa_sink
*s
, const pa_cvolume
*new_volume
) {
1316 pa_sink_assert_ref(s
);
1318 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1320 if (pa_cvolume_equal(&s
->virtual_volume
, new_volume
))
1323 s
->reference_volume
= s
->virtual_volume
= *new_volume
;
1325 if (s
->flags
& PA_SINK_FLAT_VOLUME
)
1326 pa_sink_propagate_flat_volume(s
);
1328 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1331 /* Called from main thread */
1332 void pa_sink_set_mute(pa_sink
*s
, pa_bool_t mute
) {
1333 pa_bool_t old_muted
;
1335 pa_sink_assert_ref(s
);
1336 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1338 old_muted
= s
->muted
;
1344 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
1346 if (old_muted
!= s
->muted
)
1347 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1350 /* Called from main thread */
1351 pa_bool_t
pa_sink_get_mute(pa_sink
*s
, pa_bool_t force_refresh
) {
1353 pa_sink_assert_ref(s
);
1355 if (s
->refresh_muted
|| force_refresh
) {
1356 pa_bool_t old_muted
= s
->muted
;
1361 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
1363 if (old_muted
!= s
->muted
)
1364 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1370 /* Called from main thread */
1371 void pa_sink_mute_changed(pa_sink
*s
, pa_bool_t new_muted
) {
1372 pa_sink_assert_ref(s
);
1374 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1376 if (s
->muted
== new_muted
)
1379 s
->muted
= new_muted
;
1380 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1383 /* Called from main thread */
1384 pa_bool_t
pa_sink_update_proplist(pa_sink
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
1385 pa_sink_assert_ref(s
);
1388 pa_proplist_update(s
->proplist
, mode
, p
);
1390 if (PA_SINK_IS_LINKED(s
->state
)) {
1391 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SINK_PROPLIST_CHANGED
], s
);
1392 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1398 /* Called from main thread */
1399 void pa_sink_set_description(pa_sink
*s
, const char *description
) {
1401 pa_sink_assert_ref(s
);
1403 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
1406 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
1408 if (old
&& description
&& !strcmp(old
, description
))
1412 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
1414 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
1416 if (s
->monitor_source
) {
1419 n
= pa_sprintf_malloc("Monitor Source of %s", description
? description
: s
->name
);
1420 pa_source_set_description(s
->monitor_source
, n
);
1424 if (PA_SINK_IS_LINKED(s
->state
)) {
1425 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SINK
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1426 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SINK_PROPLIST_CHANGED
], s
);
1430 /* Called from main thread */
1431 unsigned pa_sink_linked_by(pa_sink
*s
) {
1434 pa_sink_assert_ref(s
);
1435 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1437 ret
= pa_idxset_size(s
->inputs
);
1439 /* We add in the number of streams connected to us here. Please
1440 * note the asymmmetry to pa_sink_used_by()! */
1442 if (s
->monitor_source
)
1443 ret
+= pa_source_linked_by(s
->monitor_source
);
1448 /* Called from main thread */
1449 unsigned pa_sink_used_by(pa_sink
*s
) {
1452 pa_sink_assert_ref(s
);
1453 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1455 ret
= pa_idxset_size(s
->inputs
);
1456 pa_assert(ret
>= s
->n_corked
);
1458 /* Streams connected to our monitor source do not matter for
1459 * pa_sink_used_by()!.*/
1461 return ret
- s
->n_corked
;
1464 /* Called from main thread */
1465 unsigned pa_sink_check_suspend(pa_sink
*s
) {
1470 pa_sink_assert_ref(s
);
1472 if (!PA_SINK_IS_LINKED(s
->state
))
1477 for (i
= PA_SINK_INPUT(pa_idxset_first(s
->inputs
, &idx
)); i
; i
= PA_SINK_INPUT(pa_idxset_next(s
->inputs
, &idx
))) {
1478 pa_sink_input_state_t st
;
1480 st
= pa_sink_input_get_state(i
);
1481 pa_assert(PA_SINK_INPUT_IS_LINKED(st
));
1483 if (st
== PA_SINK_INPUT_CORKED
)
1486 if (i
->flags
& PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND
)
1492 if (s
->monitor_source
)
1493 ret
+= pa_source_check_suspend(s
->monitor_source
);
1498 /* Called from the IO thread */
1499 static void sync_input_volumes_within_thread(pa_sink
*s
) {
1503 pa_sink_assert_ref(s
);
1505 while ((i
= PA_SINK_INPUT(pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))) {
1506 if (pa_cvolume_equal(&i
->thread_info
.soft_volume
, &i
->soft_volume
))
1509 i
->thread_info
.soft_volume
= i
->soft_volume
;
1510 pa_sink_input_request_rewind(i
, 0, TRUE
, FALSE
, FALSE
);
1514 /* Called from IO thread, except when it is not */
1515 int pa_sink_process_msg(pa_msgobject
*o
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1516 pa_sink
*s
= PA_SINK(o
);
1517 pa_sink_assert_ref(s
);
1519 switch ((pa_sink_message_t
) code
) {
1521 case PA_SINK_MESSAGE_ADD_INPUT
: {
1522 pa_sink_input
*i
= PA_SINK_INPUT(userdata
);
1524 /* If you change anything here, make sure to change the
1525 * sink input handling a few lines down at
1526 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1528 pa_hashmap_put(s
->thread_info
.inputs
, PA_UINT32_TO_PTR(i
->index
), pa_sink_input_ref(i
));
1530 /* Since the caller sleeps in pa_sink_input_put(), we can
1531 * safely access data outside of thread_info even though
1534 if ((i
->thread_info
.sync_prev
= i
->sync_prev
)) {
1535 pa_assert(i
->sink
== i
->thread_info
.sync_prev
->sink
);
1536 pa_assert(i
->sync_prev
->sync_next
== i
);
1537 i
->thread_info
.sync_prev
->thread_info
.sync_next
= i
;
1540 if ((i
->thread_info
.sync_next
= i
->sync_next
)) {
1541 pa_assert(i
->sink
== i
->thread_info
.sync_next
->sink
);
1542 pa_assert(i
->sync_next
->sync_prev
== i
);
1543 i
->thread_info
.sync_next
->thread_info
.sync_prev
= i
;
1546 pa_assert(!i
->thread_info
.attached
);
1547 i
->thread_info
.attached
= TRUE
;
1552 pa_sink_input_set_state_within_thread(i
, i
->state
);
1554 /* The requested latency of the sink input needs to be
1555 * fixed up and then configured on the sink */
1557 if (i
->thread_info
.requested_sink_latency
!= (pa_usec_t
) -1)
1558 pa_sink_input_set_requested_latency_within_thread(i
, i
->thread_info
.requested_sink_latency
);
1560 pa_sink_input_update_max_rewind(i
, s
->thread_info
.max_rewind
);
1561 pa_sink_input_update_max_request(i
, s
->thread_info
.max_request
);
1563 /* We don't rewind here automatically. This is left to the
1564 * sink input implementor because some sink inputs need a
1565 * slow start, i.e. need some time to buffer client
1566 * samples before beginning streaming. */
1568 /* In flat volume mode we need to update the volume as
1570 return o
->process_msg(o
, PA_SINK_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
);
1573 case PA_SINK_MESSAGE_REMOVE_INPUT
: {
1574 pa_sink_input
*i
= PA_SINK_INPUT(userdata
);
1576 /* If you change anything here, make sure to change the
1577 * sink input handling a few lines down at
1578 * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1583 pa_sink_input_set_state_within_thread(i
, i
->state
);
1585 pa_assert(i
->thread_info
.attached
);
1586 i
->thread_info
.attached
= FALSE
;
1588 /* Since the caller sleeps in pa_sink_input_unlink(),
1589 * we can safely access data outside of thread_info even
1590 * though it is mutable */
1592 pa_assert(!i
->sync_prev
);
1593 pa_assert(!i
->sync_next
);
1595 if (i
->thread_info
.sync_prev
) {
1596 i
->thread_info
.sync_prev
->thread_info
.sync_next
= i
->thread_info
.sync_prev
->sync_next
;
1597 i
->thread_info
.sync_prev
= NULL
;
1600 if (i
->thread_info
.sync_next
) {
1601 i
->thread_info
.sync_next
->thread_info
.sync_prev
= i
->thread_info
.sync_next
->sync_prev
;
1602 i
->thread_info
.sync_next
= NULL
;
1605 if (pa_hashmap_remove(s
->thread_info
.inputs
, PA_UINT32_TO_PTR(i
->index
)))
1606 pa_sink_input_unref(i
);
1608 pa_sink_invalidate_requested_latency(s
);
1609 pa_sink_request_rewind(s
, (size_t) -1);
1611 /* In flat volume mode we need to update the volume as
1613 return o
->process_msg(o
, PA_SINK_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
);
1616 case PA_SINK_MESSAGE_START_MOVE
: {
1617 pa_sink_input
*i
= PA_SINK_INPUT(userdata
);
1619 /* We don't support moving synchronized streams. */
1620 pa_assert(!i
->sync_prev
);
1621 pa_assert(!i
->sync_next
);
1622 pa_assert(!i
->thread_info
.sync_next
);
1623 pa_assert(!i
->thread_info
.sync_prev
);
1625 if (i
->thread_info
.state
!= PA_SINK_INPUT_CORKED
) {
1627 size_t sink_nbytes
, total_nbytes
;
1629 /* Get the latency of the sink */
1630 if (!(s
->flags
& PA_SINK_LATENCY
) ||
1631 PA_MSGOBJECT(s
)->process_msg(PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
1634 sink_nbytes
= pa_usec_to_bytes(usec
, &s
->sample_spec
);
1635 total_nbytes
= sink_nbytes
+ pa_memblockq_get_length(i
->thread_info
.render_memblockq
);
1637 if (total_nbytes
> 0) {
1638 i
->thread_info
.rewrite_nbytes
= i
->thread_info
.resampler
? pa_resampler_request(i
->thread_info
.resampler
, total_nbytes
) : total_nbytes
;
1639 i
->thread_info
.rewrite_flush
= TRUE
;
1640 pa_sink_input_process_rewind(i
, sink_nbytes
);
1647 pa_assert(i
->thread_info
.attached
);
1648 i
->thread_info
.attached
= FALSE
;
1650 /* Let's remove the sink input ...*/
1651 if (pa_hashmap_remove(s
->thread_info
.inputs
, PA_UINT32_TO_PTR(i
->index
)))
1652 pa_sink_input_unref(i
);
1654 pa_sink_invalidate_requested_latency(s
);
1656 pa_log_debug("Requesting rewind due to started move");
1657 pa_sink_request_rewind(s
, (size_t) -1);
1659 /* In flat volume mode we need to update the volume as
1661 return o
->process_msg(o
, PA_SINK_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
);
1664 case PA_SINK_MESSAGE_FINISH_MOVE
: {
1665 pa_sink_input
*i
= PA_SINK_INPUT(userdata
);
1667 /* We don't support moving synchronized streams. */
1668 pa_assert(!i
->sync_prev
);
1669 pa_assert(!i
->sync_next
);
1670 pa_assert(!i
->thread_info
.sync_next
);
1671 pa_assert(!i
->thread_info
.sync_prev
);
1673 pa_hashmap_put(s
->thread_info
.inputs
, PA_UINT32_TO_PTR(i
->index
), pa_sink_input_ref(i
));
1675 pa_assert(!i
->thread_info
.attached
);
1676 i
->thread_info
.attached
= TRUE
;
1681 if (i
->thread_info
.requested_sink_latency
!= (pa_usec_t
) -1)
1682 pa_sink_input_set_requested_latency_within_thread(i
, i
->thread_info
.requested_sink_latency
);
1684 pa_sink_input_update_max_rewind(i
, s
->thread_info
.max_rewind
);
1685 pa_sink_input_update_max_request(i
, s
->thread_info
.max_request
);
1687 if (i
->thread_info
.state
!= PA_SINK_INPUT_CORKED
) {
1691 /* Get the latency of the sink */
1692 if (!(s
->flags
& PA_SINK_LATENCY
) ||
1693 PA_MSGOBJECT(s
)->process_msg(PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
1696 nbytes
= pa_usec_to_bytes(usec
, &s
->sample_spec
);
1699 pa_sink_input_drop(i
, nbytes
);
1701 pa_log_debug("Requesting rewind due to finished move");
1702 pa_sink_request_rewind(s
, nbytes
);
1705 /* In flat volume mode we need to update the volume as
1707 return o
->process_msg(o
, PA_SINK_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
);
1710 case PA_SINK_MESSAGE_SET_VOLUME
:
1712 if (!pa_cvolume_equal(&s
->thread_info
.soft_volume
, &s
->soft_volume
)) {
1713 s
->thread_info
.soft_volume
= s
->soft_volume
;
1714 pa_sink_request_rewind(s
, (size_t) -1);
1717 if (!(s
->flags
& PA_SINK_FLAT_VOLUME
))
1720 /* Fall through ... */
1722 case PA_SINK_MESSAGE_SYNC_VOLUMES
:
1723 sync_input_volumes_within_thread(s
);
1726 case PA_SINK_MESSAGE_GET_VOLUME
:
1729 case PA_SINK_MESSAGE_SET_MUTE
:
1731 if (s
->thread_info
.soft_muted
!= s
->muted
) {
1732 s
->thread_info
.soft_muted
= s
->muted
;
1733 pa_sink_request_rewind(s
, (size_t) -1);
1738 case PA_SINK_MESSAGE_GET_MUTE
:
1741 case PA_SINK_MESSAGE_SET_STATE
: {
1743 pa_bool_t suspend_change
=
1744 (s
->thread_info
.state
== PA_SINK_SUSPENDED
&& PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
1745 (PA_SINK_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SINK_SUSPENDED
);
1747 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
1749 if (s
->thread_info
.state
== PA_SINK_SUSPENDED
) {
1750 s
->thread_info
.rewind_nbytes
= 0;
1751 s
->thread_info
.rewind_requested
= FALSE
;
1754 if (suspend_change
) {
1758 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
1759 if (i
->suspend_within_thread
)
1760 i
->suspend_within_thread(i
, s
->thread_info
.state
== PA_SINK_SUSPENDED
);
1766 case PA_SINK_MESSAGE_DETACH
:
1768 /* Detach all streams */
1769 pa_sink_detach_within_thread(s
);
1772 case PA_SINK_MESSAGE_ATTACH
:
1774 /* Reattach all streams */
1775 pa_sink_attach_within_thread(s
);
1778 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY
: {
1780 pa_usec_t
*usec
= userdata
;
1781 *usec
= pa_sink_get_requested_latency_within_thread(s
);
1783 if (*usec
== (pa_usec_t
) -1)
1784 *usec
= s
->thread_info
.max_latency
;
1789 case PA_SINK_MESSAGE_SET_LATENCY_RANGE
: {
1790 pa_usec_t
*r
= userdata
;
1792 pa_sink_set_latency_range_within_thread(s
, r
[0], r
[1]);
1797 case PA_SINK_MESSAGE_GET_LATENCY_RANGE
: {
1798 pa_usec_t
*r
= userdata
;
1800 r
[0] = s
->thread_info
.min_latency
;
1801 r
[1] = s
->thread_info
.max_latency
;
1806 case PA_SINK_MESSAGE_GET_MAX_REWIND
:
1808 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1811 case PA_SINK_MESSAGE_GET_MAX_REQUEST
:
1813 *((size_t*) userdata
) = s
->thread_info
.max_request
;
1816 case PA_SINK_MESSAGE_SET_MAX_REWIND
:
1818 pa_sink_set_max_rewind_within_thread(s
, (size_t) offset
);
1821 case PA_SINK_MESSAGE_SET_MAX_REQUEST
:
1823 pa_sink_set_max_request_within_thread(s
, (size_t) offset
);
1826 case PA_SINK_MESSAGE_GET_LATENCY
:
1827 case PA_SINK_MESSAGE_MAX
:
1834 /* Called from main thread */
1835 int pa_sink_suspend_all(pa_core
*c
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
1840 pa_core_assert_ref(c
);
1841 pa_assert(cause
!= 0);
1843 for (sink
= PA_SINK(pa_idxset_first(c
->sinks
, &idx
)); sink
; sink
= PA_SINK(pa_idxset_next(c
->sinks
, &idx
))) {
1846 if ((r
= pa_sink_suspend(sink
, suspend
, cause
)) < 0)
1853 /* Called from main thread */
1854 void pa_sink_detach(pa_sink
*s
) {
1855 pa_sink_assert_ref(s
);
1856 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1858 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1861 /* Called from main thread */
1862 void pa_sink_attach(pa_sink
*s
) {
1863 pa_sink_assert_ref(s
);
1864 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1866 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1869 /* Called from IO thread */
1870 void pa_sink_detach_within_thread(pa_sink
*s
) {
1874 pa_sink_assert_ref(s
);
1875 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
1877 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
1881 if (s
->monitor_source
)
1882 pa_source_detach_within_thread(s
->monitor_source
);
1885 /* Called from IO thread */
1886 void pa_sink_attach_within_thread(pa_sink
*s
) {
1890 pa_sink_assert_ref(s
);
1891 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
1893 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
1897 if (s
->monitor_source
)
1898 pa_source_attach_within_thread(s
->monitor_source
);
1901 /* Called from IO thread */
1902 void pa_sink_request_rewind(pa_sink
*s
, size_t nbytes
) {
1903 pa_sink_assert_ref(s
);
1904 pa_assert(PA_SINK_IS_LINKED(s
->thread_info
.state
));
1906 if (s
->thread_info
.state
== PA_SINK_SUSPENDED
)
1909 if (nbytes
== (size_t) -1)
1910 nbytes
= s
->thread_info
.max_rewind
;
1912 nbytes
= PA_MIN(nbytes
, s
->thread_info
.max_rewind
);
1914 if (s
->thread_info
.rewind_requested
&&
1915 nbytes
<= s
->thread_info
.rewind_nbytes
)
1918 s
->thread_info
.rewind_nbytes
= nbytes
;
1919 s
->thread_info
.rewind_requested
= TRUE
;
1921 if (s
->request_rewind
)
1922 s
->request_rewind(s
);
1925 /* Called from IO thread */
1926 pa_usec_t
pa_sink_get_requested_latency_within_thread(pa_sink
*s
) {
1927 pa_usec_t result
= (pa_usec_t
) -1;
1930 pa_usec_t monitor_latency
;
1932 pa_sink_assert_ref(s
);
1934 if (!(s
->flags
& PA_SINK_DYNAMIC_LATENCY
))
1935 return PA_CLAMP(s
->fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1937 if (s
->thread_info
.requested_latency_valid
)
1938 return s
->thread_info
.requested_latency
;
1940 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
1942 if (i
->thread_info
.requested_sink_latency
!= (pa_usec_t
) -1 &&
1943 (result
== (pa_usec_t
) -1 || result
> i
->thread_info
.requested_sink_latency
))
1944 result
= i
->thread_info
.requested_sink_latency
;
1946 monitor_latency
= pa_source_get_requested_latency_within_thread(s
->monitor_source
);
1948 if (monitor_latency
!= (pa_usec_t
) -1 &&
1949 (result
== (pa_usec_t
) -1 || result
> monitor_latency
))
1950 result
= monitor_latency
;
1952 if (result
!= (pa_usec_t
) -1)
1953 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1955 if (PA_SINK_IS_LINKED(s
->thread_info
.state
)) {
1956 /* Only cache if properly initialized */
1957 s
->thread_info
.requested_latency
= result
;
1958 s
->thread_info
.requested_latency_valid
= TRUE
;
1964 /* Called from main thread */
1965 pa_usec_t
pa_sink_get_requested_latency(pa_sink
*s
) {
1968 pa_sink_assert_ref(s
);
1969 pa_assert(PA_SINK_IS_LINKED(s
->state
));
1971 if (s
->state
== PA_SINK_SUSPENDED
)
1974 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1978 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1979 void pa_sink_set_max_rewind_within_thread(pa_sink
*s
, size_t max_rewind
) {
1983 pa_sink_assert_ref(s
);
1985 if (max_rewind
== s
->thread_info
.max_rewind
)
1988 s
->thread_info
.max_rewind
= max_rewind
;
1990 if (PA_SINK_IS_LINKED(s
->thread_info
.state
)) {
1991 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
1992 pa_sink_input_update_max_rewind(i
, s
->thread_info
.max_rewind
);
1995 if (s
->monitor_source
)
1996 pa_source_set_max_rewind_within_thread(s
->monitor_source
, s
->thread_info
.max_rewind
);
1999 /* Called from main thread */
2000 void pa_sink_set_max_rewind(pa_sink
*s
, size_t max_rewind
) {
2001 pa_sink_assert_ref(s
);
2003 if (PA_SINK_IS_LINKED(s
->state
))
2004 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
2006 pa_sink_set_max_rewind_within_thread(s
, max_rewind
);
2009 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
2010 void pa_sink_set_max_request_within_thread(pa_sink
*s
, size_t max_request
) {
2013 pa_sink_assert_ref(s
);
2015 if (max_request
== s
->thread_info
.max_request
)
2018 s
->thread_info
.max_request
= max_request
;
2020 if (PA_SINK_IS_LINKED(s
->thread_info
.state
)) {
2023 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
2024 pa_sink_input_update_max_request(i
, s
->thread_info
.max_request
);
2028 /* Called from main thread */
2029 void pa_sink_set_max_request(pa_sink
*s
, size_t max_request
) {
2030 pa_sink_assert_ref(s
);
2032 if (PA_SINK_IS_LINKED(s
->state
))
2033 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_MAX_REQUEST
, NULL
, max_request
, NULL
) == 0);
2035 pa_sink_set_max_request_within_thread(s
, max_request
);
2038 /* Called from IO thread */
2039 void pa_sink_invalidate_requested_latency(pa_sink
*s
) {
2043 pa_sink_assert_ref(s
);
2045 if (!(s
->flags
& PA_SINK_DYNAMIC_LATENCY
))
2048 s
->thread_info
.requested_latency_valid
= FALSE
;
2050 if (PA_SINK_IS_LINKED(s
->thread_info
.state
)) {
2052 if (s
->update_requested_latency
)
2053 s
->update_requested_latency(s
);
2055 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
2056 if (i
->update_sink_requested_latency
)
2057 i
->update_sink_requested_latency(i
);
2061 /* Called from main thread */
2062 void pa_sink_set_latency_range(pa_sink
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
2063 pa_sink_assert_ref(s
);
2065 /* min_latency == 0: no limit
2066 * min_latency anything else: specified limit
2068 * Similar for max_latency */
2070 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
2071 min_latency
= ABSOLUTE_MIN_LATENCY
;
2073 if (max_latency
<= 0 ||
2074 max_latency
> ABSOLUTE_MAX_LATENCY
)
2075 max_latency
= ABSOLUTE_MAX_LATENCY
;
2077 pa_assert(min_latency
<= max_latency
);
2079 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
2080 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
2081 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
2082 (s
->flags
& PA_SINK_DYNAMIC_LATENCY
));
2084 if (PA_SINK_IS_LINKED(s
->state
)) {
2090 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
2092 pa_sink_set_latency_range_within_thread(s
, min_latency
, max_latency
);
2095 /* Called from main thread */
2096 void pa_sink_get_latency_range(pa_sink
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
2097 pa_sink_assert_ref(s
);
2098 pa_assert(min_latency
);
2099 pa_assert(max_latency
);
2101 if (PA_SINK_IS_LINKED(s
->state
)) {
2102 pa_usec_t r
[2] = { 0, 0 };
2104 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
2106 *min_latency
= r
[0];
2107 *max_latency
= r
[1];
2109 *min_latency
= s
->thread_info
.min_latency
;
2110 *max_latency
= s
->thread_info
.max_latency
;
2114 /* Called from IO thread */
2115 void pa_sink_set_latency_range_within_thread(pa_sink
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
2118 pa_sink_assert_ref(s
);
2120 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
2121 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
2122 pa_assert(min_latency
<= max_latency
);
2124 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
2125 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
2126 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
2127 (s
->flags
& PA_SINK_DYNAMIC_LATENCY
));
2129 s
->thread_info
.min_latency
= min_latency
;
2130 s
->thread_info
.max_latency
= max_latency
;
2132 if (PA_SINK_IS_LINKED(s
->thread_info
.state
)) {
2135 while ((i
= pa_hashmap_iterate(s
->thread_info
.inputs
, &state
, NULL
)))
2136 if (i
->update_sink_latency_range
)
2137 i
->update_sink_latency_range(i
);
2140 pa_sink_invalidate_requested_latency(s
);
2142 pa_source_set_latency_range_within_thread(s
->monitor_source
, min_latency
, max_latency
);
2145 /* Called from main thread, before the sink is put */
2146 void pa_sink_set_fixed_latency(pa_sink
*s
, pa_usec_t latency
) {
2147 pa_sink_assert_ref(s
);
2149 pa_assert(pa_sink_get_state(s
) == PA_SINK_INIT
);
2151 if (latency
< ABSOLUTE_MIN_LATENCY
)
2152 latency
= ABSOLUTE_MIN_LATENCY
;
2154 if (latency
> ABSOLUTE_MAX_LATENCY
)
2155 latency
= ABSOLUTE_MAX_LATENCY
;
2157 s
->fixed_latency
= latency
;
2158 pa_source_set_fixed_latency(s
->monitor_source
, latency
);
2161 /* Called from main context */
2162 size_t pa_sink_get_max_rewind(pa_sink
*s
) {
2164 pa_sink_assert_ref(s
);
2166 if (!PA_SINK_IS_LINKED(s
->state
))
2167 return s
->thread_info
.max_rewind
;
2169 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);
2174 /* Called from main context */
2175 size_t pa_sink_get_max_request(pa_sink
*s
) {
2177 pa_sink_assert_ref(s
);
2179 if (!PA_SINK_IS_LINKED(s
->state
))
2180 return s
->thread_info
.max_request
;
2182 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SINK_MESSAGE_GET_MAX_REQUEST
, &r
, 0, NULL
) == 0);
2187 /* Called from main context */
2188 pa_bool_t
pa_device_init_icon(pa_proplist
*p
, pa_bool_t is_sink
) {
2189 const char *ff
, *c
, *t
= NULL
, *s
= "", *profile
, *bus
;
2193 if (pa_proplist_contains(p
, PA_PROP_DEVICE_ICON_NAME
))
2196 if ((ff
= pa_proplist_gets(p
, PA_PROP_DEVICE_FORM_FACTOR
))) {
2198 if (pa_streq(ff
, "microphone"))
2199 t
= "audio-input-microphone";
2200 else if (pa_streq(ff
, "webcam"))
2202 else if (pa_streq(ff
, "computer"))
2204 else if (pa_streq(ff
, "handset"))
2206 else if (pa_streq(ff
, "portable"))
2207 t
= "multimedia-player";
2208 else if (pa_streq(ff
, "tv"))
2209 t
= "video-display";
2212 * The following icons are not part of the icon naming spec,
2213 * because Rodney Dawes sucks as the maintainer of that spec.
2215 * http://lists.freedesktop.org/archives/xdg/2009-May/010397.html
2217 else if (pa_streq(ff
, "headset"))
2218 t
= "audio-headset";
2219 else if (pa_streq(ff
, "headphone"))
2220 t
= "audio-headphones";
2221 else if (pa_streq(ff
, "speaker"))
2222 t
= "audio-speakers";
2223 else if (pa_streq(ff
, "hands-free"))
2224 t
= "audio-handsfree";
2228 if ((c
= pa_proplist_gets(p
, PA_PROP_DEVICE_CLASS
)))
2229 if (pa_streq(c
, "modem"))
2236 t
= "audio-input-microphone";
2239 if ((profile
= pa_proplist_gets(p
, PA_PROP_DEVICE_PROFILE_NAME
))) {
2240 if (strstr(profile
, "analog"))
2242 else if (strstr(profile
, "iec958"))
2244 else if (strstr(profile
, "hdmi"))
2248 bus
= pa_proplist_gets(p
, PA_PROP_DEVICE_BUS
);
2250 pa_proplist_setf(p
, PA_PROP_DEVICE_ICON_NAME
, "%s%s%s%s", t
, pa_strempty(s
), bus
? "-" : "", pa_strempty(bus
));
2255 pa_bool_t
pa_device_init_description(pa_proplist
*p
) {
2259 if (pa_proplist_contains(p
, PA_PROP_DEVICE_DESCRIPTION
))
2262 if ((s
= pa_proplist_gets(p
, PA_PROP_DEVICE_FORM_FACTOR
)))
2263 if (pa_streq(s
, "internal")) {
2264 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, _("Internal Audio"));
2268 if ((s
= pa_proplist_gets(p
, PA_PROP_DEVICE_CLASS
)))
2269 if (pa_streq(s
, "modem")) {
2270 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, _("Modem"));
2274 if ((s
= pa_proplist_gets(p
, PA_PROP_DEVICE_PRODUCT_NAME
))) {
2275 pa_proplist_sets(p
, PA_PROP_DEVICE_DESCRIPTION
, s
);