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 DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
46 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
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;
209 pa_silence_memchunk_get(
210 &core->silence_cache,
216 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
217 s->thread_info.soft_volume = s->soft_volume;
218 s->thread_info.soft_muted = s->muted;
219 s->thread_info.state = s->state;
220 s->thread_info.max_rewind = 0;
221 s->thread_info.requested_latency_valid = FALSE;
222 s->thread_info.requested_latency = 0;
223 s->thread_info.min_latency = DEFAULT_MIN_LATENCY;
224 s->thread_info.max_latency = DEFAULT_MIN_LATENCY;
226 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
229 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
231 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
232 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
235 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
236 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
243 /* Called from main context */
244 static int source_set_state(pa_source *s, pa_source_state_t state) {
246 pa_bool_t suspend_change;
247 pa_source_state_t original_state;
251 if (s->state == state)
254 original_state = s->state;
257 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
258 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
261 if ((ret = s->set_state(s, state)) < 0)
265 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
268 s->set_state(s, original_state);
275 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
276 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
277 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
280 if (suspend_change) {
284 /* We're suspending or resuming, tell everyone about it */
286 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
287 if (s->state == PA_SOURCE_SUSPENDED &&
288 (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
289 pa_source_output_kill(o);
291 o->suspend(o, state == PA_SOURCE_SUSPENDED);
298 /* Called from main context */
299 void pa_source_put(pa_source *s) {
300 pa_source_assert_ref(s);
302 pa_assert(s->state == PA_SOURCE_INIT);
304 /* The following fields must be initialized properly when calling _put() */
305 pa_assert(s->asyncmsgq);
306 pa_assert(s->rtpoll);
307 pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
308 s->thread_info.min_latency <= s->thread_info.max_latency);
310 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) {
311 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
313 s->thread_info.soft_volume = s->soft_volume;
314 s->thread_info.soft_muted = s->muted;
317 if (s->flags & PA_SOURCE_DECIBEL_VOLUME)
318 s->n_volume_steps = PA_VOLUME_NORM+1;
320 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
322 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
323 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
326 /* Called from main context */
327 void pa_source_unlink(pa_source *s) {
329 pa_source_output *o, *j = NULL;
333 /* See pa_sink_unlink() for a couple of comments how this function
336 linked = PA_SOURCE_IS_LINKED(s->state);
339 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
341 if (s->state != PA_SOURCE_UNLINKED)
342 pa_namereg_unregister(s->core, s->name);
343 pa_idxset_remove_by_data(s->core->sources, s, NULL);
346 pa_idxset_remove_by_data(s->card->sources, s, NULL);
348 while ((o = pa_idxset_first(s->outputs, NULL))) {
350 pa_source_output_kill(o);
355 source_set_state(s, PA_SOURCE_UNLINKED);
357 s->state = PA_SOURCE_UNLINKED;
362 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
363 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
367 /* Called from main context */
368 static void source_free(pa_object *o) {
369 pa_source_output *so;
370 pa_source *s = PA_SOURCE(o);
373 pa_assert(pa_source_refcnt(s) == 0);
375 if (PA_SOURCE_IS_LINKED(s->state))
378 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
380 pa_idxset_free(s->outputs, NULL, NULL);
382 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
383 pa_source_output_unref(so);
385 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
387 if (s->silence.memblock)
388 pa_memblock_unref(s->silence.memblock);
394 pa_proplist_free(s->proplist);
399 /* Called from main context */
400 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
401 pa_source_assert_ref(s);
406 /* Called from main context */
407 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
408 pa_source_assert_ref(s);
413 /* Called from main context */
414 int pa_source_update_status(pa_source*s) {
415 pa_source_assert_ref(s);
416 pa_assert(PA_SOURCE_IS_LINKED(s->state));
418 if (s->state == PA_SOURCE_SUSPENDED)
421 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
424 /* Called from main context */
425 int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
426 pa_source_assert_ref(s);
427 pa_assert(PA_SOURCE_IS_LINKED(s->state));
430 return -PA_ERR_NOTSUPPORTED;
433 return source_set_state(s, PA_SOURCE_SUSPENDED);
435 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
438 /* Called from main context */
439 int pa_source_sync_suspend(pa_source *s) {
440 pa_sink_state_t state;
442 pa_source_assert_ref(s);
443 pa_assert(PA_SOURCE_IS_LINKED(s->state));
444 pa_assert(s->monitor_of);
446 state = pa_sink_get_state(s->monitor_of);
448 if (state == PA_SINK_SUSPENDED)
449 return source_set_state(s, PA_SOURCE_SUSPENDED);
451 pa_assert(PA_SINK_IS_OPENED(state));
453 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
456 /* Called from main context */
457 pa_queue *pa_source_move_all_start(pa_source *s) {
459 pa_source_output *o, *n;
462 pa_source_assert_ref(s);
463 pa_assert(PA_SOURCE_IS_LINKED(s->state));
467 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
468 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
470 if (pa_source_output_start_move(o) >= 0)
471 pa_queue_push(q, pa_source_output_ref(o));
477 /* Called from main context */
478 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
481 pa_source_assert_ref(s);
482 pa_assert(PA_SOURCE_IS_LINKED(s->state));
485 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
486 if (pa_source_output_finish_move(o, s, save) < 0)
487 pa_source_output_kill(o);
489 pa_source_output_unref(o);
492 pa_queue_free(q, NULL, NULL);
495 /* Called from main context */
496 void pa_source_move_all_fail(pa_queue *q) {
500 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
501 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
502 pa_source_output_kill(o);
503 pa_source_output_unref(o);
507 pa_queue_free(q, NULL, NULL);
510 /* Called from IO thread context */
511 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
515 pa_source_assert_ref(s);
516 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
518 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
524 pa_log_debug("Processing rewind...");
526 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
527 pa_source_output_assert_ref(o);
528 pa_source_output_process_rewind(o, nbytes);
532 /* Called from IO thread context */
533 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
537 pa_source_assert_ref(s);
538 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
541 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
544 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
545 pa_memchunk vchunk = *chunk;
547 pa_memblock_ref(vchunk.memblock);
548 pa_memchunk_make_writable(&vchunk, 0);
550 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
551 pa_silence_memchunk(&vchunk, &s->sample_spec);
553 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
555 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
556 pa_source_output_assert_ref(o);
558 if (!o->thread_info.direct_on_input)
559 pa_source_output_push(o, &vchunk);
562 pa_memblock_unref(vchunk.memblock);
565 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
566 pa_source_output_assert_ref(o);
568 if (!o->thread_info.direct_on_input)
569 pa_source_output_push(o, chunk);
574 /* Called from IO thread context */
575 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
576 pa_source_assert_ref(s);
577 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
578 pa_source_output_assert_ref(o);
579 pa_assert(o->thread_info.direct_on_input);
582 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
585 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
586 pa_memchunk vchunk = *chunk;
588 pa_memblock_ref(vchunk.memblock);
589 pa_memchunk_make_writable(&vchunk, 0);
591 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
592 pa_silence_memchunk(&vchunk, &s->sample_spec);
594 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
596 pa_source_output_push(o, &vchunk);
598 pa_memblock_unref(vchunk.memblock);
600 pa_source_output_push(o, chunk);
603 /* Called from main thread */
604 pa_usec_t pa_source_get_latency(pa_source *s) {
607 pa_source_assert_ref(s);
608 pa_assert(PA_SOURCE_IS_LINKED(s->state));
610 if (s->state == PA_SOURCE_SUSPENDED)
613 if (!(s->flags & PA_SOURCE_LATENCY))
616 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
621 /* Called from main thread */
622 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
623 pa_cvolume old_virtual_volume;
624 pa_bool_t virtual_volume_changed;
626 pa_source_assert_ref(s);
627 pa_assert(PA_SOURCE_IS_LINKED(s->state));
629 pa_assert(pa_cvolume_valid(volume));
630 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
632 old_virtual_volume = s->virtual_volume;
633 s->virtual_volume = *volume;
634 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
637 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
640 s->soft_volume = s->virtual_volume;
642 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
644 if (virtual_volume_changed)
645 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
648 /* Called from main thread. Only to be called by source implementor */
649 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
650 pa_source_assert_ref(s);
653 if (PA_SOURCE_IS_LINKED(s->state))
654 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
656 s->thread_info.soft_volume = *volume;
659 /* Called from main thread */
660 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
661 pa_source_assert_ref(s);
662 pa_assert(PA_SOURCE_IS_LINKED(s->state));
664 if (s->refresh_volume || force_refresh) {
665 pa_cvolume old_virtual_volume = s->virtual_volume;
670 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
672 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
673 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
676 return &s->virtual_volume;
679 /* Called from main thread */
680 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
681 pa_source_assert_ref(s);
683 /* The source implementor may call this if the volume changed to make sure everyone is notified */
685 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
688 s->virtual_volume = *new_volume;
689 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
692 /* Called from main thread */
693 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
696 pa_source_assert_ref(s);
697 pa_assert(PA_SOURCE_IS_LINKED(s->state));
699 old_muted = s->muted;
705 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
707 if (old_muted != s->muted)
708 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
711 /* Called from main thread */
712 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
713 pa_source_assert_ref(s);
714 pa_assert(PA_SOURCE_IS_LINKED(s->state));
716 if (s->refresh_muted || force_refresh) {
717 pa_bool_t old_muted = s->muted;
722 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
724 if (old_muted != s->muted)
725 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
731 /* Called from main thread */
732 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
733 pa_source_assert_ref(s);
735 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
737 if (s->muted == new_muted)
740 s->muted = new_muted;
741 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
744 /* Called from main thread */
745 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
746 pa_source_assert_ref(s);
749 pa_proplist_update(s->proplist, mode, p);
751 if (PA_SOURCE_IS_LINKED(s->state)) {
752 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
753 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
759 /* Called from main thread */
760 void pa_source_set_description(pa_source *s, const char *description) {
762 pa_source_assert_ref(s);
764 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
767 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
769 if (old && description && !strcmp(old, description))
773 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
775 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
777 if (PA_SOURCE_IS_LINKED(s->state)) {
778 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
779 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
783 /* Called from main thread */
784 unsigned pa_source_linked_by(pa_source *s) {
785 pa_source_assert_ref(s);
786 pa_assert(PA_SOURCE_IS_LINKED(s->state));
788 return pa_idxset_size(s->outputs);
791 /* Called from main thread */
792 unsigned pa_source_used_by(pa_source *s) {
795 pa_source_assert_ref(s);
796 pa_assert(PA_SOURCE_IS_LINKED(s->state));
798 ret = pa_idxset_size(s->outputs);
799 pa_assert(ret >= s->n_corked);
801 return ret - s->n_corked;
804 /* Called from main thread */
805 unsigned pa_source_check_suspend(pa_source *s) {
810 pa_source_assert_ref(s);
812 if (!PA_SOURCE_IS_LINKED(s->state))
817 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
818 pa_source_output_state_t st;
820 st = pa_source_output_get_state(o);
821 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
823 if (st == PA_SOURCE_OUTPUT_CORKED)
826 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
835 /* Called from IO thread, except when it is not */
836 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
837 pa_source *s = PA_SOURCE(object);
838 pa_source_assert_ref(s);
840 switch ((pa_source_message_t) code) {
842 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
843 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
845 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
847 if (o->direct_on_input) {
848 o->thread_info.direct_on_input = o->direct_on_input;
849 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
852 pa_assert(!o->thread_info.attached);
853 o->thread_info.attached = TRUE;
858 pa_source_output_set_state_within_thread(o, o->state);
860 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
861 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
863 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
865 /* We don't just invalidate the requested latency here,
866 * because if we are in a move we might need to fix up the
867 * requested latency. */
868 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
873 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
874 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
876 pa_source_output_set_state_within_thread(o, o->state);
881 pa_assert(o->thread_info.attached);
882 o->thread_info.attached = FALSE;
884 if (o->thread_info.direct_on_input) {
885 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
886 o->thread_info.direct_on_input = NULL;
889 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
890 pa_source_output_unref(o);
892 pa_source_invalidate_requested_latency(s);
897 case PA_SOURCE_MESSAGE_SET_VOLUME:
898 s->thread_info.soft_volume = s->soft_volume;
901 case PA_SOURCE_MESSAGE_GET_VOLUME:
904 case PA_SOURCE_MESSAGE_SET_MUTE:
905 s->thread_info.soft_muted = s->muted;
908 case PA_SOURCE_MESSAGE_GET_MUTE:
911 case PA_SOURCE_MESSAGE_SET_STATE:
912 s->thread_info.state = PA_PTR_TO_UINT(userdata);
915 case PA_SOURCE_MESSAGE_DETACH:
917 /* Detach all streams */
918 pa_source_detach_within_thread(s);
921 case PA_SOURCE_MESSAGE_ATTACH:
923 /* Reattach all streams */
924 pa_source_attach_within_thread(s);
927 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
929 pa_usec_t *usec = userdata;
930 *usec = pa_source_get_requested_latency_within_thread(s);
932 if (*usec == (pa_usec_t) -1)
933 *usec = s->thread_info.max_latency;
938 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
939 pa_usec_t *r = userdata;
941 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
946 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
947 pa_usec_t *r = userdata;
949 r[0] = s->thread_info.min_latency;
950 r[1] = s->thread_info.max_latency;
955 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
957 *((size_t*) userdata) = s->thread_info.max_rewind;
960 case PA_SOURCE_MESSAGE_GET_LATENCY:
963 *((pa_usec_t*) userdata) = 0;
967 /* Implementors need to overwrite this implementation! */
970 case PA_SOURCE_MESSAGE_MAX:
977 /* Called from main thread */
978 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
983 pa_core_assert_ref(c);
985 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
988 if (source->monitor_of)
991 if ((r = pa_source_suspend(source, suspend)) < 0)
998 /* Called from main thread */
999 void pa_source_detach(pa_source *s) {
1000 pa_source_assert_ref(s);
1001 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1003 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1006 /* Called from main thread */
1007 void pa_source_attach(pa_source *s) {
1008 pa_source_assert_ref(s);
1009 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1011 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1014 /* Called from IO thread */
1015 void pa_source_detach_within_thread(pa_source *s) {
1016 pa_source_output *o;
1019 pa_source_assert_ref(s);
1020 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1022 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1027 /* Called from IO thread */
1028 void pa_source_attach_within_thread(pa_source *s) {
1029 pa_source_output *o;
1032 pa_source_assert_ref(s);
1033 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1035 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1040 /* Called from IO thread */
1041 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1042 pa_usec_t result = (pa_usec_t) -1;
1043 pa_source_output *o;
1046 pa_source_assert_ref(s);
1048 if (s->thread_info.requested_latency_valid)
1049 return s->thread_info.requested_latency;
1051 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1053 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1054 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1055 result = o->thread_info.requested_source_latency;
1057 if (result != (pa_usec_t) -1) {
1058 if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1059 result = s->thread_info.max_latency;
1061 if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1062 result = s->thread_info.min_latency;
1065 s->thread_info.requested_latency = result;
1066 s->thread_info.requested_latency_valid = TRUE;
1071 /* Called from main thread */
1072 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1075 pa_source_assert_ref(s);
1076 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1078 if (s->state == PA_SOURCE_SUSPENDED)
1081 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1086 /* Called from IO thread */
1087 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1088 pa_source_output *o;
1091 pa_source_assert_ref(s);
1093 if (max_rewind == s->thread_info.max_rewind)
1096 s->thread_info.max_rewind = max_rewind;
1098 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1099 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1100 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1104 void pa_source_invalidate_requested_latency(pa_source *s) {
1105 pa_source_output *o;
1108 pa_source_assert_ref(s);
1110 s->thread_info.requested_latency_valid = FALSE;
1112 if (s->update_requested_latency)
1113 s->update_requested_latency(s);
1115 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1116 if (o->update_source_requested_latency)
1117 o->update_source_requested_latency(o);
1120 pa_sink_invalidate_requested_latency(s->monitor_of);
1123 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1124 pa_source_assert_ref(s);
1126 /* min_latency == 0: no limit
1127 * min_latency == (size_t) -1: default limit
1128 * min_latency anything else: specified limit
1130 * Similar for max_latency */
1132 if (min_latency == (pa_usec_t) -1)
1133 min_latency = DEFAULT_MIN_LATENCY;
1135 if (min_latency < ABSOLUTE_MIN_LATENCY)
1136 min_latency = ABSOLUTE_MIN_LATENCY;
1138 if (max_latency == (pa_usec_t) -1)
1139 max_latency = min_latency;
1141 if (max_latency > ABSOLUTE_MAX_LATENCY || max_latency <= 0)
1142 max_latency = ABSOLUTE_MAX_LATENCY;
1144 pa_assert(min_latency <= max_latency);
1146 if (PA_SOURCE_IS_LINKED(s->state)) {
1152 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1154 s->thread_info.min_latency = min_latency;
1155 s->thread_info.max_latency = max_latency;
1157 s->thread_info.requested_latency_valid = FALSE;
1161 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1162 pa_source_assert_ref(s);
1163 pa_assert(min_latency);
1164 pa_assert(max_latency);
1166 if (PA_SOURCE_IS_LINKED(s->state)) {
1167 pa_usec_t r[2] = { 0, 0 };
1169 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1171 *min_latency = r[0];
1172 *max_latency = r[1];
1174 *min_latency = s->thread_info.min_latency;
1175 *max_latency = s->thread_info.max_latency;
1179 /* Called from IO thread */
1180 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1181 pa_source_output *o;
1184 pa_source_assert_ref(s);
1186 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1187 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1188 pa_assert(min_latency <= max_latency);
1190 s->thread_info.min_latency = min_latency;
1191 s->thread_info.max_latency = max_latency;
1193 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1194 if (o->update_source_latency_range)
1195 o->update_source_latency_range(o);
1197 pa_source_invalidate_requested_latency(s);
1200 size_t pa_source_get_max_rewind(pa_source *s) {
1202 pa_source_assert_ref(s);
1204 if (!PA_SOURCE_IS_LINKED(s->state))
1205 return s->thread_info.max_rewind;
1207 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);