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 ABSOLUTE_MIN_LATENCY (500)
45 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
47 static PA_DEFINE_CHECK_TYPE(pa_source
, pa_msgobject
);
49 static void source_free(pa_object
*o
);
51 pa_source_new_data
* pa_source_new_data_init(pa_source_new_data
*data
) {
54 memset(data
, 0, sizeof(*data
));
55 data
->proplist
= pa_proplist_new();
60 void pa_source_new_data_set_name(pa_source_new_data
*data
, const char *name
) {
64 data
->name
= pa_xstrdup(name
);
67 void pa_source_new_data_set_sample_spec(pa_source_new_data
*data
, const pa_sample_spec
*spec
) {
70 if ((data
->sample_spec_is_set
= !!spec
))
71 data
->sample_spec
= *spec
;
74 void pa_source_new_data_set_channel_map(pa_source_new_data
*data
, const pa_channel_map
*map
) {
77 if ((data
->channel_map_is_set
= !!map
))
78 data
->channel_map
= *map
;
81 void pa_source_new_data_set_volume(pa_source_new_data
*data
, const pa_cvolume
*volume
) {
84 if ((data
->volume_is_set
= !!volume
))
85 data
->volume
= *volume
;
88 void pa_source_new_data_set_muted(pa_source_new_data
*data
, pa_bool_t mute
) {
91 data
->muted_is_set
= TRUE
;
95 void pa_source_new_data_done(pa_source_new_data
*data
) {
99 pa_proplist_free(data
->proplist
);
102 /* Called from main context */
103 static void reset_callbacks(pa_source
*s
) {
107 s
->get_volume
= NULL
;
108 s
->set_volume
= NULL
;
111 s
->update_requested_latency
= NULL
;
114 /* Called from main context */
115 pa_source
* pa_source_new(
117 pa_source_new_data
*data
,
118 pa_source_flags_t flags
) {
122 char st
[PA_SAMPLE_SPEC_SNPRINT_MAX
], cm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
127 pa_assert(data
->name
);
129 s
= pa_msgobject_new(pa_source
);
131 if (!(name
= pa_namereg_register(core
, data
->name
, PA_NAMEREG_SOURCE
, s
, data
->namereg_fail
))) {
136 pa_source_new_data_set_name(data
, name
);
138 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_NEW
], data
) < 0) {
140 pa_namereg_unregister(core
, name
);
144 pa_return_null_if_fail(!data
->driver
|| pa_utf8_valid(data
->driver
));
145 pa_return_null_if_fail(data
->name
&& pa_utf8_valid(data
->name
) && data
->name
[0]);
147 pa_return_null_if_fail(data
->sample_spec_is_set
&& pa_sample_spec_valid(&data
->sample_spec
));
149 if (!data
->channel_map_is_set
)
150 pa_return_null_if_fail(pa_channel_map_init_auto(&data
->channel_map
, data
->sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
));
152 pa_return_null_if_fail(pa_channel_map_valid(&data
->channel_map
));
153 pa_return_null_if_fail(data
->channel_map
.channels
== data
->sample_spec
.channels
);
155 if (!data
->volume_is_set
)
156 pa_cvolume_reset(&data
->volume
, data
->sample_spec
.channels
);
158 pa_return_null_if_fail(pa_cvolume_valid(&data
->volume
));
159 pa_return_null_if_fail(data
->volume
.channels
== data
->sample_spec
.channels
);
161 if (!data
->muted_is_set
)
165 pa_proplist_update(data
->proplist
, PA_UPDATE_MERGE
, data
->card
->proplist
);
167 pa_device_init_description(data
->proplist
);
168 pa_device_init_icon(data
->proplist
, FALSE
);
170 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_FIXATE
], data
) < 0) {
172 pa_namereg_unregister(core
, name
);
176 s
->parent
.parent
.free
= source_free
;
177 s
->parent
.process_msg
= pa_source_process_msg
;
180 s
->state
= PA_SOURCE_INIT
;
182 s
->name
= pa_xstrdup(name
);
183 s
->proplist
= pa_proplist_copy(data
->proplist
);
184 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
185 s
->module
= data
->module
;
186 s
->card
= data
->card
;
188 s
->sample_spec
= data
->sample_spec
;
189 s
->channel_map
= data
->channel_map
;
191 s
->outputs
= pa_idxset_new(NULL
, NULL
);
193 s
->monitor_of
= NULL
;
195 s
->virtual_volume
= data
->volume
;
196 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
197 s
->base_volume
= PA_VOLUME_NORM
;
198 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
199 s
->muted
= data
->muted
;
200 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
208 pa_silence_memchunk_get(
209 &core
->silence_cache
,
215 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
216 s
->thread_info
.soft_volume
= s
->soft_volume
;
217 s
->thread_info
.soft_muted
= s
->muted
;
218 s
->thread_info
.state
= s
->state
;
219 s
->thread_info
.max_rewind
= 0;
220 s
->thread_info
.requested_latency_valid
= FALSE
;
221 s
->thread_info
.requested_latency
= 0;
222 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
223 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
225 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
228 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
230 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
231 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
234 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
235 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
242 /* Called from main context */
243 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
245 pa_bool_t suspend_change
;
246 pa_source_state_t original_state
;
250 if (s
->state
== state
)
253 original_state
= s
->state
;
256 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
257 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
260 if ((ret
= s
->set_state(s
, state
)) < 0)
264 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
267 s
->set_state(s
, original_state
);
274 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
275 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
276 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
279 if (suspend_change
) {
283 /* We're suspending or resuming, tell everyone about it */
285 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
)))
286 if (s
->state
== PA_SOURCE_SUSPENDED
&&
287 (o
->flags
& PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND
))
288 pa_source_output_kill(o
);
290 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
297 /* Called from main context */
298 void pa_source_put(pa_source
*s
) {
299 pa_source_assert_ref(s
);
301 pa_assert(s
->state
== PA_SOURCE_INIT
);
303 /* The following fields must be initialized properly when calling _put() */
304 pa_assert(s
->asyncmsgq
);
305 pa_assert(s
->rtpoll
);
306 pa_assert(!s
->thread_info
.min_latency
|| !s
->thread_info
.max_latency
||
307 s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
309 if (!(s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
)) {
310 s
->flags
|= PA_SOURCE_DECIBEL_VOLUME
;
312 s
->thread_info
.soft_volume
= s
->soft_volume
;
313 s
->thread_info
.soft_muted
= s
->muted
;
316 if (s
->flags
& PA_SOURCE_DECIBEL_VOLUME
)
317 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
319 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
321 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
322 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
325 /* Called from main context */
326 void pa_source_unlink(pa_source
*s
) {
328 pa_source_output
*o
, *j
= NULL
;
332 /* See pa_sink_unlink() for a couple of comments how this function
335 linked
= PA_SOURCE_IS_LINKED(s
->state
);
338 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
340 if (s
->state
!= PA_SOURCE_UNLINKED
)
341 pa_namereg_unregister(s
->core
, s
->name
);
342 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
345 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
347 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
349 pa_source_output_kill(o
);
354 source_set_state(s
, PA_SOURCE_UNLINKED
);
356 s
->state
= PA_SOURCE_UNLINKED
;
361 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
362 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
366 /* Called from main context */
367 static void source_free(pa_object
*o
) {
368 pa_source_output
*so
;
369 pa_source
*s
= PA_SOURCE(o
);
372 pa_assert(pa_source_refcnt(s
) == 0);
374 if (PA_SOURCE_IS_LINKED(s
->state
))
377 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
379 pa_idxset_free(s
->outputs
, NULL
, NULL
);
381 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
382 pa_source_output_unref(so
);
384 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
386 if (s
->silence
.memblock
)
387 pa_memblock_unref(s
->silence
.memblock
);
393 pa_proplist_free(s
->proplist
);
398 /* Called from main context */
399 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
400 pa_source_assert_ref(s
);
405 /* Called from main context */
406 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
407 pa_source_assert_ref(s
);
412 /* Called from main context */
413 int pa_source_update_status(pa_source
*s
) {
414 pa_source_assert_ref(s
);
415 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
417 if (s
->state
== PA_SOURCE_SUSPENDED
)
420 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
423 /* Called from main context */
424 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
) {
425 pa_source_assert_ref(s
);
426 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
429 return -PA_ERR_NOTSUPPORTED
;
432 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
434 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
437 /* Called from main context */
438 int pa_source_sync_suspend(pa_source
*s
) {
439 pa_sink_state_t state
;
441 pa_source_assert_ref(s
);
442 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
443 pa_assert(s
->monitor_of
);
445 state
= pa_sink_get_state(s
->monitor_of
);
447 if (state
== PA_SINK_SUSPENDED
)
448 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
450 pa_assert(PA_SINK_IS_OPENED(state
));
452 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
455 /* Called from main context */
456 pa_queue
*pa_source_move_all_start(pa_source
*s
) {
458 pa_source_output
*o
, *n
;
461 pa_source_assert_ref(s
);
462 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
466 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
467 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
469 if (pa_source_output_start_move(o
) >= 0)
470 pa_queue_push(q
, pa_source_output_ref(o
));
476 /* Called from main context */
477 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
480 pa_source_assert_ref(s
);
481 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
484 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
485 if (pa_source_output_finish_move(o
, s
, save
) < 0)
486 pa_source_output_kill(o
);
488 pa_source_output_unref(o
);
491 pa_queue_free(q
, NULL
, NULL
);
494 /* Called from main context */
495 void pa_source_move_all_fail(pa_queue
*q
) {
499 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
500 if (pa_hook_fire(&o
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL
], o
) == PA_HOOK_OK
) {
501 pa_source_output_kill(o
);
502 pa_source_output_unref(o
);
506 pa_queue_free(q
, NULL
, NULL
);
509 /* Called from IO thread context */
510 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
514 pa_source_assert_ref(s
);
515 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
517 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
523 pa_log_debug("Processing rewind...");
525 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
526 pa_source_output_assert_ref(o
);
527 pa_source_output_process_rewind(o
, nbytes
);
531 /* Called from IO thread context */
532 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
536 pa_source_assert_ref(s
);
537 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
540 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
543 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
544 pa_memchunk vchunk
= *chunk
;
546 pa_memblock_ref(vchunk
.memblock
);
547 pa_memchunk_make_writable(&vchunk
, 0);
549 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
550 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
552 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
554 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
555 pa_source_output_assert_ref(o
);
557 if (!o
->thread_info
.direct_on_input
)
558 pa_source_output_push(o
, &vchunk
);
561 pa_memblock_unref(vchunk
.memblock
);
564 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
565 pa_source_output_assert_ref(o
);
567 if (!o
->thread_info
.direct_on_input
)
568 pa_source_output_push(o
, chunk
);
573 /* Called from IO thread context */
574 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
575 pa_source_assert_ref(s
);
576 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
577 pa_source_output_assert_ref(o
);
578 pa_assert(o
->thread_info
.direct_on_input
);
581 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
584 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
585 pa_memchunk vchunk
= *chunk
;
587 pa_memblock_ref(vchunk
.memblock
);
588 pa_memchunk_make_writable(&vchunk
, 0);
590 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
591 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
593 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
595 pa_source_output_push(o
, &vchunk
);
597 pa_memblock_unref(vchunk
.memblock
);
599 pa_source_output_push(o
, chunk
);
602 /* Called from main thread */
603 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
606 pa_source_assert_ref(s
);
607 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
609 if (s
->state
== PA_SOURCE_SUSPENDED
)
612 if (!(s
->flags
& PA_SOURCE_LATENCY
))
615 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
620 /* Called from IO thread */
621 pa_usec_t
pa_source_get_latency_within_thread(pa_source
*s
) {
625 pa_source_assert_ref(s
);
626 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
628 /* The returned value is supposed to be in the time domain of the sound card! */
630 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
633 if (!(s
->flags
& PA_SOURCE_LATENCY
))
638 /* We probably should make this a proper vtable callback instead of going through process_msg() */
640 if (o
->process_msg(o
, PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
646 /* Called from main thread */
647 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
) {
648 pa_cvolume old_virtual_volume
;
649 pa_bool_t virtual_volume_changed
;
651 pa_source_assert_ref(s
);
652 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
654 pa_assert(pa_cvolume_valid(volume
));
655 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
657 old_virtual_volume
= s
->virtual_volume
;
658 s
->virtual_volume
= *volume
;
659 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
662 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
665 s
->soft_volume
= s
->virtual_volume
;
667 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
669 if (virtual_volume_changed
)
670 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
673 /* Called from main thread. Only to be called by source implementor */
674 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
675 pa_source_assert_ref(s
);
678 if (PA_SOURCE_IS_LINKED(s
->state
))
679 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
681 s
->thread_info
.soft_volume
= *volume
;
684 /* Called from main thread */
685 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
686 pa_source_assert_ref(s
);
687 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
689 if (s
->refresh_volume
|| force_refresh
) {
690 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
695 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
697 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
))
698 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
701 return &s
->virtual_volume
;
704 /* Called from main thread */
705 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
706 pa_source_assert_ref(s
);
708 /* The source implementor may call this if the volume changed to make sure everyone is notified */
710 if (pa_cvolume_equal(&s
->virtual_volume
, new_volume
))
713 s
->virtual_volume
= *new_volume
;
714 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
717 /* Called from main thread */
718 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
) {
721 pa_source_assert_ref(s
);
722 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
724 old_muted
= s
->muted
;
730 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
732 if (old_muted
!= s
->muted
)
733 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
736 /* Called from main thread */
737 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
738 pa_source_assert_ref(s
);
739 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
741 if (s
->refresh_muted
|| force_refresh
) {
742 pa_bool_t old_muted
= s
->muted
;
747 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
749 if (old_muted
!= s
->muted
)
750 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
756 /* Called from main thread */
757 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
758 pa_source_assert_ref(s
);
760 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
762 if (s
->muted
== new_muted
)
765 s
->muted
= new_muted
;
766 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
769 /* Called from main thread */
770 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
771 pa_source_assert_ref(s
);
774 pa_proplist_update(s
->proplist
, mode
, p
);
776 if (PA_SOURCE_IS_LINKED(s
->state
)) {
777 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
778 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
784 /* Called from main thread */
785 void pa_source_set_description(pa_source
*s
, const char *description
) {
787 pa_source_assert_ref(s
);
789 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
792 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
794 if (old
&& description
&& !strcmp(old
, description
))
798 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
800 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
802 if (PA_SOURCE_IS_LINKED(s
->state
)) {
803 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
804 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
808 /* Called from main thread */
809 unsigned pa_source_linked_by(pa_source
*s
) {
810 pa_source_assert_ref(s
);
811 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
813 return pa_idxset_size(s
->outputs
);
816 /* Called from main thread */
817 unsigned pa_source_used_by(pa_source
*s
) {
820 pa_source_assert_ref(s
);
821 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
823 ret
= pa_idxset_size(s
->outputs
);
824 pa_assert(ret
>= s
->n_corked
);
826 return ret
- s
->n_corked
;
829 /* Called from main thread */
830 unsigned pa_source_check_suspend(pa_source
*s
) {
835 pa_source_assert_ref(s
);
837 if (!PA_SOURCE_IS_LINKED(s
->state
))
842 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
))) {
843 pa_source_output_state_t st
;
845 st
= pa_source_output_get_state(o
);
846 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
848 if (st
== PA_SOURCE_OUTPUT_CORKED
)
851 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
860 /* Called from IO thread, except when it is not */
861 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
862 pa_source
*s
= PA_SOURCE(object
);
863 pa_source_assert_ref(s
);
865 switch ((pa_source_message_t
) code
) {
867 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
868 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
870 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
872 if (o
->direct_on_input
) {
873 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
874 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
877 pa_assert(!o
->thread_info
.attached
);
878 o
->thread_info
.attached
= TRUE
;
883 pa_source_output_set_state_within_thread(o
, o
->state
);
885 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
886 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
888 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
890 /* We don't just invalidate the requested latency here,
891 * because if we are in a move we might need to fix up the
892 * requested latency. */
893 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
898 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
899 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
901 pa_source_output_set_state_within_thread(o
, o
->state
);
906 pa_assert(o
->thread_info
.attached
);
907 o
->thread_info
.attached
= FALSE
;
909 if (o
->thread_info
.direct_on_input
) {
910 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
911 o
->thread_info
.direct_on_input
= NULL
;
914 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
915 pa_source_output_unref(o
);
917 pa_source_invalidate_requested_latency(s
);
922 case PA_SOURCE_MESSAGE_SET_VOLUME
:
923 s
->thread_info
.soft_volume
= s
->soft_volume
;
926 case PA_SOURCE_MESSAGE_GET_VOLUME
:
929 case PA_SOURCE_MESSAGE_SET_MUTE
:
930 s
->thread_info
.soft_muted
= s
->muted
;
933 case PA_SOURCE_MESSAGE_GET_MUTE
:
936 case PA_SOURCE_MESSAGE_SET_STATE
:
937 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
940 case PA_SOURCE_MESSAGE_DETACH
:
942 /* Detach all streams */
943 pa_source_detach_within_thread(s
);
946 case PA_SOURCE_MESSAGE_ATTACH
:
948 /* Reattach all streams */
949 pa_source_attach_within_thread(s
);
952 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
954 pa_usec_t
*usec
= userdata
;
955 *usec
= pa_source_get_requested_latency_within_thread(s
);
957 if (*usec
== (pa_usec_t
) -1)
958 *usec
= s
->thread_info
.max_latency
;
963 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
964 pa_usec_t
*r
= userdata
;
966 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
971 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
972 pa_usec_t
*r
= userdata
;
974 r
[0] = s
->thread_info
.min_latency
;
975 r
[1] = s
->thread_info
.max_latency
;
980 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
982 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
985 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
987 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
990 case PA_SOURCE_MESSAGE_GET_LATENCY
:
993 *((pa_usec_t
*) userdata
) = 0;
997 /* Implementors need to overwrite this implementation! */
1000 case PA_SOURCE_MESSAGE_MAX
:
1007 /* Called from main thread */
1008 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
) {
1013 pa_core_assert_ref(c
);
1015 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1018 if (source
->monitor_of
)
1021 if ((r
= pa_source_suspend(source
, suspend
)) < 0)
1028 /* Called from main thread */
1029 void pa_source_detach(pa_source
*s
) {
1030 pa_source_assert_ref(s
);
1031 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1033 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1036 /* Called from main thread */
1037 void pa_source_attach(pa_source
*s
) {
1038 pa_source_assert_ref(s
);
1039 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1041 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1044 /* Called from IO thread */
1045 void pa_source_detach_within_thread(pa_source
*s
) {
1046 pa_source_output
*o
;
1049 pa_source_assert_ref(s
);
1050 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1052 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1057 /* Called from IO thread */
1058 void pa_source_attach_within_thread(pa_source
*s
) {
1059 pa_source_output
*o
;
1062 pa_source_assert_ref(s
);
1063 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1065 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1070 /* Called from IO thread */
1071 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1072 pa_usec_t result
= (pa_usec_t
) -1;
1073 pa_source_output
*o
;
1076 pa_source_assert_ref(s
);
1078 if (s
->thread_info
.requested_latency_valid
)
1079 return s
->thread_info
.requested_latency
;
1081 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1083 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1084 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1085 result
= o
->thread_info
.requested_source_latency
;
1087 if (result
!= (pa_usec_t
) -1) {
1088 if (s
->thread_info
.max_latency
> 0 && result
> s
->thread_info
.max_latency
)
1089 result
= s
->thread_info
.max_latency
;
1091 if (s
->thread_info
.min_latency
> 0 && result
< s
->thread_info
.min_latency
)
1092 result
= s
->thread_info
.min_latency
;
1095 s
->thread_info
.requested_latency
= result
;
1096 s
->thread_info
.requested_latency_valid
= TRUE
;
1101 /* Called from main thread */
1102 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1105 pa_source_assert_ref(s
);
1106 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1108 if (s
->state
== PA_SOURCE_SUSPENDED
)
1111 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1116 /* Called from IO thread */
1117 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1118 pa_source_output
*o
;
1121 pa_source_assert_ref(s
);
1123 if (max_rewind
== s
->thread_info
.max_rewind
)
1126 s
->thread_info
.max_rewind
= max_rewind
;
1128 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1129 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1130 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1134 /* Called from main thread */
1135 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1136 pa_source_assert_ref(s
);
1138 if (PA_SOURCE_IS_LINKED(s
->state
))
1139 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1141 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1144 /* Called from IO thread */
1145 void pa_source_invalidate_requested_latency(pa_source
*s
) {
1146 pa_source_output
*o
;
1149 pa_source_assert_ref(s
);
1151 s
->thread_info
.requested_latency_valid
= FALSE
;
1153 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1155 if (s
->update_requested_latency
)
1156 s
->update_requested_latency(s
);
1158 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1159 if (o
->update_source_requested_latency
)
1160 o
->update_source_requested_latency(o
);
1164 pa_sink_invalidate_requested_latency(s
->monitor_of
);
1167 /* Called from main thread */
1168 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1169 pa_source_assert_ref(s
);
1171 /* min_latency == 0: no limit
1172 * min_latency anything else: specified limit
1174 * Similar for max_latency */
1176 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1177 min_latency
= ABSOLUTE_MIN_LATENCY
;
1179 if (max_latency
<= 0 ||
1180 max_latency
> ABSOLUTE_MAX_LATENCY
)
1181 max_latency
= ABSOLUTE_MAX_LATENCY
;
1183 pa_assert(min_latency
<= max_latency
);
1185 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1186 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1187 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1188 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1190 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1196 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1198 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1201 /* Called from main thread */
1202 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1203 pa_source_assert_ref(s
);
1204 pa_assert(min_latency
);
1205 pa_assert(max_latency
);
1207 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1208 pa_usec_t r
[2] = { 0, 0 };
1210 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1212 *min_latency
= r
[0];
1213 *max_latency
= r
[1];
1215 *min_latency
= s
->thread_info
.min_latency
;
1216 *max_latency
= s
->thread_info
.max_latency
;
1220 /* Called from IO thread, and from main thread before pa_sink_put() is called */
1221 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1224 pa_source_assert_ref(s
);
1226 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1227 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1228 pa_assert(min_latency
<= max_latency
);
1230 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1231 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1232 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1233 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1236 s
->thread_info
.min_latency
= min_latency
;
1237 s
->thread_info
.max_latency
= max_latency
;
1239 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1240 pa_source_output
*o
;
1242 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1243 if (o
->update_source_latency_range
)
1244 o
->update_source_latency_range(o
);
1247 pa_source_invalidate_requested_latency(s
);
1250 /* Called from main thread */
1251 size_t pa_source_get_max_rewind(pa_source
*s
) {
1253 pa_source_assert_ref(s
);
1255 if (!PA_SOURCE_IS_LINKED(s
->state
))
1256 return s
->thread_info
.max_rewind
;
1258 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);