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)
46 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
48 static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
50 static void source_free(pa_object *o);
52 pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
55 memset(data, 0, sizeof(*data));
56 data->proplist = pa_proplist_new();
61 void pa_source_new_data_set_name(pa_source_new_data *data, const char *name) {
65 data->name = pa_xstrdup(name);
68 void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sample_spec *spec) {
71 if ((data->sample_spec_is_set = !!spec))
72 data->sample_spec = *spec;
75 void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_channel_map *map) {
78 if ((data->channel_map_is_set = !!map))
79 data->channel_map = *map;
82 void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume) {
85 if ((data->volume_is_set = !!volume))
86 data->volume = *volume;
89 void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute) {
92 data->muted_is_set = TRUE;
96 void pa_source_new_data_done(pa_source_new_data *data) {
100 pa_proplist_free(data->proplist);
103 /* Called from main context */
104 static void reset_callbacks(pa_source *s) {
108 s->get_volume = NULL;
109 s->set_volume = NULL;
112 s->update_requested_latency = NULL;
115 /* Called from main context */
116 pa_source* pa_source_new(
118 pa_source_new_data *data,
119 pa_source_flags_t flags) {
123 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
128 pa_assert(data->name);
130 s = pa_msgobject_new(pa_source);
132 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
137 pa_source_new_data_set_name(data, name);
139 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
141 pa_namereg_unregister(core, name);
145 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
146 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
148 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
150 if (!data->channel_map_is_set)
151 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
153 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
154 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
156 if (!data->volume_is_set)
157 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
159 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
160 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
162 if (!data->muted_is_set)
166 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
168 pa_device_init_description(data->proplist);
169 pa_device_init_icon(data->proplist, FALSE);
171 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
173 pa_namereg_unregister(core, name);
177 s->parent.parent.free = source_free;
178 s->parent.process_msg = pa_source_process_msg;
181 s->state = PA_SOURCE_INIT;
183 s->name = pa_xstrdup(name);
184 s->proplist = pa_proplist_copy(data->proplist);
185 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
186 s->module = data->module;
187 s->card = data->card;
189 s->sample_spec = data->sample_spec;
190 s->channel_map = data->channel_map;
192 s->outputs = pa_idxset_new(NULL, NULL);
194 s->monitor_of = NULL;
196 s->virtual_volume = data->volume;
197 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
198 s->base_volume = PA_VOLUME_NORM;
199 s->n_volume_steps = PA_VOLUME_NORM+1;
200 s->muted = data->muted;
201 s->refresh_volume = s->refresh_muted = FALSE;
203 s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
211 pa_silence_memchunk_get(
212 &core->silence_cache,
218 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
219 s->thread_info.soft_volume = s->soft_volume;
220 s->thread_info.soft_muted = s->muted;
221 s->thread_info.state = s->state;
222 s->thread_info.max_rewind = 0;
223 s->thread_info.requested_latency_valid = FALSE;
224 s->thread_info.requested_latency = 0;
225 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
226 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
228 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
231 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
233 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
234 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
237 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
238 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
245 /* Called from main context */
246 static int source_set_state(pa_source *s, pa_source_state_t state) {
248 pa_bool_t suspend_change;
249 pa_source_state_t original_state;
253 if (s->state == state)
256 original_state = s->state;
259 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
260 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
263 if ((ret = s->set_state(s, state)) < 0)
267 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
270 s->set_state(s, original_state);
277 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
278 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
279 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
282 if (suspend_change) {
286 /* We're suspending or resuming, tell everyone about it */
288 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
289 if (s->state == PA_SOURCE_SUSPENDED &&
290 (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
291 pa_source_output_kill(o);
293 o->suspend(o, state == PA_SOURCE_SUSPENDED);
300 /* Called from main context */
301 void pa_source_put(pa_source *s) {
302 pa_source_assert_ref(s);
304 pa_assert(s->state == PA_SOURCE_INIT);
306 /* The following fields must be initialized properly when calling _put() */
307 pa_assert(s->asyncmsgq);
308 pa_assert(s->rtpoll);
309 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
311 /* Generally, flags should be initialized via pa_source_new(). As
312 * a special exception we allow volume related flags to be set
313 * between _new() and _put(). */
315 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL))
316 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
318 s->thread_info.soft_volume = s->soft_volume;
319 s->thread_info.soft_muted = s->muted;
321 pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME));
322 pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
323 pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
325 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
327 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
328 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
331 /* Called from main context */
332 void pa_source_unlink(pa_source *s) {
334 pa_source_output *o, *j = NULL;
338 /* See pa_sink_unlink() for a couple of comments how this function
341 linked = PA_SOURCE_IS_LINKED(s->state);
344 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
346 if (s->state != PA_SOURCE_UNLINKED)
347 pa_namereg_unregister(s->core, s->name);
348 pa_idxset_remove_by_data(s->core->sources, s, NULL);
351 pa_idxset_remove_by_data(s->card->sources, s, NULL);
353 while ((o = pa_idxset_first(s->outputs, NULL))) {
355 pa_source_output_kill(o);
360 source_set_state(s, PA_SOURCE_UNLINKED);
362 s->state = PA_SOURCE_UNLINKED;
367 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
368 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
372 /* Called from main context */
373 static void source_free(pa_object *o) {
374 pa_source_output *so;
375 pa_source *s = PA_SOURCE(o);
378 pa_assert(pa_source_refcnt(s) == 0);
380 if (PA_SOURCE_IS_LINKED(s->state))
383 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
385 pa_idxset_free(s->outputs, NULL, NULL);
387 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
388 pa_source_output_unref(so);
390 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
392 if (s->silence.memblock)
393 pa_memblock_unref(s->silence.memblock);
399 pa_proplist_free(s->proplist);
404 /* Called from main context */
405 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
406 pa_source_assert_ref(s);
411 /* Called from main context */
412 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
413 pa_source_assert_ref(s);
418 /* Called from main context */
419 int pa_source_update_status(pa_source*s) {
420 pa_source_assert_ref(s);
421 pa_assert(PA_SOURCE_IS_LINKED(s->state));
423 if (s->state == PA_SOURCE_SUSPENDED)
426 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
429 /* Called from main context */
430 int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
431 pa_source_assert_ref(s);
432 pa_assert(PA_SOURCE_IS_LINKED(s->state));
435 return -PA_ERR_NOTSUPPORTED;
438 return source_set_state(s, PA_SOURCE_SUSPENDED);
440 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
443 /* Called from main context */
444 int pa_source_sync_suspend(pa_source *s) {
445 pa_sink_state_t state;
447 pa_source_assert_ref(s);
448 pa_assert(PA_SOURCE_IS_LINKED(s->state));
449 pa_assert(s->monitor_of);
451 state = pa_sink_get_state(s->monitor_of);
453 if (state == PA_SINK_SUSPENDED)
454 return source_set_state(s, PA_SOURCE_SUSPENDED);
456 pa_assert(PA_SINK_IS_OPENED(state));
458 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
461 /* Called from main context */
462 pa_queue *pa_source_move_all_start(pa_source *s) {
464 pa_source_output *o, *n;
467 pa_source_assert_ref(s);
468 pa_assert(PA_SOURCE_IS_LINKED(s->state));
472 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
473 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
475 pa_source_output_ref(o);
477 if (pa_source_output_start_move(o) >= 0)
480 pa_source_output_unref(o);
486 /* Called from main context */
487 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
490 pa_source_assert_ref(s);
491 pa_assert(PA_SOURCE_IS_LINKED(s->state));
494 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
495 if (pa_source_output_finish_move(o, s, save) < 0)
496 pa_source_output_kill(o);
498 pa_source_output_unref(o);
501 pa_queue_free(q, NULL, NULL);
504 /* Called from main context */
505 void pa_source_move_all_fail(pa_queue *q) {
509 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
510 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
511 pa_source_output_kill(o);
512 pa_source_output_unref(o);
516 pa_queue_free(q, NULL, NULL);
519 /* Called from IO thread context */
520 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
524 pa_source_assert_ref(s);
525 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
527 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
533 pa_log_debug("Processing rewind...");
535 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
536 pa_source_output_assert_ref(o);
537 pa_source_output_process_rewind(o, nbytes);
541 /* Called from IO thread context */
542 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
546 pa_source_assert_ref(s);
547 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
550 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
553 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
554 pa_memchunk vchunk = *chunk;
556 pa_memblock_ref(vchunk.memblock);
557 pa_memchunk_make_writable(&vchunk, 0);
559 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
560 pa_silence_memchunk(&vchunk, &s->sample_spec);
562 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
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, &vchunk);
571 pa_memblock_unref(vchunk.memblock);
574 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
575 pa_source_output_assert_ref(o);
577 if (!o->thread_info.direct_on_input)
578 pa_source_output_push(o, chunk);
583 /* Called from IO thread context */
584 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
585 pa_source_assert_ref(s);
586 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
587 pa_source_output_assert_ref(o);
588 pa_assert(o->thread_info.direct_on_input);
591 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
594 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
595 pa_memchunk vchunk = *chunk;
597 pa_memblock_ref(vchunk.memblock);
598 pa_memchunk_make_writable(&vchunk, 0);
600 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
601 pa_silence_memchunk(&vchunk, &s->sample_spec);
603 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
605 pa_source_output_push(o, &vchunk);
607 pa_memblock_unref(vchunk.memblock);
609 pa_source_output_push(o, chunk);
612 /* Called from main thread */
613 pa_usec_t pa_source_get_latency(pa_source *s) {
616 pa_source_assert_ref(s);
617 pa_assert(PA_SOURCE_IS_LINKED(s->state));
619 if (s->state == PA_SOURCE_SUSPENDED)
622 if (!(s->flags & PA_SOURCE_LATENCY))
625 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
630 /* Called from IO thread */
631 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
635 pa_source_assert_ref(s);
636 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
638 /* The returned value is supposed to be in the time domain of the sound card! */
640 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
643 if (!(s->flags & PA_SOURCE_LATENCY))
648 /* We probably should make this a proper vtable callback instead of going through process_msg() */
650 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
656 /* Called from main thread */
657 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
658 pa_cvolume old_virtual_volume;
659 pa_bool_t virtual_volume_changed;
661 pa_source_assert_ref(s);
662 pa_assert(PA_SOURCE_IS_LINKED(s->state));
664 pa_assert(pa_cvolume_valid(volume));
665 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
667 old_virtual_volume = s->virtual_volume;
668 s->virtual_volume = *volume;
669 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
672 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
675 s->soft_volume = s->virtual_volume;
677 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
679 if (virtual_volume_changed)
680 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
683 /* Called from main thread. Only to be called by source implementor */
684 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
685 pa_source_assert_ref(s);
688 if (PA_SOURCE_IS_LINKED(s->state))
689 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
691 s->thread_info.soft_volume = *volume;
694 /* Called from main thread */
695 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
696 pa_source_assert_ref(s);
697 pa_assert(PA_SOURCE_IS_LINKED(s->state));
699 if (s->refresh_volume || force_refresh) {
700 pa_cvolume old_virtual_volume = s->virtual_volume;
705 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
707 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
708 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
711 return &s->virtual_volume;
714 /* Called from main thread */
715 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
716 pa_source_assert_ref(s);
718 /* The source implementor may call this if the volume changed to make sure everyone is notified */
720 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
723 s->virtual_volume = *new_volume;
724 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
727 /* Called from main thread */
728 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
731 pa_source_assert_ref(s);
732 pa_assert(PA_SOURCE_IS_LINKED(s->state));
734 old_muted = s->muted;
740 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
742 if (old_muted != s->muted)
743 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
746 /* Called from main thread */
747 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
748 pa_source_assert_ref(s);
749 pa_assert(PA_SOURCE_IS_LINKED(s->state));
751 if (s->refresh_muted || force_refresh) {
752 pa_bool_t old_muted = s->muted;
757 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
759 if (old_muted != s->muted)
760 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
766 /* Called from main thread */
767 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
768 pa_source_assert_ref(s);
770 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
772 if (s->muted == new_muted)
775 s->muted = new_muted;
776 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
779 /* Called from main thread */
780 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
781 pa_source_assert_ref(s);
784 pa_proplist_update(s->proplist, mode, p);
786 if (PA_SOURCE_IS_LINKED(s->state)) {
787 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
788 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
794 /* Called from main thread */
795 void pa_source_set_description(pa_source *s, const char *description) {
797 pa_source_assert_ref(s);
799 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
802 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
804 if (old && description && !strcmp(old, description))
808 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
810 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
812 if (PA_SOURCE_IS_LINKED(s->state)) {
813 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
814 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
818 /* Called from main thread */
819 unsigned pa_source_linked_by(pa_source *s) {
820 pa_source_assert_ref(s);
821 pa_assert(PA_SOURCE_IS_LINKED(s->state));
823 return pa_idxset_size(s->outputs);
826 /* Called from main thread */
827 unsigned pa_source_used_by(pa_source *s) {
830 pa_source_assert_ref(s);
831 pa_assert(PA_SOURCE_IS_LINKED(s->state));
833 ret = pa_idxset_size(s->outputs);
834 pa_assert(ret >= s->n_corked);
836 return ret - s->n_corked;
839 /* Called from main thread */
840 unsigned pa_source_check_suspend(pa_source *s) {
845 pa_source_assert_ref(s);
847 if (!PA_SOURCE_IS_LINKED(s->state))
852 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
853 pa_source_output_state_t st;
855 st = pa_source_output_get_state(o);
856 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
858 if (st == PA_SOURCE_OUTPUT_CORKED)
861 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
870 /* Called from IO thread, except when it is not */
871 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
872 pa_source *s = PA_SOURCE(object);
873 pa_source_assert_ref(s);
875 switch ((pa_source_message_t) code) {
877 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
878 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
880 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
882 if (o->direct_on_input) {
883 o->thread_info.direct_on_input = o->direct_on_input;
884 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
887 pa_assert(!o->thread_info.attached);
888 o->thread_info.attached = TRUE;
893 pa_source_output_set_state_within_thread(o, o->state);
895 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
896 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
898 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
900 /* We don't just invalidate the requested latency here,
901 * because if we are in a move we might need to fix up the
902 * requested latency. */
903 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
908 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
909 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
911 pa_source_output_set_state_within_thread(o, o->state);
916 pa_assert(o->thread_info.attached);
917 o->thread_info.attached = FALSE;
919 if (o->thread_info.direct_on_input) {
920 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
921 o->thread_info.direct_on_input = NULL;
924 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
925 pa_source_output_unref(o);
927 pa_source_invalidate_requested_latency(s);
932 case PA_SOURCE_MESSAGE_SET_VOLUME:
933 s->thread_info.soft_volume = s->soft_volume;
936 case PA_SOURCE_MESSAGE_GET_VOLUME:
939 case PA_SOURCE_MESSAGE_SET_MUTE:
940 s->thread_info.soft_muted = s->muted;
943 case PA_SOURCE_MESSAGE_GET_MUTE:
946 case PA_SOURCE_MESSAGE_SET_STATE: {
948 pa_bool_t suspend_change =
949 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
950 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
952 s->thread_info.state = PA_PTR_TO_UINT(userdata);
954 if (suspend_change) {
958 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
959 if (o->suspend_within_thread)
960 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
967 case PA_SOURCE_MESSAGE_DETACH:
969 /* Detach all streams */
970 pa_source_detach_within_thread(s);
973 case PA_SOURCE_MESSAGE_ATTACH:
975 /* Reattach all streams */
976 pa_source_attach_within_thread(s);
979 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
981 pa_usec_t *usec = userdata;
982 *usec = pa_source_get_requested_latency_within_thread(s);
984 if (*usec == (pa_usec_t) -1)
985 *usec = s->thread_info.max_latency;
990 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
991 pa_usec_t *r = userdata;
993 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
998 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
999 pa_usec_t *r = userdata;
1001 r[0] = s->thread_info.min_latency;
1002 r[1] = s->thread_info.max_latency;
1007 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1009 *((size_t*) userdata) = s->thread_info.max_rewind;
1012 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1014 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1017 case PA_SOURCE_MESSAGE_GET_LATENCY:
1019 if (s->monitor_of) {
1020 *((pa_usec_t*) userdata) = 0;
1024 /* Implementors need to overwrite this implementation! */
1027 case PA_SOURCE_MESSAGE_MAX:
1034 /* Called from main thread */
1035 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
1040 pa_core_assert_ref(c);
1042 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1045 if (source->monitor_of)
1048 if ((r = pa_source_suspend(source, suspend)) < 0)
1055 /* Called from main thread */
1056 void pa_source_detach(pa_source *s) {
1057 pa_source_assert_ref(s);
1058 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1060 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1063 /* Called from main thread */
1064 void pa_source_attach(pa_source *s) {
1065 pa_source_assert_ref(s);
1066 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1068 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1071 /* Called from IO thread */
1072 void pa_source_detach_within_thread(pa_source *s) {
1073 pa_source_output *o;
1076 pa_source_assert_ref(s);
1077 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1079 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1084 /* Called from IO thread */
1085 void pa_source_attach_within_thread(pa_source *s) {
1086 pa_source_output *o;
1089 pa_source_assert_ref(s);
1090 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1092 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1097 /* Called from IO thread */
1098 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1099 pa_usec_t result = (pa_usec_t) -1;
1100 pa_source_output *o;
1103 pa_source_assert_ref(s);
1105 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1106 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1108 if (s->thread_info.requested_latency_valid)
1109 return s->thread_info.requested_latency;
1111 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1113 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1114 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1115 result = o->thread_info.requested_source_latency;
1117 if (result != (pa_usec_t) -1)
1118 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1120 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1121 /* Only cache this if we are fully set up */
1122 s->thread_info.requested_latency = result;
1123 s->thread_info.requested_latency_valid = TRUE;
1129 /* Called from main thread */
1130 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1133 pa_source_assert_ref(s);
1134 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1136 if (s->state == PA_SOURCE_SUSPENDED)
1139 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1144 /* Called from IO thread */
1145 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1146 pa_source_output *o;
1149 pa_source_assert_ref(s);
1151 if (max_rewind == s->thread_info.max_rewind)
1154 s->thread_info.max_rewind = max_rewind;
1156 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1157 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1158 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1162 /* Called from main thread */
1163 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1164 pa_source_assert_ref(s);
1166 if (PA_SOURCE_IS_LINKED(s->state))
1167 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1169 pa_source_set_max_rewind_within_thread(s, max_rewind);
1172 /* Called from IO thread */
1173 void pa_source_invalidate_requested_latency(pa_source *s) {
1174 pa_source_output *o;
1177 pa_source_assert_ref(s);
1179 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1182 s->thread_info.requested_latency_valid = FALSE;
1184 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1186 if (s->update_requested_latency)
1187 s->update_requested_latency(s);
1189 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1190 if (o->update_source_requested_latency)
1191 o->update_source_requested_latency(o);
1195 pa_sink_invalidate_requested_latency(s->monitor_of);
1198 /* Called from main thread */
1199 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1200 pa_source_assert_ref(s);
1202 /* min_latency == 0: no limit
1203 * min_latency anything else: specified limit
1205 * Similar for max_latency */
1207 if (min_latency < ABSOLUTE_MIN_LATENCY)
1208 min_latency = ABSOLUTE_MIN_LATENCY;
1210 if (max_latency <= 0 ||
1211 max_latency > ABSOLUTE_MAX_LATENCY)
1212 max_latency = ABSOLUTE_MAX_LATENCY;
1214 pa_assert(min_latency <= max_latency);
1216 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1217 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1218 max_latency == ABSOLUTE_MAX_LATENCY) ||
1219 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1221 if (PA_SOURCE_IS_LINKED(s->state)) {
1227 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1229 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1232 /* Called from main thread */
1233 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1234 pa_source_assert_ref(s);
1235 pa_assert(min_latency);
1236 pa_assert(max_latency);
1238 if (PA_SOURCE_IS_LINKED(s->state)) {
1239 pa_usec_t r[2] = { 0, 0 };
1241 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1243 *min_latency = r[0];
1244 *max_latency = r[1];
1246 *min_latency = s->thread_info.min_latency;
1247 *max_latency = s->thread_info.max_latency;
1251 /* Called from IO thread, and from main thread before pa_source_put() is called */
1252 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1255 pa_source_assert_ref(s);
1257 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1258 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1259 pa_assert(min_latency <= max_latency);
1261 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1262 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1263 max_latency == ABSOLUTE_MAX_LATENCY) ||
1264 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1267 s->thread_info.min_latency = min_latency;
1268 s->thread_info.max_latency = max_latency;
1270 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1271 pa_source_output *o;
1273 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1274 if (o->update_source_latency_range)
1275 o->update_source_latency_range(o);
1278 pa_source_invalidate_requested_latency(s);
1281 /* Called from main thread, before the source is put */
1282 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1283 pa_source_assert_ref(s);
1285 pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1287 if (latency < ABSOLUTE_MIN_LATENCY)
1288 latency = ABSOLUTE_MIN_LATENCY;
1290 if (latency > ABSOLUTE_MAX_LATENCY)
1291 latency = ABSOLUTE_MAX_LATENCY;
1293 s->fixed_latency = latency;
1296 /* Called from main thread */
1297 size_t pa_source_get_max_rewind(pa_source *s) {
1299 pa_source_assert_ref(s);
1301 if (!PA_SOURCE_IS_LINKED(s->state))
1302 return s->thread_info.max_rewind;
1304 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);