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 pa_source_output_ref(o);
471 if (pa_source_output_start_move(o) >= 0)
474 pa_source_output_unref(o);
480 /* Called from main context */
481 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
484 pa_source_assert_ref(s);
485 pa_assert(PA_SOURCE_IS_LINKED(s->state));
488 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
489 if (pa_source_output_finish_move(o, s, save) < 0)
490 pa_source_output_kill(o);
492 pa_source_output_unref(o);
495 pa_queue_free(q, NULL, NULL);
498 /* Called from main context */
499 void pa_source_move_all_fail(pa_queue *q) {
503 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
504 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
505 pa_source_output_kill(o);
506 pa_source_output_unref(o);
510 pa_queue_free(q, NULL, NULL);
513 /* Called from IO thread context */
514 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
518 pa_source_assert_ref(s);
519 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
521 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
527 pa_log_debug("Processing rewind...");
529 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
530 pa_source_output_assert_ref(o);
531 pa_source_output_process_rewind(o, nbytes);
535 /* Called from IO thread context */
536 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
540 pa_source_assert_ref(s);
541 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
544 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
547 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
548 pa_memchunk vchunk = *chunk;
550 pa_memblock_ref(vchunk.memblock);
551 pa_memchunk_make_writable(&vchunk, 0);
553 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
554 pa_silence_memchunk(&vchunk, &s->sample_spec);
556 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
558 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
559 pa_source_output_assert_ref(o);
561 if (!o->thread_info.direct_on_input)
562 pa_source_output_push(o, &vchunk);
565 pa_memblock_unref(vchunk.memblock);
568 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
569 pa_source_output_assert_ref(o);
571 if (!o->thread_info.direct_on_input)
572 pa_source_output_push(o, chunk);
577 /* Called from IO thread context */
578 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
579 pa_source_assert_ref(s);
580 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
581 pa_source_output_assert_ref(o);
582 pa_assert(o->thread_info.direct_on_input);
585 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
588 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
589 pa_memchunk vchunk = *chunk;
591 pa_memblock_ref(vchunk.memblock);
592 pa_memchunk_make_writable(&vchunk, 0);
594 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
595 pa_silence_memchunk(&vchunk, &s->sample_spec);
597 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
599 pa_source_output_push(o, &vchunk);
601 pa_memblock_unref(vchunk.memblock);
603 pa_source_output_push(o, chunk);
606 /* Called from main thread */
607 pa_usec_t pa_source_get_latency(pa_source *s) {
610 pa_source_assert_ref(s);
611 pa_assert(PA_SOURCE_IS_LINKED(s->state));
613 if (s->state == PA_SOURCE_SUSPENDED)
616 if (!(s->flags & PA_SOURCE_LATENCY))
619 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
624 /* Called from IO thread */
625 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
629 pa_source_assert_ref(s);
630 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
632 /* The returned value is supposed to be in the time domain of the sound card! */
634 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
637 if (!(s->flags & PA_SOURCE_LATENCY))
642 /* We probably should make this a proper vtable callback instead of going through process_msg() */
644 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
650 /* Called from main thread */
651 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
652 pa_cvolume old_virtual_volume;
653 pa_bool_t virtual_volume_changed;
655 pa_source_assert_ref(s);
656 pa_assert(PA_SOURCE_IS_LINKED(s->state));
658 pa_assert(pa_cvolume_valid(volume));
659 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
661 old_virtual_volume = s->virtual_volume;
662 s->virtual_volume = *volume;
663 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
666 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
669 s->soft_volume = s->virtual_volume;
671 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
673 if (virtual_volume_changed)
674 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
677 /* Called from main thread. Only to be called by source implementor */
678 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
679 pa_source_assert_ref(s);
682 if (PA_SOURCE_IS_LINKED(s->state))
683 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
685 s->thread_info.soft_volume = *volume;
688 /* Called from main thread */
689 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
690 pa_source_assert_ref(s);
691 pa_assert(PA_SOURCE_IS_LINKED(s->state));
693 if (s->refresh_volume || force_refresh) {
694 pa_cvolume old_virtual_volume = s->virtual_volume;
699 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
701 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
702 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
705 return &s->virtual_volume;
708 /* Called from main thread */
709 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
710 pa_source_assert_ref(s);
712 /* The source implementor may call this if the volume changed to make sure everyone is notified */
714 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
717 s->virtual_volume = *new_volume;
718 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
721 /* Called from main thread */
722 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
725 pa_source_assert_ref(s);
726 pa_assert(PA_SOURCE_IS_LINKED(s->state));
728 old_muted = s->muted;
734 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
736 if (old_muted != s->muted)
737 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
740 /* Called from main thread */
741 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
742 pa_source_assert_ref(s);
743 pa_assert(PA_SOURCE_IS_LINKED(s->state));
745 if (s->refresh_muted || force_refresh) {
746 pa_bool_t old_muted = s->muted;
751 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
753 if (old_muted != s->muted)
754 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
760 /* Called from main thread */
761 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
762 pa_source_assert_ref(s);
764 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
766 if (s->muted == new_muted)
769 s->muted = new_muted;
770 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
773 /* Called from main thread */
774 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
775 pa_source_assert_ref(s);
778 pa_proplist_update(s->proplist, mode, p);
780 if (PA_SOURCE_IS_LINKED(s->state)) {
781 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
782 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
788 /* Called from main thread */
789 void pa_source_set_description(pa_source *s, const char *description) {
791 pa_source_assert_ref(s);
793 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
796 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
798 if (old && description && !strcmp(old, description))
802 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
804 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
806 if (PA_SOURCE_IS_LINKED(s->state)) {
807 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
808 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
812 /* Called from main thread */
813 unsigned pa_source_linked_by(pa_source *s) {
814 pa_source_assert_ref(s);
815 pa_assert(PA_SOURCE_IS_LINKED(s->state));
817 return pa_idxset_size(s->outputs);
820 /* Called from main thread */
821 unsigned pa_source_used_by(pa_source *s) {
824 pa_source_assert_ref(s);
825 pa_assert(PA_SOURCE_IS_LINKED(s->state));
827 ret = pa_idxset_size(s->outputs);
828 pa_assert(ret >= s->n_corked);
830 return ret - s->n_corked;
833 /* Called from main thread */
834 unsigned pa_source_check_suspend(pa_source *s) {
839 pa_source_assert_ref(s);
841 if (!PA_SOURCE_IS_LINKED(s->state))
846 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
847 pa_source_output_state_t st;
849 st = pa_source_output_get_state(o);
850 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
852 if (st == PA_SOURCE_OUTPUT_CORKED)
855 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
864 /* Called from IO thread, except when it is not */
865 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
866 pa_source *s = PA_SOURCE(object);
867 pa_source_assert_ref(s);
869 switch ((pa_source_message_t) code) {
871 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
872 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
874 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
876 if (o->direct_on_input) {
877 o->thread_info.direct_on_input = o->direct_on_input;
878 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
881 pa_assert(!o->thread_info.attached);
882 o->thread_info.attached = TRUE;
887 pa_source_output_set_state_within_thread(o, o->state);
889 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
890 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
892 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
894 /* We don't just invalidate the requested latency here,
895 * because if we are in a move we might need to fix up the
896 * requested latency. */
897 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
902 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
903 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
905 pa_source_output_set_state_within_thread(o, o->state);
910 pa_assert(o->thread_info.attached);
911 o->thread_info.attached = FALSE;
913 if (o->thread_info.direct_on_input) {
914 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
915 o->thread_info.direct_on_input = NULL;
918 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
919 pa_source_output_unref(o);
921 pa_source_invalidate_requested_latency(s);
926 case PA_SOURCE_MESSAGE_SET_VOLUME:
927 s->thread_info.soft_volume = s->soft_volume;
930 case PA_SOURCE_MESSAGE_GET_VOLUME:
933 case PA_SOURCE_MESSAGE_SET_MUTE:
934 s->thread_info.soft_muted = s->muted;
937 case PA_SOURCE_MESSAGE_GET_MUTE:
940 case PA_SOURCE_MESSAGE_SET_STATE: {
942 pa_bool_t suspend_change =
943 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
944 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
946 s->thread_info.state = PA_PTR_TO_UINT(userdata);
948 if (suspend_change) {
952 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
953 if (o->suspend_within_thread)
954 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
961 case PA_SOURCE_MESSAGE_DETACH:
963 /* Detach all streams */
964 pa_source_detach_within_thread(s);
967 case PA_SOURCE_MESSAGE_ATTACH:
969 /* Reattach all streams */
970 pa_source_attach_within_thread(s);
973 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
975 pa_usec_t *usec = userdata;
976 *usec = pa_source_get_requested_latency_within_thread(s);
978 if (*usec == (pa_usec_t) -1)
979 *usec = s->thread_info.max_latency;
984 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
985 pa_usec_t *r = userdata;
987 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
992 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
993 pa_usec_t *r = userdata;
995 r[0] = s->thread_info.min_latency;
996 r[1] = s->thread_info.max_latency;
1001 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1003 *((size_t*) userdata) = s->thread_info.max_rewind;
1006 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1008 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1011 case PA_SOURCE_MESSAGE_GET_LATENCY:
1013 if (s->monitor_of) {
1014 *((pa_usec_t*) userdata) = 0;
1018 /* Implementors need to overwrite this implementation! */
1021 case PA_SOURCE_MESSAGE_MAX:
1028 /* Called from main thread */
1029 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
1034 pa_core_assert_ref(c);
1036 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1039 if (source->monitor_of)
1042 if ((r = pa_source_suspend(source, suspend)) < 0)
1049 /* Called from main thread */
1050 void pa_source_detach(pa_source *s) {
1051 pa_source_assert_ref(s);
1052 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1054 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1057 /* Called from main thread */
1058 void pa_source_attach(pa_source *s) {
1059 pa_source_assert_ref(s);
1060 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1062 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1065 /* Called from IO thread */
1066 void pa_source_detach_within_thread(pa_source *s) {
1067 pa_source_output *o;
1070 pa_source_assert_ref(s);
1071 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1073 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1078 /* Called from IO thread */
1079 void pa_source_attach_within_thread(pa_source *s) {
1080 pa_source_output *o;
1083 pa_source_assert_ref(s);
1084 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1086 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1091 /* Called from IO thread */
1092 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1093 pa_usec_t result = (pa_usec_t) -1;
1094 pa_source_output *o;
1097 pa_source_assert_ref(s);
1099 if (s->thread_info.requested_latency_valid)
1100 return s->thread_info.requested_latency;
1102 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1104 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1105 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1106 result = o->thread_info.requested_source_latency;
1108 if (result != (pa_usec_t) -1) {
1109 if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1110 result = s->thread_info.max_latency;
1112 if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1113 result = s->thread_info.min_latency;
1116 s->thread_info.requested_latency = result;
1117 s->thread_info.requested_latency_valid = TRUE;
1122 /* Called from main thread */
1123 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1126 pa_source_assert_ref(s);
1127 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1129 if (s->state == PA_SOURCE_SUSPENDED)
1132 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1137 /* Called from IO thread */
1138 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1139 pa_source_output *o;
1142 pa_source_assert_ref(s);
1144 if (max_rewind == s->thread_info.max_rewind)
1147 s->thread_info.max_rewind = max_rewind;
1149 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1150 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1151 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1155 /* Called from main thread */
1156 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1157 pa_source_assert_ref(s);
1159 if (PA_SOURCE_IS_LINKED(s->state))
1160 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1162 pa_source_set_max_rewind_within_thread(s, max_rewind);
1165 /* Called from IO thread */
1166 void pa_source_invalidate_requested_latency(pa_source *s) {
1167 pa_source_output *o;
1170 pa_source_assert_ref(s);
1172 s->thread_info.requested_latency_valid = FALSE;
1174 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1176 if (s->update_requested_latency)
1177 s->update_requested_latency(s);
1179 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1180 if (o->update_source_requested_latency)
1181 o->update_source_requested_latency(o);
1185 pa_sink_invalidate_requested_latency(s->monitor_of);
1188 /* Called from main thread */
1189 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1190 pa_source_assert_ref(s);
1192 /* min_latency == 0: no limit
1193 * min_latency anything else: specified limit
1195 * Similar for max_latency */
1197 if (min_latency < ABSOLUTE_MIN_LATENCY)
1198 min_latency = ABSOLUTE_MIN_LATENCY;
1200 if (max_latency <= 0 ||
1201 max_latency > ABSOLUTE_MAX_LATENCY)
1202 max_latency = ABSOLUTE_MAX_LATENCY;
1204 pa_assert(min_latency <= max_latency);
1206 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1207 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1208 max_latency == ABSOLUTE_MAX_LATENCY) ||
1209 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1211 if (PA_SOURCE_IS_LINKED(s->state)) {
1217 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1219 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1222 /* Called from main thread */
1223 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1224 pa_source_assert_ref(s);
1225 pa_assert(min_latency);
1226 pa_assert(max_latency);
1228 if (PA_SOURCE_IS_LINKED(s->state)) {
1229 pa_usec_t r[2] = { 0, 0 };
1231 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1233 *min_latency = r[0];
1234 *max_latency = r[1];
1236 *min_latency = s->thread_info.min_latency;
1237 *max_latency = s->thread_info.max_latency;
1241 /* Called from IO thread, and from main thread before pa_source_put() is called */
1242 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1245 pa_source_assert_ref(s);
1247 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1248 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1249 pa_assert(min_latency <= max_latency);
1251 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1252 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1253 max_latency == ABSOLUTE_MAX_LATENCY) ||
1254 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1257 s->thread_info.min_latency = min_latency;
1258 s->thread_info.max_latency = max_latency;
1260 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1261 pa_source_output *o;
1263 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1264 if (o->update_source_latency_range)
1265 o->update_source_latency_range(o);
1268 pa_source_invalidate_requested_latency(s);
1271 /* Called from main thread */
1272 size_t pa_source_get_max_rewind(pa_source *s) {
1274 pa_source_assert_ref(s);
1276 if (!PA_SOURCE_IS_LINKED(s->state))
1277 return s->thread_info.max_rewind;
1279 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);