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 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) {
312 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
314 s->thread_info.soft_volume = s->soft_volume;
315 s->thread_info.soft_muted = s->muted;
318 if (s->flags & PA_SOURCE_DECIBEL_VOLUME)
319 s->n_volume_steps = PA_VOLUME_NORM+1;
321 if (s->flags & PA_SOURCE_DYNAMIC_LATENCY)
322 s->fixed_latency = 0;
323 else if (s->fixed_latency <= 0)
324 s->fixed_latency = DEFAULT_FIXED_LATENCY;
326 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
328 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
329 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
332 /* Called from main context */
333 void pa_source_unlink(pa_source *s) {
335 pa_source_output *o, *j = NULL;
339 /* See pa_sink_unlink() for a couple of comments how this function
342 linked = PA_SOURCE_IS_LINKED(s->state);
345 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
347 if (s->state != PA_SOURCE_UNLINKED)
348 pa_namereg_unregister(s->core, s->name);
349 pa_idxset_remove_by_data(s->core->sources, s, NULL);
352 pa_idxset_remove_by_data(s->card->sources, s, NULL);
354 while ((o = pa_idxset_first(s->outputs, NULL))) {
356 pa_source_output_kill(o);
361 source_set_state(s, PA_SOURCE_UNLINKED);
363 s->state = PA_SOURCE_UNLINKED;
368 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
369 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
373 /* Called from main context */
374 static void source_free(pa_object *o) {
375 pa_source_output *so;
376 pa_source *s = PA_SOURCE(o);
379 pa_assert(pa_source_refcnt(s) == 0);
381 if (PA_SOURCE_IS_LINKED(s->state))
384 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
386 pa_idxset_free(s->outputs, NULL, NULL);
388 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
389 pa_source_output_unref(so);
391 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
393 if (s->silence.memblock)
394 pa_memblock_unref(s->silence.memblock);
400 pa_proplist_free(s->proplist);
405 /* Called from main context */
406 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
407 pa_source_assert_ref(s);
412 /* Called from main context */
413 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
414 pa_source_assert_ref(s);
419 /* Called from main context */
420 int pa_source_update_status(pa_source*s) {
421 pa_source_assert_ref(s);
422 pa_assert(PA_SOURCE_IS_LINKED(s->state));
424 if (s->state == PA_SOURCE_SUSPENDED)
427 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
430 /* Called from main context */
431 int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
432 pa_source_assert_ref(s);
433 pa_assert(PA_SOURCE_IS_LINKED(s->state));
436 return -PA_ERR_NOTSUPPORTED;
439 return source_set_state(s, PA_SOURCE_SUSPENDED);
441 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
444 /* Called from main context */
445 int pa_source_sync_suspend(pa_source *s) {
446 pa_sink_state_t state;
448 pa_source_assert_ref(s);
449 pa_assert(PA_SOURCE_IS_LINKED(s->state));
450 pa_assert(s->monitor_of);
452 state = pa_sink_get_state(s->monitor_of);
454 if (state == PA_SINK_SUSPENDED)
455 return source_set_state(s, PA_SOURCE_SUSPENDED);
457 pa_assert(PA_SINK_IS_OPENED(state));
459 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
462 /* Called from main context */
463 pa_queue *pa_source_move_all_start(pa_source *s) {
465 pa_source_output *o, *n;
468 pa_source_assert_ref(s);
469 pa_assert(PA_SOURCE_IS_LINKED(s->state));
473 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
474 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
476 pa_source_output_ref(o);
478 if (pa_source_output_start_move(o) >= 0)
481 pa_source_output_unref(o);
487 /* Called from main context */
488 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
491 pa_source_assert_ref(s);
492 pa_assert(PA_SOURCE_IS_LINKED(s->state));
495 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
496 if (pa_source_output_finish_move(o, s, save) < 0)
497 pa_source_output_kill(o);
499 pa_source_output_unref(o);
502 pa_queue_free(q, NULL, NULL);
505 /* Called from main context */
506 void pa_source_move_all_fail(pa_queue *q) {
510 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
511 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
512 pa_source_output_kill(o);
513 pa_source_output_unref(o);
517 pa_queue_free(q, NULL, NULL);
520 /* Called from IO thread context */
521 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
525 pa_source_assert_ref(s);
526 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
528 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
534 pa_log_debug("Processing rewind...");
536 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
537 pa_source_output_assert_ref(o);
538 pa_source_output_process_rewind(o, nbytes);
542 /* Called from IO thread context */
543 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
547 pa_source_assert_ref(s);
548 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
551 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
554 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
555 pa_memchunk vchunk = *chunk;
557 pa_memblock_ref(vchunk.memblock);
558 pa_memchunk_make_writable(&vchunk, 0);
560 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
561 pa_silence_memchunk(&vchunk, &s->sample_spec);
563 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
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, &vchunk);
572 pa_memblock_unref(vchunk.memblock);
575 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
576 pa_source_output_assert_ref(o);
578 if (!o->thread_info.direct_on_input)
579 pa_source_output_push(o, chunk);
584 /* Called from IO thread context */
585 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
586 pa_source_assert_ref(s);
587 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
588 pa_source_output_assert_ref(o);
589 pa_assert(o->thread_info.direct_on_input);
592 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
595 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
596 pa_memchunk vchunk = *chunk;
598 pa_memblock_ref(vchunk.memblock);
599 pa_memchunk_make_writable(&vchunk, 0);
601 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
602 pa_silence_memchunk(&vchunk, &s->sample_spec);
604 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
606 pa_source_output_push(o, &vchunk);
608 pa_memblock_unref(vchunk.memblock);
610 pa_source_output_push(o, chunk);
613 /* Called from main thread */
614 pa_usec_t pa_source_get_latency(pa_source *s) {
617 pa_source_assert_ref(s);
618 pa_assert(PA_SOURCE_IS_LINKED(s->state));
620 if (s->state == PA_SOURCE_SUSPENDED)
623 if (!(s->flags & PA_SOURCE_LATENCY))
626 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
631 /* Called from IO thread */
632 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
636 pa_source_assert_ref(s);
637 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
639 /* The returned value is supposed to be in the time domain of the sound card! */
641 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
644 if (!(s->flags & PA_SOURCE_LATENCY))
649 /* We probably should make this a proper vtable callback instead of going through process_msg() */
651 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
657 /* Called from main thread */
658 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
659 pa_cvolume old_virtual_volume;
660 pa_bool_t virtual_volume_changed;
662 pa_source_assert_ref(s);
663 pa_assert(PA_SOURCE_IS_LINKED(s->state));
665 pa_assert(pa_cvolume_valid(volume));
666 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
668 old_virtual_volume = s->virtual_volume;
669 s->virtual_volume = *volume;
670 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
673 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
676 s->soft_volume = s->virtual_volume;
678 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
680 if (virtual_volume_changed)
681 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
684 /* Called from main thread. Only to be called by source implementor */
685 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
686 pa_source_assert_ref(s);
689 if (PA_SOURCE_IS_LINKED(s->state))
690 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
692 s->thread_info.soft_volume = *volume;
695 /* Called from main thread */
696 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
697 pa_source_assert_ref(s);
698 pa_assert(PA_SOURCE_IS_LINKED(s->state));
700 if (s->refresh_volume || force_refresh) {
701 pa_cvolume old_virtual_volume = s->virtual_volume;
706 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
708 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
709 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
712 return &s->virtual_volume;
715 /* Called from main thread */
716 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
717 pa_source_assert_ref(s);
719 /* The source implementor may call this if the volume changed to make sure everyone is notified */
721 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
724 s->virtual_volume = *new_volume;
725 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
728 /* Called from main thread */
729 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
732 pa_source_assert_ref(s);
733 pa_assert(PA_SOURCE_IS_LINKED(s->state));
735 old_muted = s->muted;
741 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
743 if (old_muted != s->muted)
744 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
747 /* Called from main thread */
748 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
749 pa_source_assert_ref(s);
750 pa_assert(PA_SOURCE_IS_LINKED(s->state));
752 if (s->refresh_muted || force_refresh) {
753 pa_bool_t old_muted = s->muted;
758 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
760 if (old_muted != s->muted)
761 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
767 /* Called from main thread */
768 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
769 pa_source_assert_ref(s);
771 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
773 if (s->muted == new_muted)
776 s->muted = new_muted;
777 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
780 /* Called from main thread */
781 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
782 pa_source_assert_ref(s);
785 pa_proplist_update(s->proplist, mode, p);
787 if (PA_SOURCE_IS_LINKED(s->state)) {
788 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
789 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
795 /* Called from main thread */
796 void pa_source_set_description(pa_source *s, const char *description) {
798 pa_source_assert_ref(s);
800 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
803 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
805 if (old && description && !strcmp(old, description))
809 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
811 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
813 if (PA_SOURCE_IS_LINKED(s->state)) {
814 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
815 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
819 /* Called from main thread */
820 unsigned pa_source_linked_by(pa_source *s) {
821 pa_source_assert_ref(s);
822 pa_assert(PA_SOURCE_IS_LINKED(s->state));
824 return pa_idxset_size(s->outputs);
827 /* Called from main thread */
828 unsigned pa_source_used_by(pa_source *s) {
831 pa_source_assert_ref(s);
832 pa_assert(PA_SOURCE_IS_LINKED(s->state));
834 ret = pa_idxset_size(s->outputs);
835 pa_assert(ret >= s->n_corked);
837 return ret - s->n_corked;
840 /* Called from main thread */
841 unsigned pa_source_check_suspend(pa_source *s) {
846 pa_source_assert_ref(s);
848 if (!PA_SOURCE_IS_LINKED(s->state))
853 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
854 pa_source_output_state_t st;
856 st = pa_source_output_get_state(o);
857 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
859 if (st == PA_SOURCE_OUTPUT_CORKED)
862 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
871 /* Called from IO thread, except when it is not */
872 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
873 pa_source *s = PA_SOURCE(object);
874 pa_source_assert_ref(s);
876 switch ((pa_source_message_t) code) {
878 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
879 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
881 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
883 if (o->direct_on_input) {
884 o->thread_info.direct_on_input = o->direct_on_input;
885 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
888 pa_assert(!o->thread_info.attached);
889 o->thread_info.attached = TRUE;
894 pa_source_output_set_state_within_thread(o, o->state);
896 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
897 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
899 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
901 /* We don't just invalidate the requested latency here,
902 * because if we are in a move we might need to fix up the
903 * requested latency. */
904 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
909 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
910 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
912 pa_source_output_set_state_within_thread(o, o->state);
917 pa_assert(o->thread_info.attached);
918 o->thread_info.attached = FALSE;
920 if (o->thread_info.direct_on_input) {
921 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
922 o->thread_info.direct_on_input = NULL;
925 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
926 pa_source_output_unref(o);
928 pa_source_invalidate_requested_latency(s);
933 case PA_SOURCE_MESSAGE_SET_VOLUME:
934 s->thread_info.soft_volume = s->soft_volume;
937 case PA_SOURCE_MESSAGE_GET_VOLUME:
940 case PA_SOURCE_MESSAGE_SET_MUTE:
941 s->thread_info.soft_muted = s->muted;
944 case PA_SOURCE_MESSAGE_GET_MUTE:
947 case PA_SOURCE_MESSAGE_SET_STATE: {
949 pa_bool_t suspend_change =
950 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
951 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
953 s->thread_info.state = PA_PTR_TO_UINT(userdata);
955 if (suspend_change) {
959 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
960 if (o->suspend_within_thread)
961 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
968 case PA_SOURCE_MESSAGE_DETACH:
970 /* Detach all streams */
971 pa_source_detach_within_thread(s);
974 case PA_SOURCE_MESSAGE_ATTACH:
976 /* Reattach all streams */
977 pa_source_attach_within_thread(s);
980 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
982 pa_usec_t *usec = userdata;
983 *usec = pa_source_get_requested_latency_within_thread(s);
985 if (*usec == (pa_usec_t) -1)
986 *usec = s->thread_info.max_latency;
991 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
992 pa_usec_t *r = userdata;
994 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
999 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
1000 pa_usec_t *r = userdata;
1002 r[0] = s->thread_info.min_latency;
1003 r[1] = s->thread_info.max_latency;
1008 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1010 *((size_t*) userdata) = s->thread_info.max_rewind;
1013 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1015 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1018 case PA_SOURCE_MESSAGE_GET_LATENCY:
1020 if (s->monitor_of) {
1021 *((pa_usec_t*) userdata) = 0;
1025 /* Implementors need to overwrite this implementation! */
1028 case PA_SOURCE_MESSAGE_MAX:
1035 /* Called from main thread */
1036 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
1041 pa_core_assert_ref(c);
1043 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1046 if (source->monitor_of)
1049 if ((r = pa_source_suspend(source, suspend)) < 0)
1056 /* Called from main thread */
1057 void pa_source_detach(pa_source *s) {
1058 pa_source_assert_ref(s);
1059 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1061 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1064 /* Called from main thread */
1065 void pa_source_attach(pa_source *s) {
1066 pa_source_assert_ref(s);
1067 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1069 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1072 /* Called from IO thread */
1073 void pa_source_detach_within_thread(pa_source *s) {
1074 pa_source_output *o;
1077 pa_source_assert_ref(s);
1078 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1080 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1085 /* Called from IO thread */
1086 void pa_source_attach_within_thread(pa_source *s) {
1087 pa_source_output *o;
1090 pa_source_assert_ref(s);
1091 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1093 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1098 /* Called from IO thread */
1099 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1100 pa_usec_t result = (pa_usec_t) -1;
1101 pa_source_output *o;
1104 pa_source_assert_ref(s);
1106 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1107 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1109 if (s->thread_info.requested_latency_valid)
1110 return s->thread_info.requested_latency;
1112 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1114 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1115 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1116 result = o->thread_info.requested_source_latency;
1118 if (result != (pa_usec_t) -1)
1119 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1121 s->thread_info.requested_latency = result;
1122 s->thread_info.requested_latency_valid = TRUE;
1127 /* Called from main thread */
1128 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1131 pa_source_assert_ref(s);
1132 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1134 if (s->state == PA_SOURCE_SUSPENDED)
1137 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1142 /* Called from IO thread */
1143 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1144 pa_source_output *o;
1147 pa_source_assert_ref(s);
1149 if (max_rewind == s->thread_info.max_rewind)
1152 s->thread_info.max_rewind = max_rewind;
1154 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1155 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1156 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1160 /* Called from main thread */
1161 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1162 pa_source_assert_ref(s);
1164 if (PA_SOURCE_IS_LINKED(s->state))
1165 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1167 pa_source_set_max_rewind_within_thread(s, max_rewind);
1170 /* Called from IO thread */
1171 void pa_source_invalidate_requested_latency(pa_source *s) {
1172 pa_source_output *o;
1175 pa_source_assert_ref(s);
1177 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1180 s->thread_info.requested_latency_valid = FALSE;
1182 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1184 if (s->update_requested_latency)
1185 s->update_requested_latency(s);
1187 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1188 if (o->update_source_requested_latency)
1189 o->update_source_requested_latency(o);
1193 pa_sink_invalidate_requested_latency(s->monitor_of);
1196 /* Called from main thread */
1197 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1198 pa_source_assert_ref(s);
1200 /* min_latency == 0: no limit
1201 * min_latency anything else: specified limit
1203 * Similar for max_latency */
1205 if (min_latency < ABSOLUTE_MIN_LATENCY)
1206 min_latency = ABSOLUTE_MIN_LATENCY;
1208 if (max_latency <= 0 ||
1209 max_latency > ABSOLUTE_MAX_LATENCY)
1210 max_latency = ABSOLUTE_MAX_LATENCY;
1212 pa_assert(min_latency <= max_latency);
1214 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1215 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1216 max_latency == ABSOLUTE_MAX_LATENCY) ||
1217 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1219 if (PA_SOURCE_IS_LINKED(s->state)) {
1225 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1227 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1230 /* Called from main thread */
1231 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1232 pa_source_assert_ref(s);
1233 pa_assert(min_latency);
1234 pa_assert(max_latency);
1236 if (PA_SOURCE_IS_LINKED(s->state)) {
1237 pa_usec_t r[2] = { 0, 0 };
1239 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1241 *min_latency = r[0];
1242 *max_latency = r[1];
1244 *min_latency = s->thread_info.min_latency;
1245 *max_latency = s->thread_info.max_latency;
1249 /* Called from IO thread, and from main thread before pa_source_put() is called */
1250 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1253 pa_source_assert_ref(s);
1255 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1256 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1257 pa_assert(min_latency <= max_latency);
1259 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1260 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1261 max_latency == ABSOLUTE_MAX_LATENCY) ||
1262 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1265 s->thread_info.min_latency = min_latency;
1266 s->thread_info.max_latency = max_latency;
1268 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1269 pa_source_output *o;
1271 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1272 if (o->update_source_latency_range)
1273 o->update_source_latency_range(o);
1276 pa_source_invalidate_requested_latency(s);
1279 /* Called from main thread */
1280 size_t pa_source_get_max_rewind(pa_source *s) {
1282 pa_source_assert_ref(s);
1284 if (!PA_SOURCE_IS_LINKED(s->state))
1285 return s->thread_info.max_rewind;
1287 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);