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/core-util.h>
37 #include <pulsecore/source-output.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/core-subscribe.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/sample-util.h>
45 #define ABSOLUTE_MIN_LATENCY (500)
46 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
47 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
49 static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
51 static void source_free(pa_object *o);
53 pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
57 data->proplist = pa_proplist_new();
62 void pa_source_new_data_set_name(pa_source_new_data *data, const char *name) {
66 data->name = pa_xstrdup(name);
69 void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sample_spec *spec) {
72 if ((data->sample_spec_is_set = !!spec))
73 data->sample_spec = *spec;
76 void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_channel_map *map) {
79 if ((data->channel_map_is_set = !!map))
80 data->channel_map = *map;
83 void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume) {
86 if ((data->volume_is_set = !!volume))
87 data->volume = *volume;
90 void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute) {
93 data->muted_is_set = TRUE;
97 void pa_source_new_data_set_port(pa_source_new_data *data, const char *port) {
100 pa_xfree(data->active_port);
101 data->active_port = pa_xstrdup(port);
104 void pa_source_new_data_done(pa_source_new_data *data) {
107 pa_proplist_free(data->proplist);
112 while ((p = pa_hashmap_steal_first(data->ports)))
113 pa_device_port_free(p);
115 pa_hashmap_free(data->ports, NULL, NULL);
118 pa_xfree(data->name);
119 pa_xfree(data->active_port);
122 /* Called from main context */
123 static void reset_callbacks(pa_source *s) {
127 s->get_volume = NULL;
128 s->set_volume = NULL;
131 s->update_requested_latency = NULL;
135 /* Called from main context */
136 pa_source* pa_source_new(
138 pa_source_new_data *data,
139 pa_source_flags_t flags) {
143 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
148 pa_assert(data->name);
149 pa_assert_ctl_context();
151 s = pa_msgobject_new(pa_source);
153 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
154 pa_log_debug("Failed to register name %s.", data->name);
159 pa_source_new_data_set_name(data, name);
161 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
163 pa_namereg_unregister(core, name);
167 /* FIXME, need to free s here on failure */
169 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
170 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
172 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
174 if (!data->channel_map_is_set)
175 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
177 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
178 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
180 if (!data->volume_is_set)
181 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
183 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
184 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
186 if (!data->muted_is_set)
190 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
192 pa_device_init_description(data->proplist);
193 pa_device_init_icon(data->proplist, FALSE);
194 pa_device_init_intended_roles(data->proplist);
196 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
198 pa_namereg_unregister(core, name);
202 s->parent.parent.free = source_free;
203 s->parent.process_msg = pa_source_process_msg;
206 s->state = PA_SOURCE_INIT;
208 s->suspend_cause = 0;
209 s->name = pa_xstrdup(name);
210 s->proplist = pa_proplist_copy(data->proplist);
211 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
212 s->module = data->module;
213 s->card = data->card;
215 s->sample_spec = data->sample_spec;
216 s->channel_map = data->channel_map;
218 s->outputs = pa_idxset_new(NULL, NULL);
220 s->monitor_of = NULL;
222 s->virtual_volume = data->volume;
223 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
224 s->base_volume = PA_VOLUME_NORM;
225 s->n_volume_steps = PA_VOLUME_NORM+1;
226 s->muted = data->muted;
227 s->refresh_volume = s->refresh_muted = FALSE;
229 s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
236 /* As a minor optimization we just steal the list instead of
238 s->ports = data->ports;
241 s->active_port = NULL;
242 s->save_port = FALSE;
244 if (data->active_port && s->ports)
245 if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
246 s->save_port = data->save_port;
248 if (!s->active_port && s->ports) {
252 PA_HASHMAP_FOREACH(p, s->ports, state)
253 if (!s->active_port || p->priority > s->active_port->priority)
257 s->save_volume = data->save_volume;
258 s->save_muted = data->save_muted;
260 pa_silence_memchunk_get(
261 &core->silence_cache,
267 s->thread_info.rtpoll = NULL;
268 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
269 s->thread_info.soft_volume = s->soft_volume;
270 s->thread_info.soft_muted = s->muted;
271 s->thread_info.state = s->state;
272 s->thread_info.max_rewind = 0;
273 s->thread_info.requested_latency_valid = FALSE;
274 s->thread_info.requested_latency = 0;
275 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
276 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
278 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
281 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
283 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
284 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
287 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
288 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
295 /* Called from main context */
296 static int source_set_state(pa_source *s, pa_source_state_t state) {
298 pa_bool_t suspend_change;
299 pa_source_state_t original_state;
302 pa_assert_ctl_context();
304 if (s->state == state)
307 original_state = s->state;
310 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
311 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
314 if ((ret = s->set_state(s, state)) < 0)
318 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
321 s->set_state(s, original_state);
328 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
329 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
330 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
333 if (suspend_change) {
337 /* We're suspending or resuming, tell everyone about it */
339 PA_IDXSET_FOREACH(o, s->outputs, idx)
340 if (s->state == PA_SOURCE_SUSPENDED &&
341 (o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND))
342 pa_source_output_kill(o);
344 o->suspend(o, state == PA_SOURCE_SUSPENDED);
350 /* Called from main context */
351 void pa_source_put(pa_source *s) {
352 pa_source_assert_ref(s);
353 pa_assert_ctl_context();
355 pa_assert(s->state == PA_SOURCE_INIT);
357 /* The following fields must be initialized properly when calling _put() */
358 pa_assert(s->asyncmsgq);
359 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
361 /* Generally, flags should be initialized via pa_source_new(). As
362 * a special exception we allow volume related flags to be set
363 * between _new() and _put(). */
365 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL))
366 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
368 s->thread_info.soft_volume = s->soft_volume;
369 s->thread_info.soft_muted = s->muted;
371 pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME));
372 pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
373 pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
375 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
377 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
378 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
381 /* Called from main context */
382 void pa_source_unlink(pa_source *s) {
384 pa_source_output *o, *j = NULL;
387 pa_assert_ctl_context();
389 /* See pa_sink_unlink() for a couple of comments how this function
392 linked = PA_SOURCE_IS_LINKED(s->state);
395 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
397 if (s->state != PA_SOURCE_UNLINKED)
398 pa_namereg_unregister(s->core, s->name);
399 pa_idxset_remove_by_data(s->core->sources, s, NULL);
402 pa_idxset_remove_by_data(s->card->sources, s, NULL);
404 while ((o = pa_idxset_first(s->outputs, NULL))) {
406 pa_source_output_kill(o);
411 source_set_state(s, PA_SOURCE_UNLINKED);
413 s->state = PA_SOURCE_UNLINKED;
418 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
419 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
423 /* Called from main context */
424 static void source_free(pa_object *o) {
425 pa_source_output *so;
426 pa_source *s = PA_SOURCE(o);
429 pa_assert_ctl_context();
430 pa_assert(pa_source_refcnt(s) == 0);
432 if (PA_SOURCE_IS_LINKED(s->state))
435 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
437 pa_idxset_free(s->outputs, NULL, NULL);
439 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
440 pa_source_output_unref(so);
442 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
444 if (s->silence.memblock)
445 pa_memblock_unref(s->silence.memblock);
451 pa_proplist_free(s->proplist);
456 while ((p = pa_hashmap_steal_first(s->ports)))
457 pa_device_port_free(p);
459 pa_hashmap_free(s->ports, NULL, NULL);
465 /* Called from main context */
466 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
467 pa_source_assert_ref(s);
468 pa_assert_ctl_context();
473 /* Called from main context */
474 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
475 pa_source_assert_ref(s);
476 pa_source_assert_io_context(s);
478 s->thread_info.rtpoll = p;
481 /* Called from main context */
482 int pa_source_update_status(pa_source*s) {
483 pa_source_assert_ref(s);
484 pa_assert_ctl_context();
485 pa_assert(PA_SOURCE_IS_LINKED(s->state));
487 if (s->state == PA_SOURCE_SUSPENDED)
490 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
493 /* Called from main context */
494 int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
495 pa_source_assert_ref(s);
496 pa_assert_ctl_context();
497 pa_assert(PA_SOURCE_IS_LINKED(s->state));
498 pa_assert(cause != 0);
501 return -PA_ERR_NOTSUPPORTED;
504 s->suspend_cause |= cause;
506 s->suspend_cause &= ~cause;
508 if ((pa_source_get_state(s) == PA_SOURCE_SUSPENDED) == !!s->suspend_cause)
511 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
514 return source_set_state(s, PA_SOURCE_SUSPENDED);
516 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
519 /* Called from main context */
520 int pa_source_sync_suspend(pa_source *s) {
521 pa_sink_state_t state;
523 pa_source_assert_ref(s);
524 pa_assert_ctl_context();
525 pa_assert(PA_SOURCE_IS_LINKED(s->state));
526 pa_assert(s->monitor_of);
528 state = pa_sink_get_state(s->monitor_of);
530 if (state == PA_SINK_SUSPENDED)
531 return source_set_state(s, PA_SOURCE_SUSPENDED);
533 pa_assert(PA_SINK_IS_OPENED(state));
535 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
538 /* Called from main context */
539 pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q) {
540 pa_source_output *o, *n;
543 pa_source_assert_ref(s);
544 pa_assert_ctl_context();
545 pa_assert(PA_SOURCE_IS_LINKED(s->state));
550 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
551 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
553 pa_source_output_ref(o);
555 if (pa_source_output_start_move(o) >= 0)
558 pa_source_output_unref(o);
564 /* Called from main context */
565 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
568 pa_source_assert_ref(s);
569 pa_assert_ctl_context();
570 pa_assert(PA_SOURCE_IS_LINKED(s->state));
573 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
574 if (pa_source_output_finish_move(o, s, save) < 0)
575 pa_source_output_fail_move(o);
577 pa_source_output_unref(o);
580 pa_queue_free(q, NULL, NULL);
583 /* Called from main context */
584 void pa_source_move_all_fail(pa_queue *q) {
587 pa_assert_ctl_context();
590 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
591 pa_source_output_fail_move(o);
592 pa_source_output_unref(o);
595 pa_queue_free(q, NULL, NULL);
598 /* Called from IO thread context */
599 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
603 pa_source_assert_ref(s);
604 pa_source_assert_io_context(s);
605 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
610 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
613 pa_log_debug("Processing rewind...");
615 PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state) {
616 pa_source_output_assert_ref(o);
617 pa_source_output_process_rewind(o, nbytes);
621 /* Called from IO thread context */
622 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
626 pa_source_assert_ref(s);
627 pa_source_assert_io_context(s);
628 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
631 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
634 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
635 pa_memchunk vchunk = *chunk;
637 pa_memblock_ref(vchunk.memblock);
638 pa_memchunk_make_writable(&vchunk, 0);
640 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
641 pa_silence_memchunk(&vchunk, &s->sample_spec);
643 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
645 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
646 pa_source_output_assert_ref(o);
648 if (!o->thread_info.direct_on_input)
649 pa_source_output_push(o, &vchunk);
652 pa_memblock_unref(vchunk.memblock);
655 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
656 pa_source_output_assert_ref(o);
658 if (!o->thread_info.direct_on_input)
659 pa_source_output_push(o, chunk);
664 /* Called from IO thread context */
665 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
666 pa_source_assert_ref(s);
667 pa_source_assert_io_context(s);
668 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
669 pa_source_output_assert_ref(o);
670 pa_assert(o->thread_info.direct_on_input);
673 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
676 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
677 pa_memchunk vchunk = *chunk;
679 pa_memblock_ref(vchunk.memblock);
680 pa_memchunk_make_writable(&vchunk, 0);
682 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
683 pa_silence_memchunk(&vchunk, &s->sample_spec);
685 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
687 pa_source_output_push(o, &vchunk);
689 pa_memblock_unref(vchunk.memblock);
691 pa_source_output_push(o, chunk);
694 /* Called from main thread */
695 pa_usec_t pa_source_get_latency(pa_source *s) {
698 pa_source_assert_ref(s);
699 pa_assert_ctl_context();
700 pa_assert(PA_SOURCE_IS_LINKED(s->state));
702 if (s->state == PA_SOURCE_SUSPENDED)
705 if (!(s->flags & PA_SOURCE_LATENCY))
708 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
713 /* Called from IO thread */
714 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
718 pa_source_assert_ref(s);
719 pa_source_assert_io_context(s);
720 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
722 /* The returned value is supposed to be in the time domain of the sound card! */
724 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
727 if (!(s->flags & PA_SOURCE_LATENCY))
732 /* We probably should make this a proper vtable callback instead of going through process_msg() */
734 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
740 /* Called from main thread */
741 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save) {
742 pa_cvolume old_virtual_volume;
743 pa_bool_t virtual_volume_changed;
745 pa_source_assert_ref(s);
746 pa_assert_ctl_context();
747 pa_assert(PA_SOURCE_IS_LINKED(s->state));
749 pa_assert(pa_cvolume_valid(volume));
750 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
752 old_virtual_volume = s->virtual_volume;
753 s->virtual_volume = *volume;
754 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
755 s->save_volume = (!virtual_volume_changed && s->save_volume) || save;
758 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
761 s->soft_volume = s->virtual_volume;
763 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
765 if (virtual_volume_changed)
766 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
769 /* Called from main thread. Only to be called by source implementor */
770 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
771 pa_source_assert_ref(s);
772 pa_assert_ctl_context();
775 if (PA_SOURCE_IS_LINKED(s->state))
776 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
778 s->thread_info.soft_volume = *volume;
781 /* Called from main thread */
782 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
783 pa_source_assert_ref(s);
784 pa_assert_ctl_context();
785 pa_assert(PA_SOURCE_IS_LINKED(s->state));
787 if (s->refresh_volume || force_refresh) {
788 pa_cvolume old_virtual_volume = s->virtual_volume;
793 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
795 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
796 s->save_volume = TRUE;
797 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
801 return &s->virtual_volume;
804 /* Called from main thread */
805 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
806 pa_source_assert_ref(s);
807 pa_assert_ctl_context();
808 pa_assert(PA_SOURCE_IS_LINKED(s->state));
810 /* The source implementor may call this if the volume changed to make sure everyone is notified */
812 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
815 s->virtual_volume = *new_volume;
816 s->save_volume = TRUE;
818 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
821 /* Called from main thread */
822 void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
825 pa_source_assert_ref(s);
826 pa_assert_ctl_context();
827 pa_assert(PA_SOURCE_IS_LINKED(s->state));
829 old_muted = s->muted;
831 s->save_muted = (old_muted == s->muted && s->save_muted) || save;
836 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
838 if (old_muted != s->muted)
839 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
842 /* Called from main thread */
843 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
844 pa_source_assert_ref(s);
845 pa_assert_ctl_context();
846 pa_assert(PA_SOURCE_IS_LINKED(s->state));
848 if (s->refresh_muted || force_refresh) {
849 pa_bool_t old_muted = s->muted;
854 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
856 if (old_muted != s->muted) {
857 s->save_muted = TRUE;
859 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
861 /* Make sure the soft mute status stays in sync */
862 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
869 /* Called from main thread */
870 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
871 pa_source_assert_ref(s);
872 pa_assert_ctl_context();
873 pa_assert(PA_SOURCE_IS_LINKED(s->state));
875 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
877 if (s->muted == new_muted)
880 s->muted = new_muted;
881 s->save_muted = TRUE;
883 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
886 /* Called from main thread */
887 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
888 pa_source_assert_ref(s);
889 pa_assert_ctl_context();
892 pa_proplist_update(s->proplist, mode, p);
894 if (PA_SOURCE_IS_LINKED(s->state)) {
895 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
896 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
902 /* Called from main thread */
903 /* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
904 void pa_source_set_description(pa_source *s, const char *description) {
906 pa_source_assert_ref(s);
907 pa_assert_ctl_context();
909 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
912 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
914 if (old && description && pa_streq(old, description))
918 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
920 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
922 if (PA_SOURCE_IS_LINKED(s->state)) {
923 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
924 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
928 /* Called from main thread */
929 unsigned pa_source_linked_by(pa_source *s) {
930 pa_source_assert_ref(s);
931 pa_assert(PA_SOURCE_IS_LINKED(s->state));
932 pa_assert_ctl_context();
934 return pa_idxset_size(s->outputs);
937 /* Called from main thread */
938 unsigned pa_source_used_by(pa_source *s) {
941 pa_source_assert_ref(s);
942 pa_assert(PA_SOURCE_IS_LINKED(s->state));
943 pa_assert_ctl_context();
945 ret = pa_idxset_size(s->outputs);
946 pa_assert(ret >= s->n_corked);
948 return ret - s->n_corked;
951 /* Called from main thread */
952 unsigned pa_source_check_suspend(pa_source *s) {
957 pa_source_assert_ref(s);
958 pa_assert_ctl_context();
960 if (!PA_SOURCE_IS_LINKED(s->state))
965 PA_IDXSET_FOREACH(o, s->outputs, idx) {
966 pa_source_output_state_t st;
968 st = pa_source_output_get_state(o);
969 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
971 if (st == PA_SOURCE_OUTPUT_CORKED)
974 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
983 /* Called from IO thread, except when it is not */
984 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
985 pa_source *s = PA_SOURCE(object);
986 pa_source_assert_ref(s);
988 switch ((pa_source_message_t) code) {
990 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
991 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
993 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
995 if (o->direct_on_input) {
996 o->thread_info.direct_on_input = o->direct_on_input;
997 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
1000 pa_assert(!o->thread_info.attached);
1001 o->thread_info.attached = TRUE;
1006 pa_source_output_set_state_within_thread(o, o->state);
1008 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
1009 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
1011 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1013 /* We don't just invalidate the requested latency here,
1014 * because if we are in a move we might need to fix up the
1015 * requested latency. */
1016 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
1021 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
1022 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
1024 pa_source_output_set_state_within_thread(o, o->state);
1029 pa_assert(o->thread_info.attached);
1030 o->thread_info.attached = FALSE;
1032 if (o->thread_info.direct_on_input) {
1033 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
1034 o->thread_info.direct_on_input = NULL;
1037 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
1038 pa_source_output_unref(o);
1040 pa_source_invalidate_requested_latency(s);
1045 case PA_SOURCE_MESSAGE_SET_VOLUME:
1046 s->thread_info.soft_volume = s->soft_volume;
1049 case PA_SOURCE_MESSAGE_GET_VOLUME:
1052 case PA_SOURCE_MESSAGE_SET_MUTE:
1053 s->thread_info.soft_muted = s->muted;
1056 case PA_SOURCE_MESSAGE_GET_MUTE:
1059 case PA_SOURCE_MESSAGE_SET_STATE: {
1061 pa_bool_t suspend_change =
1062 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
1063 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
1065 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1067 if (suspend_change) {
1068 pa_source_output *o;
1071 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1072 if (o->suspend_within_thread)
1073 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
1080 case PA_SOURCE_MESSAGE_DETACH:
1082 /* Detach all streams */
1083 pa_source_detach_within_thread(s);
1086 case PA_SOURCE_MESSAGE_ATTACH:
1088 /* Reattach all streams */
1089 pa_source_attach_within_thread(s);
1092 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
1094 pa_usec_t *usec = userdata;
1095 *usec = pa_source_get_requested_latency_within_thread(s);
1097 if (*usec == (pa_usec_t) -1)
1098 *usec = s->thread_info.max_latency;
1103 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
1104 pa_usec_t *r = userdata;
1106 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
1111 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
1112 pa_usec_t *r = userdata;
1114 r[0] = s->thread_info.min_latency;
1115 r[1] = s->thread_info.max_latency;
1120 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1122 *((size_t*) userdata) = s->thread_info.max_rewind;
1125 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1127 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1130 case PA_SOURCE_MESSAGE_GET_LATENCY:
1132 if (s->monitor_of) {
1133 *((pa_usec_t*) userdata) = 0;
1137 /* Implementors need to overwrite this implementation! */
1140 case PA_SOURCE_MESSAGE_MAX:
1147 /* Called from main thread */
1148 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
1153 pa_core_assert_ref(c);
1154 pa_assert_ctl_context();
1155 pa_assert(cause != 0);
1157 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1160 if (source->monitor_of)
1163 if ((r = pa_source_suspend(source, suspend, cause)) < 0)
1170 /* Called from main thread */
1171 void pa_source_detach(pa_source *s) {
1172 pa_source_assert_ref(s);
1173 pa_assert_ctl_context();
1174 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1176 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1179 /* Called from main thread */
1180 void pa_source_attach(pa_source *s) {
1181 pa_source_assert_ref(s);
1182 pa_assert_ctl_context();
1183 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1185 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1188 /* Called from IO thread */
1189 void pa_source_detach_within_thread(pa_source *s) {
1190 pa_source_output *o;
1193 pa_source_assert_ref(s);
1194 pa_source_assert_io_context(s);
1195 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1197 PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
1202 /* Called from IO thread */
1203 void pa_source_attach_within_thread(pa_source *s) {
1204 pa_source_output *o;
1207 pa_source_assert_ref(s);
1208 pa_source_assert_io_context(s);
1209 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1211 PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
1216 /* Called from IO thread */
1217 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1218 pa_usec_t result = (pa_usec_t) -1;
1219 pa_source_output *o;
1222 pa_source_assert_ref(s);
1223 pa_source_assert_io_context(s);
1225 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1226 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1228 if (s->thread_info.requested_latency_valid)
1229 return s->thread_info.requested_latency;
1231 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1233 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1234 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1235 result = o->thread_info.requested_source_latency;
1237 if (result != (pa_usec_t) -1)
1238 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1240 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1241 /* Only cache this if we are fully set up */
1242 s->thread_info.requested_latency = result;
1243 s->thread_info.requested_latency_valid = TRUE;
1249 /* Called from main thread */
1250 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1253 pa_source_assert_ref(s);
1254 pa_assert_ctl_context();
1255 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1257 if (s->state == PA_SOURCE_SUSPENDED)
1260 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1265 /* Called from IO thread */
1266 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1267 pa_source_output *o;
1270 pa_source_assert_ref(s);
1271 pa_source_assert_io_context(s);
1273 if (max_rewind == s->thread_info.max_rewind)
1276 s->thread_info.max_rewind = max_rewind;
1278 if (PA_SOURCE_IS_LINKED(s->thread_info.state))
1279 PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
1280 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1283 /* Called from main thread */
1284 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1285 pa_source_assert_ref(s);
1286 pa_assert_ctl_context();
1288 if (PA_SOURCE_IS_LINKED(s->state))
1289 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1291 pa_source_set_max_rewind_within_thread(s, max_rewind);
1294 /* Called from IO thread */
1295 void pa_source_invalidate_requested_latency(pa_source *s) {
1296 pa_source_output *o;
1299 pa_source_assert_ref(s);
1300 pa_source_assert_io_context(s);
1302 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1305 s->thread_info.requested_latency_valid = FALSE;
1307 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1309 if (s->update_requested_latency)
1310 s->update_requested_latency(s);
1312 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1313 if (o->update_source_requested_latency)
1314 o->update_source_requested_latency(o);
1318 pa_sink_invalidate_requested_latency(s->monitor_of);
1321 /* Called from main thread */
1322 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1323 pa_source_assert_ref(s);
1324 pa_assert_ctl_context();
1326 /* min_latency == 0: no limit
1327 * min_latency anything else: specified limit
1329 * Similar for max_latency */
1331 if (min_latency < ABSOLUTE_MIN_LATENCY)
1332 min_latency = ABSOLUTE_MIN_LATENCY;
1334 if (max_latency <= 0 ||
1335 max_latency > ABSOLUTE_MAX_LATENCY)
1336 max_latency = ABSOLUTE_MAX_LATENCY;
1338 pa_assert(min_latency <= max_latency);
1340 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1341 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1342 max_latency == ABSOLUTE_MAX_LATENCY) ||
1343 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1345 if (PA_SOURCE_IS_LINKED(s->state)) {
1351 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1353 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1356 /* Called from main thread */
1357 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1358 pa_source_assert_ref(s);
1359 pa_assert_ctl_context();
1360 pa_assert(min_latency);
1361 pa_assert(max_latency);
1363 if (PA_SOURCE_IS_LINKED(s->state)) {
1364 pa_usec_t r[2] = { 0, 0 };
1366 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1368 *min_latency = r[0];
1369 *max_latency = r[1];
1371 *min_latency = s->thread_info.min_latency;
1372 *max_latency = s->thread_info.max_latency;
1376 /* Called from IO thread, and from main thread before pa_source_put() is called */
1377 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1380 pa_source_assert_ref(s);
1381 pa_source_assert_io_context(s);
1383 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1384 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1385 pa_assert(min_latency <= max_latency);
1387 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1388 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1389 max_latency == ABSOLUTE_MAX_LATENCY) ||
1390 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1393 s->thread_info.min_latency = min_latency;
1394 s->thread_info.max_latency = max_latency;
1396 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1397 pa_source_output *o;
1399 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1400 if (o->update_source_latency_range)
1401 o->update_source_latency_range(o);
1404 pa_source_invalidate_requested_latency(s);
1407 /* Called from main thread, before the source is put */
1408 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1409 pa_source_assert_ref(s);
1410 pa_assert_ctl_context();
1412 pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1414 if (latency < ABSOLUTE_MIN_LATENCY)
1415 latency = ABSOLUTE_MIN_LATENCY;
1417 if (latency > ABSOLUTE_MAX_LATENCY)
1418 latency = ABSOLUTE_MAX_LATENCY;
1420 s->fixed_latency = latency;
1423 /* Called from main thread */
1424 size_t pa_source_get_max_rewind(pa_source *s) {
1426 pa_assert_ctl_context();
1427 pa_source_assert_ref(s);
1429 if (!PA_SOURCE_IS_LINKED(s->state))
1430 return s->thread_info.max_rewind;
1432 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1437 /* Called from main context */
1438 int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
1439 pa_device_port *port;
1442 pa_assert_ctl_context();
1445 pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s->index, s->name);
1446 return -PA_ERR_NOTIMPLEMENTED;
1450 return -PA_ERR_NOENTITY;
1452 if (!(port = pa_hashmap_get(s->ports, name)))
1453 return -PA_ERR_NOENTITY;
1455 if (s->active_port == port) {
1456 s->save_port = s->save_port || save;
1460 if ((s->set_port(s, port)) < 0)
1461 return -PA_ERR_NOENTITY;
1463 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1465 pa_log_info("Changed port of source %u \"%s\" to %s", s->index, s->name, port->name);
1467 s->active_port = port;
1468 s->save_port = save;