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_set_port(pa_source_new_data *data, const char *port) {
99 pa_xfree(data->active_port);
100 data->active_port = pa_xstrdup(port);
103 void pa_source_new_data_done(pa_source_new_data *data) {
106 pa_proplist_free(data->proplist);
111 while ((p = pa_hashmap_steal_first(data->ports)))
112 pa_device_port_free(p);
114 pa_hashmap_free(data->ports, NULL, NULL);
117 pa_xfree(data->name);
118 pa_xfree(data->active_port);
121 /* Called from main context */
122 static void reset_callbacks(pa_source *s) {
126 s->get_volume = NULL;
127 s->set_volume = NULL;
130 s->update_requested_latency = NULL;
134 /* Called from main context */
135 pa_source* pa_source_new(
137 pa_source_new_data *data,
138 pa_source_flags_t flags) {
142 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
147 pa_assert(data->name);
149 s = pa_msgobject_new(pa_source);
151 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
152 pa_log_debug("Failed to register name %s.", data->name);
157 pa_source_new_data_set_name(data, name);
159 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
161 pa_namereg_unregister(core, name);
165 /* FIXME, need to free s here on failure */
167 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
168 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
170 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
172 if (!data->channel_map_is_set)
173 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
175 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
176 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
178 if (!data->volume_is_set)
179 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
181 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
182 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
184 if (!data->muted_is_set)
188 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
190 pa_device_init_description(data->proplist);
191 pa_device_init_icon(data->proplist, FALSE);
192 pa_device_init_intended_roles(data->proplist);
194 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
196 pa_namereg_unregister(core, name);
200 s->parent.parent.free = source_free;
201 s->parent.process_msg = pa_source_process_msg;
204 s->state = PA_SOURCE_INIT;
206 s->suspend_cause = 0;
207 s->name = pa_xstrdup(name);
208 s->proplist = pa_proplist_copy(data->proplist);
209 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
210 s->module = data->module;
211 s->card = data->card;
213 s->sample_spec = data->sample_spec;
214 s->channel_map = data->channel_map;
216 s->outputs = pa_idxset_new(NULL, NULL);
218 s->monitor_of = NULL;
220 s->virtual_volume = data->volume;
221 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
222 s->base_volume = PA_VOLUME_NORM;
223 s->n_volume_steps = PA_VOLUME_NORM+1;
224 s->muted = data->muted;
225 s->refresh_volume = s->refresh_muted = FALSE;
227 s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
235 /* As a minor optimization we just steal the list instead of
237 s->ports = data->ports;
240 s->active_port = NULL;
241 s->save_port = FALSE;
243 if (data->active_port && s->ports)
244 if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
245 s->save_port = data->save_port;
247 if (!s->active_port && s->ports) {
251 PA_HASHMAP_FOREACH(p, s->ports, state)
252 if (!s->active_port || p->priority > s->active_port->priority)
256 s->save_volume = data->save_volume;
257 s->save_muted = data->save_muted;
259 pa_silence_memchunk_get(
260 &core->silence_cache,
266 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
267 s->thread_info.soft_volume = s->soft_volume;
268 s->thread_info.soft_muted = s->muted;
269 s->thread_info.state = s->state;
270 s->thread_info.max_rewind = 0;
271 s->thread_info.requested_latency_valid = FALSE;
272 s->thread_info.requested_latency = 0;
273 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
274 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
276 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
279 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
281 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
282 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
285 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
286 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
293 /* Called from main context */
294 static int source_set_state(pa_source *s, pa_source_state_t state) {
296 pa_bool_t suspend_change;
297 pa_source_state_t original_state;
301 if (s->state == state)
304 original_state = s->state;
307 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
308 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
311 if ((ret = s->set_state(s, state)) < 0)
315 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
318 s->set_state(s, original_state);
325 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
326 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
327 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
330 if (suspend_change) {
334 /* We're suspending or resuming, tell everyone about it */
336 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
337 if (s->state == PA_SOURCE_SUSPENDED &&
338 (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
339 pa_source_output_kill(o);
341 o->suspend(o, state == PA_SOURCE_SUSPENDED);
348 /* Called from main context */
349 void pa_source_put(pa_source *s) {
350 pa_source_assert_ref(s);
352 pa_assert(s->state == PA_SOURCE_INIT);
354 /* The following fields must be initialized properly when calling _put() */
355 pa_assert(s->asyncmsgq);
356 pa_assert(s->rtpoll);
357 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
359 /* Generally, flags should be initialized via pa_source_new(). As
360 * a special exception we allow volume related flags to be set
361 * between _new() and _put(). */
363 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL))
364 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
366 s->thread_info.soft_volume = s->soft_volume;
367 s->thread_info.soft_muted = s->muted;
369 pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME));
370 pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
371 pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
373 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
375 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
376 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
379 /* Called from main context */
380 void pa_source_unlink(pa_source *s) {
382 pa_source_output *o, *j = NULL;
386 /* See pa_sink_unlink() for a couple of comments how this function
389 linked = PA_SOURCE_IS_LINKED(s->state);
392 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
394 if (s->state != PA_SOURCE_UNLINKED)
395 pa_namereg_unregister(s->core, s->name);
396 pa_idxset_remove_by_data(s->core->sources, s, NULL);
399 pa_idxset_remove_by_data(s->card->sources, s, NULL);
401 while ((o = pa_idxset_first(s->outputs, NULL))) {
403 pa_source_output_kill(o);
408 source_set_state(s, PA_SOURCE_UNLINKED);
410 s->state = PA_SOURCE_UNLINKED;
415 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
416 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
420 /* Called from main context */
421 static void source_free(pa_object *o) {
422 pa_source_output *so;
423 pa_source *s = PA_SOURCE(o);
426 pa_assert(pa_source_refcnt(s) == 0);
428 if (PA_SOURCE_IS_LINKED(s->state))
431 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
433 pa_idxset_free(s->outputs, NULL, NULL);
435 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
436 pa_source_output_unref(so);
438 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
440 if (s->silence.memblock)
441 pa_memblock_unref(s->silence.memblock);
447 pa_proplist_free(s->proplist);
452 while ((p = pa_hashmap_steal_first(s->ports)))
453 pa_device_port_free(p);
455 pa_hashmap_free(s->ports, NULL, NULL);
461 /* Called from main context */
462 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
463 pa_source_assert_ref(s);
468 /* Called from main context */
469 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
470 pa_source_assert_ref(s);
475 /* Called from main context */
476 int pa_source_update_status(pa_source*s) {
477 pa_source_assert_ref(s);
478 pa_assert(PA_SOURCE_IS_LINKED(s->state));
480 if (s->state == PA_SOURCE_SUSPENDED)
483 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
486 /* Called from main context */
487 int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
488 pa_source_assert_ref(s);
489 pa_assert(PA_SOURCE_IS_LINKED(s->state));
490 pa_assert(cause != 0);
493 return -PA_ERR_NOTSUPPORTED;
496 s->suspend_cause |= cause;
498 s->suspend_cause &= ~cause;
500 if ((pa_source_get_state(s) == PA_SOURCE_SUSPENDED) == !!s->suspend_cause)
503 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
506 return source_set_state(s, PA_SOURCE_SUSPENDED);
508 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
511 /* Called from main context */
512 int pa_source_sync_suspend(pa_source *s) {
513 pa_sink_state_t state;
515 pa_source_assert_ref(s);
516 pa_assert(PA_SOURCE_IS_LINKED(s->state));
517 pa_assert(s->monitor_of);
519 state = pa_sink_get_state(s->monitor_of);
521 if (state == PA_SINK_SUSPENDED)
522 return source_set_state(s, PA_SOURCE_SUSPENDED);
524 pa_assert(PA_SINK_IS_OPENED(state));
526 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
529 /* Called from main context */
530 pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q) {
531 pa_source_output *o, *n;
534 pa_source_assert_ref(s);
535 pa_assert(PA_SOURCE_IS_LINKED(s->state));
540 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
541 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
543 pa_source_output_ref(o);
545 if (pa_source_output_start_move(o) >= 0)
548 pa_source_output_unref(o);
554 /* Called from main context */
555 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
558 pa_source_assert_ref(s);
559 pa_assert(PA_SOURCE_IS_LINKED(s->state));
562 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
563 if (pa_source_output_finish_move(o, s, save) < 0)
564 pa_source_output_kill(o);
566 pa_source_output_unref(o);
569 pa_queue_free(q, NULL, NULL);
572 /* Called from main context */
573 void pa_source_move_all_fail(pa_queue *q) {
577 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
578 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
579 pa_source_output_kill(o);
580 pa_source_output_unref(o);
584 pa_queue_free(q, NULL, NULL);
587 /* Called from IO thread context */
588 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
592 pa_source_assert_ref(s);
593 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
595 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
601 pa_log_debug("Processing rewind...");
603 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
604 pa_source_output_assert_ref(o);
605 pa_source_output_process_rewind(o, nbytes);
609 /* Called from IO thread context */
610 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
614 pa_source_assert_ref(s);
615 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
618 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
621 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
622 pa_memchunk vchunk = *chunk;
624 pa_memblock_ref(vchunk.memblock);
625 pa_memchunk_make_writable(&vchunk, 0);
627 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
628 pa_silence_memchunk(&vchunk, &s->sample_spec);
630 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
632 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
633 pa_source_output_assert_ref(o);
635 if (!o->thread_info.direct_on_input)
636 pa_source_output_push(o, &vchunk);
639 pa_memblock_unref(vchunk.memblock);
642 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
643 pa_source_output_assert_ref(o);
645 if (!o->thread_info.direct_on_input)
646 pa_source_output_push(o, chunk);
651 /* Called from IO thread context */
652 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
653 pa_source_assert_ref(s);
654 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
655 pa_source_output_assert_ref(o);
656 pa_assert(o->thread_info.direct_on_input);
659 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
662 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
663 pa_memchunk vchunk = *chunk;
665 pa_memblock_ref(vchunk.memblock);
666 pa_memchunk_make_writable(&vchunk, 0);
668 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
669 pa_silence_memchunk(&vchunk, &s->sample_spec);
671 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
673 pa_source_output_push(o, &vchunk);
675 pa_memblock_unref(vchunk.memblock);
677 pa_source_output_push(o, chunk);
680 /* Called from main thread */
681 pa_usec_t pa_source_get_latency(pa_source *s) {
684 pa_source_assert_ref(s);
685 pa_assert(PA_SOURCE_IS_LINKED(s->state));
687 if (s->state == PA_SOURCE_SUSPENDED)
690 if (!(s->flags & PA_SOURCE_LATENCY))
693 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
698 /* Called from IO thread */
699 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
703 pa_source_assert_ref(s);
704 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
706 /* The returned value is supposed to be in the time domain of the sound card! */
708 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
711 if (!(s->flags & PA_SOURCE_LATENCY))
716 /* We probably should make this a proper vtable callback instead of going through process_msg() */
718 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
724 /* Called from main thread */
725 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save) {
726 pa_cvolume old_virtual_volume;
727 pa_bool_t virtual_volume_changed;
729 pa_source_assert_ref(s);
730 pa_assert(PA_SOURCE_IS_LINKED(s->state));
732 pa_assert(pa_cvolume_valid(volume));
733 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
735 old_virtual_volume = s->virtual_volume;
736 s->virtual_volume = *volume;
737 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
738 s->save_volume = (!virtual_volume_changed && s->save_volume) || save;
741 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
744 s->soft_volume = s->virtual_volume;
746 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
748 if (virtual_volume_changed)
749 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
752 /* Called from main thread. Only to be called by source implementor */
753 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
754 pa_source_assert_ref(s);
757 if (PA_SOURCE_IS_LINKED(s->state))
758 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
760 s->thread_info.soft_volume = *volume;
763 /* Called from main thread */
764 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
765 pa_source_assert_ref(s);
766 pa_assert(PA_SOURCE_IS_LINKED(s->state));
768 if (s->refresh_volume || force_refresh) {
769 pa_cvolume old_virtual_volume = s->virtual_volume;
774 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
776 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
777 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
780 return &s->virtual_volume;
783 /* Called from main thread */
784 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save) {
785 pa_source_assert_ref(s);
787 /* The source implementor may call this if the volume changed to make sure everyone is notified */
789 if (pa_cvolume_equal(&s->virtual_volume, new_volume)) {
790 s->save_volume = s->save_volume || save;
794 s->virtual_volume = *new_volume;
795 s->save_volume = save;
797 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
800 /* Called from main thread */
801 void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
804 pa_source_assert_ref(s);
805 pa_assert(PA_SOURCE_IS_LINKED(s->state));
807 old_muted = s->muted;
809 s->save_muted = (old_muted == s->muted && s->save_muted) || save;
814 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
816 if (old_muted != s->muted)
817 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
820 /* Called from main thread */
821 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
822 pa_source_assert_ref(s);
823 pa_assert(PA_SOURCE_IS_LINKED(s->state));
825 if (s->refresh_muted || force_refresh) {
826 pa_bool_t old_muted = s->muted;
831 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
833 if (old_muted != s->muted) {
834 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
836 /* Make sure the soft mute status stays in sync */
837 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
844 /* Called from main thread */
845 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save) {
846 pa_source_assert_ref(s);
848 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
850 if (s->muted == new_muted) {
851 s->save_muted = s->save_muted || save;
855 s->muted = new_muted;
856 s->save_muted = save;
858 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
861 /* Called from main thread */
862 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
863 pa_source_assert_ref(s);
866 pa_proplist_update(s->proplist, mode, p);
868 if (PA_SOURCE_IS_LINKED(s->state)) {
869 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
870 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
876 /* Called from main thread */
877 void pa_source_set_description(pa_source *s, const char *description) {
879 pa_source_assert_ref(s);
881 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
884 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
886 if (old && description && !strcmp(old, description))
890 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
892 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
894 if (PA_SOURCE_IS_LINKED(s->state)) {
895 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
896 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
900 /* Called from main thread */
901 unsigned pa_source_linked_by(pa_source *s) {
902 pa_source_assert_ref(s);
903 pa_assert(PA_SOURCE_IS_LINKED(s->state));
905 return pa_idxset_size(s->outputs);
908 /* Called from main thread */
909 unsigned pa_source_used_by(pa_source *s) {
912 pa_source_assert_ref(s);
913 pa_assert(PA_SOURCE_IS_LINKED(s->state));
915 ret = pa_idxset_size(s->outputs);
916 pa_assert(ret >= s->n_corked);
918 return ret - s->n_corked;
921 /* Called from main thread */
922 unsigned pa_source_check_suspend(pa_source *s) {
927 pa_source_assert_ref(s);
929 if (!PA_SOURCE_IS_LINKED(s->state))
934 PA_IDXSET_FOREACH(o, s->outputs, idx) {
935 pa_source_output_state_t st;
937 st = pa_source_output_get_state(o);
938 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
940 if (st == PA_SOURCE_OUTPUT_CORKED)
943 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
952 /* Called from IO thread, except when it is not */
953 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
954 pa_source *s = PA_SOURCE(object);
955 pa_source_assert_ref(s);
957 switch ((pa_source_message_t) code) {
959 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
960 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
962 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
964 if (o->direct_on_input) {
965 o->thread_info.direct_on_input = o->direct_on_input;
966 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
969 pa_assert(!o->thread_info.attached);
970 o->thread_info.attached = TRUE;
975 pa_source_output_set_state_within_thread(o, o->state);
977 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
978 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
980 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
982 /* We don't just invalidate the requested latency here,
983 * because if we are in a move we might need to fix up the
984 * requested latency. */
985 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
990 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
991 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
993 pa_source_output_set_state_within_thread(o, o->state);
998 pa_assert(o->thread_info.attached);
999 o->thread_info.attached = FALSE;
1001 if (o->thread_info.direct_on_input) {
1002 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
1003 o->thread_info.direct_on_input = NULL;
1006 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
1007 pa_source_output_unref(o);
1009 pa_source_invalidate_requested_latency(s);
1014 case PA_SOURCE_MESSAGE_SET_VOLUME:
1015 s->thread_info.soft_volume = s->soft_volume;
1018 case PA_SOURCE_MESSAGE_GET_VOLUME:
1021 case PA_SOURCE_MESSAGE_SET_MUTE:
1022 s->thread_info.soft_muted = s->muted;
1025 case PA_SOURCE_MESSAGE_GET_MUTE:
1028 case PA_SOURCE_MESSAGE_SET_STATE: {
1030 pa_bool_t suspend_change =
1031 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
1032 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
1034 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1036 if (suspend_change) {
1037 pa_source_output *o;
1040 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1041 if (o->suspend_within_thread)
1042 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
1049 case PA_SOURCE_MESSAGE_DETACH:
1051 /* Detach all streams */
1052 pa_source_detach_within_thread(s);
1055 case PA_SOURCE_MESSAGE_ATTACH:
1057 /* Reattach all streams */
1058 pa_source_attach_within_thread(s);
1061 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
1063 pa_usec_t *usec = userdata;
1064 *usec = pa_source_get_requested_latency_within_thread(s);
1066 if (*usec == (pa_usec_t) -1)
1067 *usec = s->thread_info.max_latency;
1072 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
1073 pa_usec_t *r = userdata;
1075 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
1080 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
1081 pa_usec_t *r = userdata;
1083 r[0] = s->thread_info.min_latency;
1084 r[1] = s->thread_info.max_latency;
1089 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1091 *((size_t*) userdata) = s->thread_info.max_rewind;
1094 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1096 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1099 case PA_SOURCE_MESSAGE_GET_LATENCY:
1101 if (s->monitor_of) {
1102 *((pa_usec_t*) userdata) = 0;
1106 /* Implementors need to overwrite this implementation! */
1109 case PA_SOURCE_MESSAGE_MAX:
1116 /* Called from main thread */
1117 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
1122 pa_core_assert_ref(c);
1123 pa_assert(cause != 0);
1125 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1128 if (source->monitor_of)
1131 if ((r = pa_source_suspend(source, suspend, cause)) < 0)
1138 /* Called from main thread */
1139 void pa_source_detach(pa_source *s) {
1140 pa_source_assert_ref(s);
1141 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1143 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1146 /* Called from main thread */
1147 void pa_source_attach(pa_source *s) {
1148 pa_source_assert_ref(s);
1149 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1151 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1154 /* Called from IO thread */
1155 void pa_source_detach_within_thread(pa_source *s) {
1156 pa_source_output *o;
1159 pa_source_assert_ref(s);
1160 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1162 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1167 /* Called from IO thread */
1168 void pa_source_attach_within_thread(pa_source *s) {
1169 pa_source_output *o;
1172 pa_source_assert_ref(s);
1173 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1175 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1180 /* Called from IO thread */
1181 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1182 pa_usec_t result = (pa_usec_t) -1;
1183 pa_source_output *o;
1186 pa_source_assert_ref(s);
1188 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1189 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1191 if (s->thread_info.requested_latency_valid)
1192 return s->thread_info.requested_latency;
1194 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1196 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1197 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1198 result = o->thread_info.requested_source_latency;
1200 if (result != (pa_usec_t) -1)
1201 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1203 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1204 /* Only cache this if we are fully set up */
1205 s->thread_info.requested_latency = result;
1206 s->thread_info.requested_latency_valid = TRUE;
1212 /* Called from main thread */
1213 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1216 pa_source_assert_ref(s);
1217 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1219 if (s->state == PA_SOURCE_SUSPENDED)
1222 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1227 /* Called from IO thread */
1228 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1229 pa_source_output *o;
1232 pa_source_assert_ref(s);
1234 if (max_rewind == s->thread_info.max_rewind)
1237 s->thread_info.max_rewind = max_rewind;
1239 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1240 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1241 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1245 /* Called from main thread */
1246 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1247 pa_source_assert_ref(s);
1249 if (PA_SOURCE_IS_LINKED(s->state))
1250 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1252 pa_source_set_max_rewind_within_thread(s, max_rewind);
1255 /* Called from IO thread */
1256 void pa_source_invalidate_requested_latency(pa_source *s) {
1257 pa_source_output *o;
1260 pa_source_assert_ref(s);
1262 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1265 s->thread_info.requested_latency_valid = FALSE;
1267 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1269 if (s->update_requested_latency)
1270 s->update_requested_latency(s);
1272 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1273 if (o->update_source_requested_latency)
1274 o->update_source_requested_latency(o);
1278 pa_sink_invalidate_requested_latency(s->monitor_of);
1281 /* Called from main thread */
1282 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1283 pa_source_assert_ref(s);
1285 /* min_latency == 0: no limit
1286 * min_latency anything else: specified limit
1288 * Similar for max_latency */
1290 if (min_latency < ABSOLUTE_MIN_LATENCY)
1291 min_latency = ABSOLUTE_MIN_LATENCY;
1293 if (max_latency <= 0 ||
1294 max_latency > ABSOLUTE_MAX_LATENCY)
1295 max_latency = ABSOLUTE_MAX_LATENCY;
1297 pa_assert(min_latency <= max_latency);
1299 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1300 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1301 max_latency == ABSOLUTE_MAX_LATENCY) ||
1302 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1304 if (PA_SOURCE_IS_LINKED(s->state)) {
1310 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1312 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1315 /* Called from main thread */
1316 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1317 pa_source_assert_ref(s);
1318 pa_assert(min_latency);
1319 pa_assert(max_latency);
1321 if (PA_SOURCE_IS_LINKED(s->state)) {
1322 pa_usec_t r[2] = { 0, 0 };
1324 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1326 *min_latency = r[0];
1327 *max_latency = r[1];
1329 *min_latency = s->thread_info.min_latency;
1330 *max_latency = s->thread_info.max_latency;
1334 /* Called from IO thread, and from main thread before pa_source_put() is called */
1335 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1338 pa_source_assert_ref(s);
1340 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1341 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1342 pa_assert(min_latency <= max_latency);
1344 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1345 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1346 max_latency == ABSOLUTE_MAX_LATENCY) ||
1347 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1350 s->thread_info.min_latency = min_latency;
1351 s->thread_info.max_latency = max_latency;
1353 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1354 pa_source_output *o;
1356 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1357 if (o->update_source_latency_range)
1358 o->update_source_latency_range(o);
1361 pa_source_invalidate_requested_latency(s);
1364 /* Called from main thread, before the source is put */
1365 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1366 pa_source_assert_ref(s);
1368 pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1370 if (latency < ABSOLUTE_MIN_LATENCY)
1371 latency = ABSOLUTE_MIN_LATENCY;
1373 if (latency > ABSOLUTE_MAX_LATENCY)
1374 latency = ABSOLUTE_MAX_LATENCY;
1376 s->fixed_latency = latency;
1379 /* Called from main thread */
1380 size_t pa_source_get_max_rewind(pa_source *s) {
1382 pa_source_assert_ref(s);
1384 if (!PA_SOURCE_IS_LINKED(s->state))
1385 return s->thread_info.max_rewind;
1387 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1392 /* Called from main context */
1393 int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
1394 pa_device_port *port;
1399 pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
1400 return -PA_ERR_NOTIMPLEMENTED;
1404 return -PA_ERR_NOENTITY;
1406 if (!(port = pa_hashmap_get(s->ports, name)))
1407 return -PA_ERR_NOENTITY;
1409 if (s->active_port == port) {
1410 s->save_port = s->save_port || save;
1414 if ((s->set_port(s, port)) < 0)
1415 return -PA_ERR_NOENTITY;
1417 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1419 pa_log_info("Changed port of source %u \"%s\" to %s", s->index, s->name, port->name);
1421 s->active_port = port;
1422 s->save_port = save;