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))) {
156 pa_source_new_data_set_name(data, name);
158 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
160 pa_namereg_unregister(core, name);
164 /* FIXME, need to free s here on failure */
166 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
167 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
169 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
171 if (!data->channel_map_is_set)
172 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
174 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
175 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
177 if (!data->volume_is_set)
178 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
180 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
181 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
183 if (!data->muted_is_set)
187 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
189 pa_device_init_description(data->proplist);
190 pa_device_init_icon(data->proplist, FALSE);
191 pa_device_init_intended_roles(data->proplist);
193 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
195 pa_namereg_unregister(core, name);
199 s->parent.parent.free = source_free;
200 s->parent.process_msg = pa_source_process_msg;
203 s->state = PA_SOURCE_INIT;
205 s->suspend_cause = 0;
206 s->name = pa_xstrdup(name);
207 s->proplist = pa_proplist_copy(data->proplist);
208 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
209 s->module = data->module;
210 s->card = data->card;
212 s->sample_spec = data->sample_spec;
213 s->channel_map = data->channel_map;
215 s->outputs = pa_idxset_new(NULL, NULL);
217 s->monitor_of = NULL;
219 s->virtual_volume = data->volume;
220 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
221 s->base_volume = PA_VOLUME_NORM;
222 s->n_volume_steps = PA_VOLUME_NORM+1;
223 s->muted = data->muted;
224 s->refresh_volume = s->refresh_muted = FALSE;
226 s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
234 /* As a minor optimization we just steal the list instead of
236 s->ports = data->ports;
239 s->active_port = NULL;
240 s->save_port = FALSE;
242 if (data->active_port && s->ports)
243 if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
244 s->save_port = data->save_port;
246 if (!s->active_port && s->ports) {
250 PA_HASHMAP_FOREACH(p, s->ports, state)
251 if (!s->active_port || p->priority > s->active_port->priority)
255 s->save_volume = data->save_volume;
256 s->save_muted = data->save_muted;
258 pa_silence_memchunk_get(
259 &core->silence_cache,
265 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
266 s->thread_info.soft_volume = s->soft_volume;
267 s->thread_info.soft_muted = s->muted;
268 s->thread_info.state = s->state;
269 s->thread_info.max_rewind = 0;
270 s->thread_info.requested_latency_valid = FALSE;
271 s->thread_info.requested_latency = 0;
272 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
273 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
275 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
278 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
280 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
281 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
284 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
285 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
292 /* Called from main context */
293 static int source_set_state(pa_source *s, pa_source_state_t state) {
295 pa_bool_t suspend_change;
296 pa_source_state_t original_state;
300 if (s->state == state)
303 original_state = s->state;
306 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
307 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
310 if ((ret = s->set_state(s, state)) < 0)
314 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
317 s->set_state(s, original_state);
324 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
325 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
326 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
329 if (suspend_change) {
333 /* We're suspending or resuming, tell everyone about it */
335 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
336 if (s->state == PA_SOURCE_SUSPENDED &&
337 (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
338 pa_source_output_kill(o);
340 o->suspend(o, state == PA_SOURCE_SUSPENDED);
347 /* Called from main context */
348 void pa_source_put(pa_source *s) {
349 pa_source_assert_ref(s);
351 pa_assert(s->state == PA_SOURCE_INIT);
353 /* The following fields must be initialized properly when calling _put() */
354 pa_assert(s->asyncmsgq);
355 pa_assert(s->rtpoll);
356 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
358 /* Generally, flags should be initialized via pa_source_new(). As
359 * a special exception we allow volume related flags to be set
360 * between _new() and _put(). */
362 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL))
363 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
365 s->thread_info.soft_volume = s->soft_volume;
366 s->thread_info.soft_muted = s->muted;
368 pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME));
369 pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
370 pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
372 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
374 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
375 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
378 /* Called from main context */
379 void pa_source_unlink(pa_source *s) {
381 pa_source_output *o, *j = NULL;
385 /* See pa_sink_unlink() for a couple of comments how this function
388 linked = PA_SOURCE_IS_LINKED(s->state);
391 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
393 if (s->state != PA_SOURCE_UNLINKED)
394 pa_namereg_unregister(s->core, s->name);
395 pa_idxset_remove_by_data(s->core->sources, s, NULL);
398 pa_idxset_remove_by_data(s->card->sources, s, NULL);
400 while ((o = pa_idxset_first(s->outputs, NULL))) {
402 pa_source_output_kill(o);
407 source_set_state(s, PA_SOURCE_UNLINKED);
409 s->state = PA_SOURCE_UNLINKED;
414 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
415 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
419 /* Called from main context */
420 static void source_free(pa_object *o) {
421 pa_source_output *so;
422 pa_source *s = PA_SOURCE(o);
425 pa_assert(pa_source_refcnt(s) == 0);
427 if (PA_SOURCE_IS_LINKED(s->state))
430 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
432 pa_idxset_free(s->outputs, NULL, NULL);
434 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
435 pa_source_output_unref(so);
437 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
439 if (s->silence.memblock)
440 pa_memblock_unref(s->silence.memblock);
446 pa_proplist_free(s->proplist);
451 while ((p = pa_hashmap_steal_first(s->ports)))
452 pa_device_port_free(p);
454 pa_hashmap_free(s->ports, NULL, NULL);
460 /* Called from main context */
461 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
462 pa_source_assert_ref(s);
467 /* Called from main context */
468 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
469 pa_source_assert_ref(s);
474 /* Called from main context */
475 int pa_source_update_status(pa_source*s) {
476 pa_source_assert_ref(s);
477 pa_assert(PA_SOURCE_IS_LINKED(s->state));
479 if (s->state == PA_SOURCE_SUSPENDED)
482 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
485 /* Called from main context */
486 int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
487 pa_source_assert_ref(s);
488 pa_assert(PA_SOURCE_IS_LINKED(s->state));
489 pa_assert(cause != 0);
492 return -PA_ERR_NOTSUPPORTED;
495 s->suspend_cause |= cause;
497 s->suspend_cause &= ~cause;
499 if ((pa_source_get_state(s) == PA_SOURCE_SUSPENDED) == !!s->suspend_cause)
502 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
505 return source_set_state(s, PA_SOURCE_SUSPENDED);
507 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
510 /* Called from main context */
511 int pa_source_sync_suspend(pa_source *s) {
512 pa_sink_state_t state;
514 pa_source_assert_ref(s);
515 pa_assert(PA_SOURCE_IS_LINKED(s->state));
516 pa_assert(s->monitor_of);
518 state = pa_sink_get_state(s->monitor_of);
520 if (state == PA_SINK_SUSPENDED)
521 return source_set_state(s, PA_SOURCE_SUSPENDED);
523 pa_assert(PA_SINK_IS_OPENED(state));
525 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
528 /* Called from main context */
529 pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q) {
530 pa_source_output *o, *n;
533 pa_source_assert_ref(s);
534 pa_assert(PA_SOURCE_IS_LINKED(s->state));
539 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
540 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
542 pa_source_output_ref(o);
544 if (pa_source_output_start_move(o) >= 0)
547 pa_source_output_unref(o);
553 /* Called from main context */
554 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
557 pa_source_assert_ref(s);
558 pa_assert(PA_SOURCE_IS_LINKED(s->state));
561 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
562 if (pa_source_output_finish_move(o, s, save) < 0)
563 pa_source_output_kill(o);
565 pa_source_output_unref(o);
568 pa_queue_free(q, NULL, NULL);
571 /* Called from main context */
572 void pa_source_move_all_fail(pa_queue *q) {
576 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
577 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
578 pa_source_output_kill(o);
579 pa_source_output_unref(o);
583 pa_queue_free(q, NULL, NULL);
586 /* Called from IO thread context */
587 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
591 pa_source_assert_ref(s);
592 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
594 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
600 pa_log_debug("Processing rewind...");
602 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
603 pa_source_output_assert_ref(o);
604 pa_source_output_process_rewind(o, nbytes);
608 /* Called from IO thread context */
609 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
613 pa_source_assert_ref(s);
614 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
617 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
620 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
621 pa_memchunk vchunk = *chunk;
623 pa_memblock_ref(vchunk.memblock);
624 pa_memchunk_make_writable(&vchunk, 0);
626 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
627 pa_silence_memchunk(&vchunk, &s->sample_spec);
629 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
631 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
632 pa_source_output_assert_ref(o);
634 if (!o->thread_info.direct_on_input)
635 pa_source_output_push(o, &vchunk);
638 pa_memblock_unref(vchunk.memblock);
641 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
642 pa_source_output_assert_ref(o);
644 if (!o->thread_info.direct_on_input)
645 pa_source_output_push(o, chunk);
650 /* Called from IO thread context */
651 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
652 pa_source_assert_ref(s);
653 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
654 pa_source_output_assert_ref(o);
655 pa_assert(o->thread_info.direct_on_input);
658 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
661 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
662 pa_memchunk vchunk = *chunk;
664 pa_memblock_ref(vchunk.memblock);
665 pa_memchunk_make_writable(&vchunk, 0);
667 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
668 pa_silence_memchunk(&vchunk, &s->sample_spec);
670 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
672 pa_source_output_push(o, &vchunk);
674 pa_memblock_unref(vchunk.memblock);
676 pa_source_output_push(o, chunk);
679 /* Called from main thread */
680 pa_usec_t pa_source_get_latency(pa_source *s) {
683 pa_source_assert_ref(s);
684 pa_assert(PA_SOURCE_IS_LINKED(s->state));
686 if (s->state == PA_SOURCE_SUSPENDED)
689 if (!(s->flags & PA_SOURCE_LATENCY))
692 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
697 /* Called from IO thread */
698 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
702 pa_source_assert_ref(s);
703 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
705 /* The returned value is supposed to be in the time domain of the sound card! */
707 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
710 if (!(s->flags & PA_SOURCE_LATENCY))
715 /* We probably should make this a proper vtable callback instead of going through process_msg() */
717 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
723 /* Called from main thread */
724 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save) {
725 pa_cvolume old_virtual_volume;
726 pa_bool_t virtual_volume_changed;
728 pa_source_assert_ref(s);
729 pa_assert(PA_SOURCE_IS_LINKED(s->state));
731 pa_assert(pa_cvolume_valid(volume));
732 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
734 old_virtual_volume = s->virtual_volume;
735 s->virtual_volume = *volume;
736 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
737 s->save_volume = (!virtual_volume_changed && s->save_volume) || save;
740 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
743 s->soft_volume = s->virtual_volume;
745 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
747 if (virtual_volume_changed)
748 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
751 /* Called from main thread. Only to be called by source implementor */
752 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
753 pa_source_assert_ref(s);
756 if (PA_SOURCE_IS_LINKED(s->state))
757 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
759 s->thread_info.soft_volume = *volume;
762 /* Called from main thread */
763 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
764 pa_source_assert_ref(s);
765 pa_assert(PA_SOURCE_IS_LINKED(s->state));
767 if (s->refresh_volume || force_refresh) {
768 pa_cvolume old_virtual_volume = s->virtual_volume;
773 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
775 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
776 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
779 return &s->virtual_volume;
782 /* Called from main thread */
783 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save) {
784 pa_source_assert_ref(s);
786 /* The source implementor may call this if the volume changed to make sure everyone is notified */
788 if (pa_cvolume_equal(&s->virtual_volume, new_volume)) {
789 s->save_volume = s->save_volume || save;
793 s->virtual_volume = *new_volume;
794 s->save_volume = save;
796 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
799 /* Called from main thread */
800 void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
803 pa_source_assert_ref(s);
804 pa_assert(PA_SOURCE_IS_LINKED(s->state));
806 old_muted = s->muted;
808 s->save_muted = (old_muted == s->muted && s->save_muted) || save;
813 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
815 if (old_muted != s->muted)
816 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
819 /* Called from main thread */
820 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
821 pa_source_assert_ref(s);
822 pa_assert(PA_SOURCE_IS_LINKED(s->state));
824 if (s->refresh_muted || force_refresh) {
825 pa_bool_t old_muted = s->muted;
830 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
832 if (old_muted != s->muted) {
833 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
835 /* Make sure the soft mute status stays in sync */
836 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
843 /* Called from main thread */
844 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save) {
845 pa_source_assert_ref(s);
847 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
849 if (s->muted == new_muted) {
850 s->save_muted = s->save_muted || save;
854 s->muted = new_muted;
855 s->save_muted = save;
857 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
860 /* Called from main thread */
861 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
862 pa_source_assert_ref(s);
865 pa_proplist_update(s->proplist, mode, p);
867 if (PA_SOURCE_IS_LINKED(s->state)) {
868 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
869 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
875 /* Called from main thread */
876 void pa_source_set_description(pa_source *s, const char *description) {
878 pa_source_assert_ref(s);
880 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
883 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
885 if (old && description && !strcmp(old, description))
889 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
891 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
893 if (PA_SOURCE_IS_LINKED(s->state)) {
894 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
895 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
899 /* Called from main thread */
900 unsigned pa_source_linked_by(pa_source *s) {
901 pa_source_assert_ref(s);
902 pa_assert(PA_SOURCE_IS_LINKED(s->state));
904 return pa_idxset_size(s->outputs);
907 /* Called from main thread */
908 unsigned pa_source_used_by(pa_source *s) {
911 pa_source_assert_ref(s);
912 pa_assert(PA_SOURCE_IS_LINKED(s->state));
914 ret = pa_idxset_size(s->outputs);
915 pa_assert(ret >= s->n_corked);
917 return ret - s->n_corked;
920 /* Called from main thread */
921 unsigned pa_source_check_suspend(pa_source *s) {
926 pa_source_assert_ref(s);
928 if (!PA_SOURCE_IS_LINKED(s->state))
933 PA_IDXSET_FOREACH(o, s->outputs, idx) {
934 pa_source_output_state_t st;
936 st = pa_source_output_get_state(o);
937 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
939 if (st == PA_SOURCE_OUTPUT_CORKED)
942 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
951 /* Called from IO thread, except when it is not */
952 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
953 pa_source *s = PA_SOURCE(object);
954 pa_source_assert_ref(s);
956 switch ((pa_source_message_t) code) {
958 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
959 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
961 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
963 if (o->direct_on_input) {
964 o->thread_info.direct_on_input = o->direct_on_input;
965 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
968 pa_assert(!o->thread_info.attached);
969 o->thread_info.attached = TRUE;
974 pa_source_output_set_state_within_thread(o, o->state);
976 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
977 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
979 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
981 /* We don't just invalidate the requested latency here,
982 * because if we are in a move we might need to fix up the
983 * requested latency. */
984 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
989 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
990 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
992 pa_source_output_set_state_within_thread(o, o->state);
997 pa_assert(o->thread_info.attached);
998 o->thread_info.attached = FALSE;
1000 if (o->thread_info.direct_on_input) {
1001 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
1002 o->thread_info.direct_on_input = NULL;
1005 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
1006 pa_source_output_unref(o);
1008 pa_source_invalidate_requested_latency(s);
1013 case PA_SOURCE_MESSAGE_SET_VOLUME:
1014 s->thread_info.soft_volume = s->soft_volume;
1017 case PA_SOURCE_MESSAGE_GET_VOLUME:
1020 case PA_SOURCE_MESSAGE_SET_MUTE:
1021 s->thread_info.soft_muted = s->muted;
1024 case PA_SOURCE_MESSAGE_GET_MUTE:
1027 case PA_SOURCE_MESSAGE_SET_STATE: {
1029 pa_bool_t suspend_change =
1030 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
1031 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
1033 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1035 if (suspend_change) {
1036 pa_source_output *o;
1039 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1040 if (o->suspend_within_thread)
1041 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
1048 case PA_SOURCE_MESSAGE_DETACH:
1050 /* Detach all streams */
1051 pa_source_detach_within_thread(s);
1054 case PA_SOURCE_MESSAGE_ATTACH:
1056 /* Reattach all streams */
1057 pa_source_attach_within_thread(s);
1060 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
1062 pa_usec_t *usec = userdata;
1063 *usec = pa_source_get_requested_latency_within_thread(s);
1065 if (*usec == (pa_usec_t) -1)
1066 *usec = s->thread_info.max_latency;
1071 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
1072 pa_usec_t *r = userdata;
1074 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
1079 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
1080 pa_usec_t *r = userdata;
1082 r[0] = s->thread_info.min_latency;
1083 r[1] = s->thread_info.max_latency;
1088 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1090 *((size_t*) userdata) = s->thread_info.max_rewind;
1093 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1095 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1098 case PA_SOURCE_MESSAGE_GET_LATENCY:
1100 if (s->monitor_of) {
1101 *((pa_usec_t*) userdata) = 0;
1105 /* Implementors need to overwrite this implementation! */
1108 case PA_SOURCE_MESSAGE_MAX:
1115 /* Called from main thread */
1116 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
1121 pa_core_assert_ref(c);
1122 pa_assert(cause != 0);
1124 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1127 if (source->monitor_of)
1130 if ((r = pa_source_suspend(source, suspend, cause)) < 0)
1137 /* Called from main thread */
1138 void pa_source_detach(pa_source *s) {
1139 pa_source_assert_ref(s);
1140 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1142 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1145 /* Called from main thread */
1146 void pa_source_attach(pa_source *s) {
1147 pa_source_assert_ref(s);
1148 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1150 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1153 /* Called from IO thread */
1154 void pa_source_detach_within_thread(pa_source *s) {
1155 pa_source_output *o;
1158 pa_source_assert_ref(s);
1159 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1161 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1166 /* Called from IO thread */
1167 void pa_source_attach_within_thread(pa_source *s) {
1168 pa_source_output *o;
1171 pa_source_assert_ref(s);
1172 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1174 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1179 /* Called from IO thread */
1180 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1181 pa_usec_t result = (pa_usec_t) -1;
1182 pa_source_output *o;
1185 pa_source_assert_ref(s);
1187 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1188 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1190 if (s->thread_info.requested_latency_valid)
1191 return s->thread_info.requested_latency;
1193 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1195 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1196 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1197 result = o->thread_info.requested_source_latency;
1199 if (result != (pa_usec_t) -1)
1200 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1202 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1203 /* Only cache this if we are fully set up */
1204 s->thread_info.requested_latency = result;
1205 s->thread_info.requested_latency_valid = TRUE;
1211 /* Called from main thread */
1212 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1215 pa_source_assert_ref(s);
1216 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1218 if (s->state == PA_SOURCE_SUSPENDED)
1221 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1226 /* Called from IO thread */
1227 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1228 pa_source_output *o;
1231 pa_source_assert_ref(s);
1233 if (max_rewind == s->thread_info.max_rewind)
1236 s->thread_info.max_rewind = max_rewind;
1238 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1239 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1240 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1244 /* Called from main thread */
1245 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1246 pa_source_assert_ref(s);
1248 if (PA_SOURCE_IS_LINKED(s->state))
1249 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1251 pa_source_set_max_rewind_within_thread(s, max_rewind);
1254 /* Called from IO thread */
1255 void pa_source_invalidate_requested_latency(pa_source *s) {
1256 pa_source_output *o;
1259 pa_source_assert_ref(s);
1261 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1264 s->thread_info.requested_latency_valid = FALSE;
1266 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1268 if (s->update_requested_latency)
1269 s->update_requested_latency(s);
1271 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1272 if (o->update_source_requested_latency)
1273 o->update_source_requested_latency(o);
1277 pa_sink_invalidate_requested_latency(s->monitor_of);
1280 /* Called from main thread */
1281 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1282 pa_source_assert_ref(s);
1284 /* min_latency == 0: no limit
1285 * min_latency anything else: specified limit
1287 * Similar for max_latency */
1289 if (min_latency < ABSOLUTE_MIN_LATENCY)
1290 min_latency = ABSOLUTE_MIN_LATENCY;
1292 if (max_latency <= 0 ||
1293 max_latency > ABSOLUTE_MAX_LATENCY)
1294 max_latency = ABSOLUTE_MAX_LATENCY;
1296 pa_assert(min_latency <= max_latency);
1298 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1299 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1300 max_latency == ABSOLUTE_MAX_LATENCY) ||
1301 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1303 if (PA_SOURCE_IS_LINKED(s->state)) {
1309 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1311 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1314 /* Called from main thread */
1315 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1316 pa_source_assert_ref(s);
1317 pa_assert(min_latency);
1318 pa_assert(max_latency);
1320 if (PA_SOURCE_IS_LINKED(s->state)) {
1321 pa_usec_t r[2] = { 0, 0 };
1323 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1325 *min_latency = r[0];
1326 *max_latency = r[1];
1328 *min_latency = s->thread_info.min_latency;
1329 *max_latency = s->thread_info.max_latency;
1333 /* Called from IO thread, and from main thread before pa_source_put() is called */
1334 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1337 pa_source_assert_ref(s);
1339 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1340 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1341 pa_assert(min_latency <= max_latency);
1343 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1344 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1345 max_latency == ABSOLUTE_MAX_LATENCY) ||
1346 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1349 s->thread_info.min_latency = min_latency;
1350 s->thread_info.max_latency = max_latency;
1352 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1353 pa_source_output *o;
1355 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1356 if (o->update_source_latency_range)
1357 o->update_source_latency_range(o);
1360 pa_source_invalidate_requested_latency(s);
1363 /* Called from main thread, before the source is put */
1364 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1365 pa_source_assert_ref(s);
1367 pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1369 if (latency < ABSOLUTE_MIN_LATENCY)
1370 latency = ABSOLUTE_MIN_LATENCY;
1372 if (latency > ABSOLUTE_MAX_LATENCY)
1373 latency = ABSOLUTE_MAX_LATENCY;
1375 s->fixed_latency = latency;
1378 /* Called from main thread */
1379 size_t pa_source_get_max_rewind(pa_source *s) {
1381 pa_source_assert_ref(s);
1383 if (!PA_SOURCE_IS_LINKED(s->state))
1384 return s->thread_info.max_rewind;
1386 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1391 /* Called from main context */
1392 int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
1393 pa_device_port *port;
1398 pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
1399 return -PA_ERR_NOTIMPLEMENTED;
1403 return -PA_ERR_NOENTITY;
1405 if (!(port = pa_hashmap_get(s->ports, name)))
1406 return -PA_ERR_NOENTITY;
1408 if (s->active_port == port) {
1409 s->save_port = s->save_port || save;
1413 if ((s->set_port(s, port)) < 0)
1414 return -PA_ERR_NOENTITY;
1416 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1418 pa_log_info("Changed port of source %u \"%s\" to %s", s->index, s->name, port->name);
1420 s->active_port = port;
1421 s->save_port = save;