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/utf8.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
36 #include <pulsecore/source-output.h>
37 #include <pulsecore/namereg.h>
38 #include <pulsecore/core-subscribe.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/sample-util.h>
44 #define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
46 static PA_DEFINE_CHECK_TYPE(pa_source
, pa_msgobject
);
48 static void source_free(pa_object
*o
);
50 pa_source_new_data
* pa_source_new_data_init(pa_source_new_data
*data
) {
53 memset(data
, 0, sizeof(*data
));
54 data
->proplist
= pa_proplist_new();
59 void pa_source_new_data_set_name(pa_source_new_data
*data
, const char *name
) {
63 data
->name
= pa_xstrdup(name
);
66 void pa_source_new_data_set_sample_spec(pa_source_new_data
*data
, const pa_sample_spec
*spec
) {
69 if ((data
->sample_spec_is_set
= !!spec
))
70 data
->sample_spec
= *spec
;
73 void pa_source_new_data_set_channel_map(pa_source_new_data
*data
, const pa_channel_map
*map
) {
76 if ((data
->channel_map_is_set
= !!map
))
77 data
->channel_map
= *map
;
80 void pa_source_new_data_set_volume(pa_source_new_data
*data
, const pa_cvolume
*volume
) {
83 if ((data
->volume_is_set
= !!volume
))
84 data
->volume
= *volume
;
87 void pa_source_new_data_set_muted(pa_source_new_data
*data
, pa_bool_t mute
) {
90 data
->muted_is_set
= TRUE
;
94 void pa_source_new_data_done(pa_source_new_data
*data
) {
98 pa_proplist_free(data
->proplist
);
101 /* Called from main context */
102 static void reset_callbacks(pa_source
*s
) {
106 s
->get_volume
= NULL
;
107 s
->set_volume
= NULL
;
110 s
->update_requested_latency
= NULL
;
113 /* Called from main context */
114 pa_source
* pa_source_new(
116 pa_source_new_data
*data
,
117 pa_source_flags_t flags
) {
121 char st
[PA_SAMPLE_SPEC_SNPRINT_MAX
], cm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
126 pa_assert(data
->name
);
128 s
= pa_msgobject_new(pa_source
);
130 if (!(name
= pa_namereg_register(core
, data
->name
, PA_NAMEREG_SOURCE
, s
, data
->namereg_fail
))) {
135 pa_source_new_data_set_name(data
, name
);
137 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_NEW
], data
) < 0) {
139 pa_namereg_unregister(core
, name
);
143 pa_return_null_if_fail(!data
->driver
|| pa_utf8_valid(data
->driver
));
144 pa_return_null_if_fail(data
->name
&& pa_utf8_valid(data
->name
) && data
->name
[0]);
146 pa_return_null_if_fail(data
->sample_spec_is_set
&& pa_sample_spec_valid(&data
->sample_spec
));
148 if (!data
->channel_map_is_set
)
149 pa_return_null_if_fail(pa_channel_map_init_auto(&data
->channel_map
, data
->sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
));
151 pa_return_null_if_fail(pa_channel_map_valid(&data
->channel_map
));
152 pa_return_null_if_fail(data
->channel_map
.channels
== data
->sample_spec
.channels
);
154 if (!data
->volume_is_set
)
155 pa_cvolume_reset(&data
->volume
, data
->sample_spec
.channels
);
157 pa_return_null_if_fail(pa_cvolume_valid(&data
->volume
));
158 pa_return_null_if_fail(data
->volume
.channels
== data
->sample_spec
.channels
);
160 if (!data
->muted_is_set
)
164 pa_proplist_update(data
->proplist
, PA_UPDATE_MERGE
, data
->card
->proplist
);
166 pa_device_init_description(data
->proplist
);
167 pa_device_init_icon(data
->proplist
, FALSE
);
169 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_FIXATE
], data
) < 0) {
171 pa_namereg_unregister(core
, name
);
175 s
->parent
.parent
.free
= source_free
;
176 s
->parent
.process_msg
= pa_source_process_msg
;
179 s
->state
= PA_SOURCE_INIT
;
181 s
->name
= pa_xstrdup(name
);
182 s
->proplist
= pa_proplist_copy(data
->proplist
);
183 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
184 s
->module
= data
->module
;
185 s
->card
= data
->card
;
187 s
->sample_spec
= data
->sample_spec
;
188 s
->channel_map
= data
->channel_map
;
190 s
->outputs
= pa_idxset_new(NULL
, NULL
);
192 s
->monitor_of
= NULL
;
194 s
->virtual_volume
= data
->volume
;
195 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
196 s
->base_volume
= PA_VOLUME_NORM
;
197 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
198 s
->muted
= data
->muted
;
199 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
207 pa_silence_memchunk_get(
208 &core
->silence_cache
,
214 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
215 s
->thread_info
.soft_volume
= s
->soft_volume
;
216 s
->thread_info
.soft_muted
= s
->muted
;
217 s
->thread_info
.state
= s
->state
;
218 s
->thread_info
.max_rewind
= 0;
219 s
->thread_info
.requested_latency_valid
= FALSE
;
220 s
->thread_info
.requested_latency
= 0;
221 s
->thread_info
.min_latency
= DEFAULT_MIN_LATENCY
;
222 s
->thread_info
.max_latency
= 0;
224 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
227 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
229 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
230 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
233 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
234 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
241 /* Called from main context */
242 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
244 pa_bool_t suspend_change
;
245 pa_source_state_t original_state
;
249 if (s
->state
== state
)
252 original_state
= s
->state
;
255 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
256 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
259 if ((ret
= s
->set_state(s
, state
)) < 0)
263 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
266 s
->set_state(s
, original_state
);
273 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
274 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
275 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
278 if (suspend_change
) {
282 /* We're suspending or resuming, tell everyone about it */
284 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
)))
285 if (s
->state
== PA_SOURCE_SUSPENDED
&&
286 (o
->flags
& PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND
))
287 pa_source_output_kill(o
);
289 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
296 /* Called from main context */
297 void pa_source_put(pa_source
*s
) {
298 pa_source_assert_ref(s
);
300 pa_assert(s
->state
== PA_SOURCE_INIT
);
302 /* The following fields must be initialized properly when calling _put() */
303 pa_assert(s
->asyncmsgq
);
304 pa_assert(s
->rtpoll
);
305 pa_assert(!s
->thread_info
.min_latency
|| !s
->thread_info
.max_latency
||
306 s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
308 if (!(s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
)) {
309 s
->flags
|= PA_SOURCE_DECIBEL_VOLUME
;
311 s
->thread_info
.soft_volume
= s
->soft_volume
;
312 s
->thread_info
.soft_muted
= s
->muted
;
315 if (s
->flags
& PA_SOURCE_DECIBEL_VOLUME
)
316 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
318 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
320 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
321 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
324 /* Called from main context */
325 void pa_source_unlink(pa_source
*s
) {
327 pa_source_output
*o
, *j
= NULL
;
331 /* See pa_sink_unlink() for a couple of comments how this function
334 linked
= PA_SOURCE_IS_LINKED(s
->state
);
337 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
339 if (s
->state
!= PA_SOURCE_UNLINKED
)
340 pa_namereg_unregister(s
->core
, s
->name
);
341 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
344 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
346 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
348 pa_source_output_kill(o
);
353 source_set_state(s
, PA_SOURCE_UNLINKED
);
355 s
->state
= PA_SOURCE_UNLINKED
;
360 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
361 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
365 /* Called from main context */
366 static void source_free(pa_object
*o
) {
367 pa_source_output
*so
;
368 pa_source
*s
= PA_SOURCE(o
);
371 pa_assert(pa_source_refcnt(s
) == 0);
373 if (PA_SOURCE_IS_LINKED(s
->state
))
376 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
378 pa_idxset_free(s
->outputs
, NULL
, NULL
);
380 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
381 pa_source_output_unref(so
);
383 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
385 if (s
->silence
.memblock
)
386 pa_memblock_unref(s
->silence
.memblock
);
392 pa_proplist_free(s
->proplist
);
397 /* Called from main context */
398 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
399 pa_source_assert_ref(s
);
404 /* Called from main context */
405 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
406 pa_source_assert_ref(s
);
411 /* Called from main context */
412 int pa_source_update_status(pa_source
*s
) {
413 pa_source_assert_ref(s
);
414 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
416 if (s
->state
== PA_SOURCE_SUSPENDED
)
419 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
422 /* Called from main context */
423 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
) {
424 pa_source_assert_ref(s
);
425 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
428 return -PA_ERR_NOTSUPPORTED
;
431 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
433 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
436 /* Called from main context */
437 int pa_source_sync_suspend(pa_source
*s
) {
438 pa_sink_state_t state
;
440 pa_source_assert_ref(s
);
441 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
442 pa_assert(s
->monitor_of
);
444 state
= pa_sink_get_state(s
->monitor_of
);
446 if (state
== PA_SINK_SUSPENDED
)
447 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
449 pa_assert(PA_SINK_IS_OPENED(state
));
451 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
454 /* Called from main context */
455 pa_queue
*pa_source_move_all_start(pa_source
*s
) {
457 pa_source_output
*o
, *n
;
460 pa_source_assert_ref(s
);
461 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
465 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
466 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
468 if (pa_source_output_start_move(o
) >= 0)
469 pa_queue_push(q
, pa_source_output_ref(o
));
475 /* Called from main context */
476 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
479 pa_source_assert_ref(s
);
480 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
483 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
484 if (pa_source_output_finish_move(o
, s
, save
) < 0)
485 pa_source_output_kill(o
);
487 pa_source_output_unref(o
);
490 pa_queue_free(q
, NULL
, NULL
);
493 /* Called from main context */
494 void pa_source_move_all_fail(pa_queue
*q
) {
498 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
499 if (pa_hook_fire(&o
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL
], o
) == PA_HOOK_OK
) {
500 pa_source_output_kill(o
);
501 pa_source_output_unref(o
);
505 pa_queue_free(q
, NULL
, NULL
);
508 /* Called from IO thread context */
509 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
513 pa_source_assert_ref(s
);
514 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
516 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
522 pa_log_debug("Processing rewind...");
524 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
525 pa_source_output_assert_ref(o
);
526 pa_source_output_process_rewind(o
, nbytes
);
530 /* Called from IO thread context */
531 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
535 pa_source_assert_ref(s
);
536 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
539 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
542 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
543 pa_memchunk vchunk
= *chunk
;
545 pa_memblock_ref(vchunk
.memblock
);
546 pa_memchunk_make_writable(&vchunk
, 0);
548 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
549 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
551 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
553 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
554 pa_source_output_assert_ref(o
);
556 if (!o
->thread_info
.direct_on_input
)
557 pa_source_output_push(o
, &vchunk
);
560 pa_memblock_unref(vchunk
.memblock
);
563 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
564 pa_source_output_assert_ref(o
);
566 if (!o
->thread_info
.direct_on_input
)
567 pa_source_output_push(o
, chunk
);
572 /* Called from IO thread context */
573 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
574 pa_source_assert_ref(s
);
575 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
576 pa_source_output_assert_ref(o
);
577 pa_assert(o
->thread_info
.direct_on_input
);
580 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
583 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
584 pa_memchunk vchunk
= *chunk
;
586 pa_memblock_ref(vchunk
.memblock
);
587 pa_memchunk_make_writable(&vchunk
, 0);
589 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
590 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
592 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
594 pa_source_output_push(o
, &vchunk
);
596 pa_memblock_unref(vchunk
.memblock
);
598 pa_source_output_push(o
, chunk
);
601 /* Called from main thread */
602 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
605 pa_source_assert_ref(s
);
606 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
608 if (s
->state
== PA_SOURCE_SUSPENDED
)
611 if (!(s
->flags
& PA_SOURCE_LATENCY
))
614 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
619 /* Called from main thread */
620 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
) {
621 pa_cvolume old_virtual_volume
;
622 pa_bool_t virtual_volume_changed
;
624 pa_source_assert_ref(s
);
625 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
627 pa_assert(pa_cvolume_valid(volume
));
628 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
630 old_virtual_volume
= s
->virtual_volume
;
631 s
->virtual_volume
= *volume
;
632 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
635 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
638 s
->soft_volume
= s
->virtual_volume
;
640 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
642 if (virtual_volume_changed
)
643 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
646 /* Called from main thread. Only to be called by source implementor */
647 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
648 pa_source_assert_ref(s
);
651 if (PA_SOURCE_IS_LINKED(s
->state
))
652 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
654 s
->thread_info
.soft_volume
= *volume
;
657 /* Called from main thread */
658 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
659 pa_source_assert_ref(s
);
660 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
662 if (s
->refresh_volume
|| force_refresh
) {
663 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
668 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
670 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
))
671 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
674 return &s
->virtual_volume
;
677 /* Called from main thread */
678 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
679 pa_source_assert_ref(s
);
681 /* The source implementor may call this if the volume changed to make sure everyone is notified */
683 if (pa_cvolume_equal(&s
->virtual_volume
, new_volume
))
686 s
->virtual_volume
= *new_volume
;
687 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
690 /* Called from main thread */
691 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
) {
694 pa_source_assert_ref(s
);
695 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
697 old_muted
= s
->muted
;
703 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
705 if (old_muted
!= s
->muted
)
706 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
709 /* Called from main thread */
710 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
711 pa_source_assert_ref(s
);
712 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
714 if (s
->refresh_muted
|| force_refresh
) {
715 pa_bool_t old_muted
= s
->muted
;
720 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
722 if (old_muted
!= s
->muted
)
723 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
729 /* Called from main thread */
730 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
731 pa_source_assert_ref(s
);
733 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
735 if (s
->muted
== new_muted
)
738 s
->muted
= new_muted
;
739 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
742 /* Called from main thread */
743 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
744 pa_source_assert_ref(s
);
747 pa_proplist_update(s
->proplist
, mode
, p
);
749 if (PA_SOURCE_IS_LINKED(s
->state
)) {
750 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
751 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
757 /* Called from main thread */
758 void pa_source_set_description(pa_source
*s
, const char *description
) {
760 pa_source_assert_ref(s
);
762 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
765 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
767 if (old
&& description
&& !strcmp(old
, description
))
771 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
773 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
775 if (PA_SOURCE_IS_LINKED(s
->state
)) {
776 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
777 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
781 /* Called from main thread */
782 unsigned pa_source_linked_by(pa_source
*s
) {
783 pa_source_assert_ref(s
);
784 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
786 return pa_idxset_size(s
->outputs
);
789 /* Called from main thread */
790 unsigned pa_source_used_by(pa_source
*s
) {
793 pa_source_assert_ref(s
);
794 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
796 ret
= pa_idxset_size(s
->outputs
);
797 pa_assert(ret
>= s
->n_corked
);
799 return ret
- s
->n_corked
;
802 /* Called from main thread */
803 unsigned pa_source_check_suspend(pa_source
*s
) {
808 pa_source_assert_ref(s
);
810 if (!PA_SOURCE_IS_LINKED(s
->state
))
815 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
))) {
816 pa_source_output_state_t st
;
818 st
= pa_source_output_get_state(o
);
819 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
821 if (st
== PA_SOURCE_OUTPUT_CORKED
)
824 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
833 /* Called from IO thread, except when it is not */
834 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
835 pa_source
*s
= PA_SOURCE(object
);
836 pa_source_assert_ref(s
);
838 switch ((pa_source_message_t
) code
) {
840 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
841 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
843 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
845 if (o
->direct_on_input
) {
846 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
847 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
850 pa_assert(!o
->thread_info
.attached
);
851 o
->thread_info
.attached
= TRUE
;
856 pa_source_output_set_state_within_thread(o
, o
->state
);
858 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
859 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
861 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
863 /* We don't just invalidate the requested latency here,
864 * because if we are in a move we might need to fix up the
865 * requested latency. */
866 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
871 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
872 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
874 pa_source_output_set_state_within_thread(o
, o
->state
);
879 pa_assert(o
->thread_info
.attached
);
880 o
->thread_info
.attached
= FALSE
;
882 if (o
->thread_info
.direct_on_input
) {
883 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
884 o
->thread_info
.direct_on_input
= NULL
;
887 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
888 pa_source_output_unref(o
);
890 pa_source_invalidate_requested_latency(s
);
895 case PA_SOURCE_MESSAGE_SET_VOLUME
:
896 s
->thread_info
.soft_volume
= s
->soft_volume
;
899 case PA_SOURCE_MESSAGE_GET_VOLUME
:
902 case PA_SOURCE_MESSAGE_SET_MUTE
:
903 s
->thread_info
.soft_muted
= s
->muted
;
906 case PA_SOURCE_MESSAGE_GET_MUTE
:
909 case PA_SOURCE_MESSAGE_SET_STATE
:
910 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
913 case PA_SOURCE_MESSAGE_DETACH
:
915 /* Detach all streams */
916 pa_source_detach_within_thread(s
);
919 case PA_SOURCE_MESSAGE_ATTACH
:
921 /* Reattach all streams */
922 pa_source_attach_within_thread(s
);
925 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
927 pa_usec_t
*usec
= userdata
;
928 *usec
= pa_source_get_requested_latency_within_thread(s
);
930 if (*usec
== (pa_usec_t
) -1)
931 *usec
= s
->thread_info
.max_latency
;
936 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
937 pa_usec_t
*r
= userdata
;
939 pa_source_update_latency_range(s
, r
[0], r
[1]);
944 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
945 pa_usec_t
*r
= userdata
;
947 r
[0] = s
->thread_info
.min_latency
;
948 r
[1] = s
->thread_info
.max_latency
;
953 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
955 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
958 case PA_SOURCE_MESSAGE_GET_LATENCY
:
961 *((pa_usec_t
*) userdata
) = 0;
965 /* Implementors need to overwrite this implementation! */
968 case PA_SOURCE_MESSAGE_MAX
:
975 /* Called from main thread */
976 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
) {
981 pa_core_assert_ref(c
);
983 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
986 if (source
->monitor_of
)
989 if ((r
= pa_source_suspend(source
, suspend
)) < 0)
996 /* Called from main thread */
997 void pa_source_detach(pa_source
*s
) {
998 pa_source_assert_ref(s
);
999 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1001 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1004 /* Called from main thread */
1005 void pa_source_attach(pa_source
*s
) {
1006 pa_source_assert_ref(s
);
1007 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1009 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1012 /* Called from IO thread */
1013 void pa_source_detach_within_thread(pa_source
*s
) {
1014 pa_source_output
*o
;
1017 pa_source_assert_ref(s
);
1018 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1020 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1025 /* Called from IO thread */
1026 void pa_source_attach_within_thread(pa_source
*s
) {
1027 pa_source_output
*o
;
1030 pa_source_assert_ref(s
);
1031 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1033 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1038 /* Called from IO thread */
1039 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1040 pa_usec_t result
= (pa_usec_t
) -1;
1041 pa_source_output
*o
;
1044 pa_source_assert_ref(s
);
1046 if (s
->thread_info
.requested_latency_valid
)
1047 return s
->thread_info
.requested_latency
;
1049 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1051 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1052 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1053 result
= o
->thread_info
.requested_source_latency
;
1055 if (result
!= (pa_usec_t
) -1) {
1056 if (s
->thread_info
.max_latency
> 0 && result
> s
->thread_info
.max_latency
)
1057 result
= s
->thread_info
.max_latency
;
1059 if (s
->thread_info
.min_latency
> 0 && result
< s
->thread_info
.min_latency
)
1060 result
= s
->thread_info
.min_latency
;
1063 s
->thread_info
.requested_latency
= result
;
1064 s
->thread_info
.requested_latency_valid
= TRUE
;
1069 /* Called from main thread */
1070 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1073 pa_source_assert_ref(s
);
1074 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1076 if (s
->state
== PA_SOURCE_SUSPENDED
)
1079 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1084 /* Called from IO thread */
1085 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1086 pa_source_output
*o
;
1089 pa_source_assert_ref(s
);
1091 if (max_rewind
== s
->thread_info
.max_rewind
)
1094 s
->thread_info
.max_rewind
= max_rewind
;
1096 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1097 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1098 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1102 void pa_source_invalidate_requested_latency(pa_source
*s
) {
1103 pa_source_output
*o
;
1106 pa_source_assert_ref(s
);
1108 s
->thread_info
.requested_latency_valid
= FALSE
;
1110 if (s
->update_requested_latency
)
1111 s
->update_requested_latency(s
);
1113 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1114 if (o
->update_source_requested_latency
)
1115 o
->update_source_requested_latency(o
);
1118 pa_sink_invalidate_requested_latency(s
->monitor_of
);
1121 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1122 pa_source_assert_ref(s
);
1124 /* min_latency == 0: no limit
1125 * min_latency == (size_t) -1: default limit
1126 * min_latency anything else: specified limit
1128 * Similar for max_latency */
1130 if (min_latency
== (pa_usec_t
) -1)
1131 min_latency
= DEFAULT_MIN_LATENCY
;
1133 if (max_latency
== (pa_usec_t
) -1)
1134 max_latency
= min_latency
;
1136 pa_assert(!min_latency
|| !max_latency
||
1137 min_latency
<= max_latency
);
1139 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1145 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1147 s
->thread_info
.min_latency
= min_latency
;
1148 s
->thread_info
.max_latency
= max_latency
;
1150 s
->thread_info
.requested_latency_valid
= FALSE
;
1154 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1155 pa_source_assert_ref(s
);
1156 pa_assert(min_latency
);
1157 pa_assert(max_latency
);
1159 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1160 pa_usec_t r
[2] = { 0, 0 };
1162 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1164 *min_latency
= r
[0];
1165 *max_latency
= r
[1];
1167 *min_latency
= s
->thread_info
.min_latency
;
1168 *max_latency
= s
->thread_info
.max_latency
;
1172 /* Called from IO thread */
1173 void pa_source_update_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1174 pa_source_output
*o
;
1177 pa_source_assert_ref(s
);
1179 pa_assert(!min_latency
|| !max_latency
||
1180 min_latency
<= max_latency
);
1182 s
->thread_info
.min_latency
= min_latency
;
1183 s
->thread_info
.max_latency
= max_latency
;
1185 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1186 if (o
->update_source_latency_range
)
1187 o
->update_source_latency_range(o
);
1189 pa_source_invalidate_requested_latency(s
);
1192 size_t pa_source_get_max_rewind(pa_source
*s
) {
1194 pa_source_assert_ref(s
);
1196 if (!PA_SOURCE_IS_LINKED(s
->state
))
1197 return s
->thread_info
.max_rewind
;
1199 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);