2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
36 #include <pulsecore/source-output.h>
37 #include <pulsecore/namereg.h>
38 #include <pulsecore/core-subscribe.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/sample-util.h>
44 #define ABSOLUTE_MIN_LATENCY (500)
45 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
46 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
48 static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
50 static void source_free(pa_object *o);
52 pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
55 memset(data, 0, sizeof(*data));
56 data->proplist = pa_proplist_new();
61 void pa_source_new_data_set_name(pa_source_new_data *data, const char *name) {
65 data->name = pa_xstrdup(name);
68 void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sample_spec *spec) {
71 if ((data->sample_spec_is_set = !!spec))
72 data->sample_spec = *spec;
75 void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_channel_map *map) {
78 if ((data->channel_map_is_set = !!map))
79 data->channel_map = *map;
82 void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume) {
85 if ((data->volume_is_set = !!volume))
86 data->volume = *volume;
89 void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute) {
92 data->muted_is_set = TRUE;
96 void pa_source_new_data_done(pa_source_new_data *data) {
100 pa_proplist_free(data->proplist);
103 /* Called from main context */
104 static void reset_callbacks(pa_source *s) {
108 s->get_volume = NULL;
109 s->set_volume = NULL;
112 s->update_requested_latency = NULL;
115 /* Called from main context */
116 pa_source* pa_source_new(
118 pa_source_new_data *data,
119 pa_source_flags_t flags) {
123 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
128 pa_assert(data->name);
130 s = pa_msgobject_new(pa_source);
132 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
137 pa_source_new_data_set_name(data, name);
139 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
141 pa_namereg_unregister(core, name);
145 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
146 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
148 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
150 if (!data->channel_map_is_set)
151 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
153 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
154 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
156 if (!data->volume_is_set)
157 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
159 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
160 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
162 if (!data->muted_is_set)
166 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
168 pa_device_init_description(data->proplist);
169 pa_device_init_icon(data->proplist, FALSE);
170 pa_device_init_intended_roles(data->proplist);
172 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
174 pa_namereg_unregister(core, name);
178 s->parent.parent.free = source_free;
179 s->parent.process_msg = pa_source_process_msg;
182 s->state = PA_SOURCE_INIT;
184 s->suspend_cause = 0;
185 s->name = pa_xstrdup(name);
186 s->proplist = pa_proplist_copy(data->proplist);
187 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
188 s->module = data->module;
189 s->card = data->card;
191 s->sample_spec = data->sample_spec;
192 s->channel_map = data->channel_map;
194 s->outputs = pa_idxset_new(NULL, NULL);
196 s->monitor_of = NULL;
198 s->virtual_volume = data->volume;
199 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
200 s->base_volume = PA_VOLUME_NORM;
201 s->n_volume_steps = PA_VOLUME_NORM+1;
202 s->muted = data->muted;
203 s->refresh_volume = s->refresh_muted = FALSE;
205 s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
213 pa_silence_memchunk_get(
214 &core->silence_cache,
220 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
221 s->thread_info.soft_volume = s->soft_volume;
222 s->thread_info.soft_muted = s->muted;
223 s->thread_info.state = s->state;
224 s->thread_info.max_rewind = 0;
225 s->thread_info.requested_latency_valid = FALSE;
226 s->thread_info.requested_latency = 0;
227 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
228 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
230 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
233 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
235 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
236 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
239 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
240 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
247 /* Called from main context */
248 static int source_set_state(pa_source *s, pa_source_state_t state) {
250 pa_bool_t suspend_change;
251 pa_source_state_t original_state;
255 if (s->state == state)
258 original_state = s->state;
261 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
262 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
265 if ((ret = s->set_state(s, state)) < 0)
269 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
272 s->set_state(s, original_state);
279 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
280 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
281 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
284 if (suspend_change) {
288 /* We're suspending or resuming, tell everyone about it */
290 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
291 if (s->state == PA_SOURCE_SUSPENDED &&
292 (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
293 pa_source_output_kill(o);
295 o->suspend(o, state == PA_SOURCE_SUSPENDED);
302 /* Called from main context */
303 void pa_source_put(pa_source *s) {
304 pa_source_assert_ref(s);
306 pa_assert(s->state == PA_SOURCE_INIT);
308 /* The following fields must be initialized properly when calling _put() */
309 pa_assert(s->asyncmsgq);
310 pa_assert(s->rtpoll);
311 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
313 /* Generally, flags should be initialized via pa_source_new(). As
314 * a special exception we allow volume related flags to be set
315 * between _new() and _put(). */
317 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL))
318 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
320 s->thread_info.soft_volume = s->soft_volume;
321 s->thread_info.soft_muted = s->muted;
323 pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME));
324 pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
325 pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
327 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
329 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
330 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
333 /* Called from main context */
334 void pa_source_unlink(pa_source *s) {
336 pa_source_output *o, *j = NULL;
340 /* See pa_sink_unlink() for a couple of comments how this function
343 linked = PA_SOURCE_IS_LINKED(s->state);
346 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
348 if (s->state != PA_SOURCE_UNLINKED)
349 pa_namereg_unregister(s->core, s->name);
350 pa_idxset_remove_by_data(s->core->sources, s, NULL);
353 pa_idxset_remove_by_data(s->card->sources, s, NULL);
355 while ((o = pa_idxset_first(s->outputs, NULL))) {
357 pa_source_output_kill(o);
362 source_set_state(s, PA_SOURCE_UNLINKED);
364 s->state = PA_SOURCE_UNLINKED;
369 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
370 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
374 /* Called from main context */
375 static void source_free(pa_object *o) {
376 pa_source_output *so;
377 pa_source *s = PA_SOURCE(o);
380 pa_assert(pa_source_refcnt(s) == 0);
382 if (PA_SOURCE_IS_LINKED(s->state))
385 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
387 pa_idxset_free(s->outputs, NULL, NULL);
389 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
390 pa_source_output_unref(so);
392 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
394 if (s->silence.memblock)
395 pa_memblock_unref(s->silence.memblock);
401 pa_proplist_free(s->proplist);
406 /* Called from main context */
407 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
408 pa_source_assert_ref(s);
413 /* Called from main context */
414 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
415 pa_source_assert_ref(s);
420 /* Called from main context */
421 int pa_source_update_status(pa_source*s) {
422 pa_source_assert_ref(s);
423 pa_assert(PA_SOURCE_IS_LINKED(s->state));
425 if (s->state == PA_SOURCE_SUSPENDED)
428 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
431 /* Called from main context */
432 int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
433 pa_source_assert_ref(s);
434 pa_assert(PA_SOURCE_IS_LINKED(s->state));
435 pa_assert(cause != 0);
438 return -PA_ERR_NOTSUPPORTED;
441 s->suspend_cause |= cause;
443 s->suspend_cause &= ~cause;
445 if ((pa_source_get_state(s) == PA_SOURCE_SUSPENDED) == !!s->suspend_cause)
448 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
451 return source_set_state(s, PA_SOURCE_SUSPENDED);
453 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
456 /* Called from main context */
457 int pa_source_sync_suspend(pa_source *s) {
458 pa_sink_state_t state;
460 pa_source_assert_ref(s);
461 pa_assert(PA_SOURCE_IS_LINKED(s->state));
462 pa_assert(s->monitor_of);
464 state = pa_sink_get_state(s->monitor_of);
466 if (state == PA_SINK_SUSPENDED)
467 return source_set_state(s, PA_SOURCE_SUSPENDED);
469 pa_assert(PA_SINK_IS_OPENED(state));
471 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
474 /* Called from main context */
475 pa_queue *pa_source_move_all_start(pa_source *s) {
477 pa_source_output *o, *n;
480 pa_source_assert_ref(s);
481 pa_assert(PA_SOURCE_IS_LINKED(s->state));
485 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
486 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
488 pa_source_output_ref(o);
490 if (pa_source_output_start_move(o) >= 0)
493 pa_source_output_unref(o);
499 /* Called from main context */
500 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
503 pa_source_assert_ref(s);
504 pa_assert(PA_SOURCE_IS_LINKED(s->state));
507 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
508 if (pa_source_output_finish_move(o, s, save) < 0)
509 pa_source_output_kill(o);
511 pa_source_output_unref(o);
514 pa_queue_free(q, NULL, NULL);
517 /* Called from main context */
518 void pa_source_move_all_fail(pa_queue *q) {
522 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
523 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
524 pa_source_output_kill(o);
525 pa_source_output_unref(o);
529 pa_queue_free(q, NULL, NULL);
532 /* Called from IO thread context */
533 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
537 pa_source_assert_ref(s);
538 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
540 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
546 pa_log_debug("Processing rewind...");
548 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
549 pa_source_output_assert_ref(o);
550 pa_source_output_process_rewind(o, nbytes);
554 /* Called from IO thread context */
555 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
559 pa_source_assert_ref(s);
560 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
563 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
566 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
567 pa_memchunk vchunk = *chunk;
569 pa_memblock_ref(vchunk.memblock);
570 pa_memchunk_make_writable(&vchunk, 0);
572 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
573 pa_silence_memchunk(&vchunk, &s->sample_spec);
575 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
577 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
578 pa_source_output_assert_ref(o);
580 if (!o->thread_info.direct_on_input)
581 pa_source_output_push(o, &vchunk);
584 pa_memblock_unref(vchunk.memblock);
587 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
588 pa_source_output_assert_ref(o);
590 if (!o->thread_info.direct_on_input)
591 pa_source_output_push(o, chunk);
596 /* Called from IO thread context */
597 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
598 pa_source_assert_ref(s);
599 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
600 pa_source_output_assert_ref(o);
601 pa_assert(o->thread_info.direct_on_input);
604 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
607 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
608 pa_memchunk vchunk = *chunk;
610 pa_memblock_ref(vchunk.memblock);
611 pa_memchunk_make_writable(&vchunk, 0);
613 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
614 pa_silence_memchunk(&vchunk, &s->sample_spec);
616 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
618 pa_source_output_push(o, &vchunk);
620 pa_memblock_unref(vchunk.memblock);
622 pa_source_output_push(o, chunk);
625 /* Called from main thread */
626 pa_usec_t pa_source_get_latency(pa_source *s) {
629 pa_source_assert_ref(s);
630 pa_assert(PA_SOURCE_IS_LINKED(s->state));
632 if (s->state == PA_SOURCE_SUSPENDED)
635 if (!(s->flags & PA_SOURCE_LATENCY))
638 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
643 /* Called from IO thread */
644 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
648 pa_source_assert_ref(s);
649 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
651 /* The returned value is supposed to be in the time domain of the sound card! */
653 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
656 if (!(s->flags & PA_SOURCE_LATENCY))
661 /* We probably should make this a proper vtable callback instead of going through process_msg() */
663 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
669 /* Called from main thread */
670 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
671 pa_cvolume old_virtual_volume;
672 pa_bool_t virtual_volume_changed;
674 pa_source_assert_ref(s);
675 pa_assert(PA_SOURCE_IS_LINKED(s->state));
677 pa_assert(pa_cvolume_valid(volume));
678 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
680 old_virtual_volume = s->virtual_volume;
681 s->virtual_volume = *volume;
682 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
685 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
688 s->soft_volume = s->virtual_volume;
690 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
692 if (virtual_volume_changed)
693 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
696 /* Called from main thread. Only to be called by source implementor */
697 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
698 pa_source_assert_ref(s);
701 if (PA_SOURCE_IS_LINKED(s->state))
702 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
704 s->thread_info.soft_volume = *volume;
707 /* Called from main thread */
708 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
709 pa_source_assert_ref(s);
710 pa_assert(PA_SOURCE_IS_LINKED(s->state));
712 if (s->refresh_volume || force_refresh) {
713 pa_cvolume old_virtual_volume = s->virtual_volume;
718 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
720 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
721 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
724 return &s->virtual_volume;
727 /* Called from main thread */
728 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
729 pa_source_assert_ref(s);
731 /* The source implementor may call this if the volume changed to make sure everyone is notified */
733 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
736 s->virtual_volume = *new_volume;
737 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
740 /* Called from main thread */
741 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
744 pa_source_assert_ref(s);
745 pa_assert(PA_SOURCE_IS_LINKED(s->state));
747 old_muted = s->muted;
753 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
755 if (old_muted != s->muted)
756 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
759 /* Called from main thread */
760 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
761 pa_source_assert_ref(s);
762 pa_assert(PA_SOURCE_IS_LINKED(s->state));
764 if (s->refresh_muted || force_refresh) {
765 pa_bool_t old_muted = s->muted;
770 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
772 if (old_muted != s->muted) {
773 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
775 /* Make sure the soft mute status stays in sync */
776 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
783 /* Called from main thread */
784 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
785 pa_source_assert_ref(s);
787 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
789 if (s->muted == new_muted)
792 s->muted = new_muted;
793 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
796 /* Called from main thread */
797 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
798 pa_source_assert_ref(s);
801 pa_proplist_update(s->proplist, mode, p);
803 if (PA_SOURCE_IS_LINKED(s->state)) {
804 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
805 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
811 /* Called from main thread */
812 void pa_source_set_description(pa_source *s, const char *description) {
814 pa_source_assert_ref(s);
816 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
819 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
821 if (old && description && !strcmp(old, description))
825 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
827 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
829 if (PA_SOURCE_IS_LINKED(s->state)) {
830 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
831 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
835 /* Called from main thread */
836 unsigned pa_source_linked_by(pa_source *s) {
837 pa_source_assert_ref(s);
838 pa_assert(PA_SOURCE_IS_LINKED(s->state));
840 return pa_idxset_size(s->outputs);
843 /* Called from main thread */
844 unsigned pa_source_used_by(pa_source *s) {
847 pa_source_assert_ref(s);
848 pa_assert(PA_SOURCE_IS_LINKED(s->state));
850 ret = pa_idxset_size(s->outputs);
851 pa_assert(ret >= s->n_corked);
853 return ret - s->n_corked;
856 /* Called from main thread */
857 unsigned pa_source_check_suspend(pa_source *s) {
862 pa_source_assert_ref(s);
864 if (!PA_SOURCE_IS_LINKED(s->state))
869 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
870 pa_source_output_state_t st;
872 st = pa_source_output_get_state(o);
873 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
875 if (st == PA_SOURCE_OUTPUT_CORKED)
878 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
887 /* Called from IO thread, except when it is not */
888 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
889 pa_source *s = PA_SOURCE(object);
890 pa_source_assert_ref(s);
892 switch ((pa_source_message_t) code) {
894 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
895 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
897 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
899 if (o->direct_on_input) {
900 o->thread_info.direct_on_input = o->direct_on_input;
901 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
904 pa_assert(!o->thread_info.attached);
905 o->thread_info.attached = TRUE;
910 pa_source_output_set_state_within_thread(o, o->state);
912 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
913 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
915 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
917 /* We don't just invalidate the requested latency here,
918 * because if we are in a move we might need to fix up the
919 * requested latency. */
920 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
925 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
926 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
928 pa_source_output_set_state_within_thread(o, o->state);
933 pa_assert(o->thread_info.attached);
934 o->thread_info.attached = FALSE;
936 if (o->thread_info.direct_on_input) {
937 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
938 o->thread_info.direct_on_input = NULL;
941 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
942 pa_source_output_unref(o);
944 pa_source_invalidate_requested_latency(s);
949 case PA_SOURCE_MESSAGE_SET_VOLUME:
950 s->thread_info.soft_volume = s->soft_volume;
953 case PA_SOURCE_MESSAGE_GET_VOLUME:
956 case PA_SOURCE_MESSAGE_SET_MUTE:
957 s->thread_info.soft_muted = s->muted;
960 case PA_SOURCE_MESSAGE_GET_MUTE:
963 case PA_SOURCE_MESSAGE_SET_STATE: {
965 pa_bool_t suspend_change =
966 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
967 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
969 s->thread_info.state = PA_PTR_TO_UINT(userdata);
971 if (suspend_change) {
975 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
976 if (o->suspend_within_thread)
977 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
984 case PA_SOURCE_MESSAGE_DETACH:
986 /* Detach all streams */
987 pa_source_detach_within_thread(s);
990 case PA_SOURCE_MESSAGE_ATTACH:
992 /* Reattach all streams */
993 pa_source_attach_within_thread(s);
996 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
998 pa_usec_t *usec = userdata;
999 *usec = pa_source_get_requested_latency_within_thread(s);
1001 if (*usec == (pa_usec_t) -1)
1002 *usec = s->thread_info.max_latency;
1007 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
1008 pa_usec_t *r = userdata;
1010 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
1015 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
1016 pa_usec_t *r = userdata;
1018 r[0] = s->thread_info.min_latency;
1019 r[1] = s->thread_info.max_latency;
1024 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1026 *((size_t*) userdata) = s->thread_info.max_rewind;
1029 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1031 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1034 case PA_SOURCE_MESSAGE_GET_LATENCY:
1036 if (s->monitor_of) {
1037 *((pa_usec_t*) userdata) = 0;
1041 /* Implementors need to overwrite this implementation! */
1044 case PA_SOURCE_MESSAGE_MAX:
1051 /* Called from main thread */
1052 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
1057 pa_core_assert_ref(c);
1058 pa_assert(cause != 0);
1060 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1063 if (source->monitor_of)
1066 if ((r = pa_source_suspend(source, suspend, cause)) < 0)
1073 /* Called from main thread */
1074 void pa_source_detach(pa_source *s) {
1075 pa_source_assert_ref(s);
1076 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1078 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1081 /* Called from main thread */
1082 void pa_source_attach(pa_source *s) {
1083 pa_source_assert_ref(s);
1084 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1086 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1089 /* Called from IO thread */
1090 void pa_source_detach_within_thread(pa_source *s) {
1091 pa_source_output *o;
1094 pa_source_assert_ref(s);
1095 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1097 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1102 /* Called from IO thread */
1103 void pa_source_attach_within_thread(pa_source *s) {
1104 pa_source_output *o;
1107 pa_source_assert_ref(s);
1108 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1110 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1115 /* Called from IO thread */
1116 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1117 pa_usec_t result = (pa_usec_t) -1;
1118 pa_source_output *o;
1121 pa_source_assert_ref(s);
1123 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1124 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1126 if (s->thread_info.requested_latency_valid)
1127 return s->thread_info.requested_latency;
1129 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1131 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1132 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1133 result = o->thread_info.requested_source_latency;
1135 if (result != (pa_usec_t) -1)
1136 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1138 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1139 /* Only cache this if we are fully set up */
1140 s->thread_info.requested_latency = result;
1141 s->thread_info.requested_latency_valid = TRUE;
1147 /* Called from main thread */
1148 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1151 pa_source_assert_ref(s);
1152 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1154 if (s->state == PA_SOURCE_SUSPENDED)
1157 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1162 /* Called from IO thread */
1163 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1164 pa_source_output *o;
1167 pa_source_assert_ref(s);
1169 if (max_rewind == s->thread_info.max_rewind)
1172 s->thread_info.max_rewind = max_rewind;
1174 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1175 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1176 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1180 /* Called from main thread */
1181 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1182 pa_source_assert_ref(s);
1184 if (PA_SOURCE_IS_LINKED(s->state))
1185 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1187 pa_source_set_max_rewind_within_thread(s, max_rewind);
1190 /* Called from IO thread */
1191 void pa_source_invalidate_requested_latency(pa_source *s) {
1192 pa_source_output *o;
1195 pa_source_assert_ref(s);
1197 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1200 s->thread_info.requested_latency_valid = FALSE;
1202 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1204 if (s->update_requested_latency)
1205 s->update_requested_latency(s);
1207 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1208 if (o->update_source_requested_latency)
1209 o->update_source_requested_latency(o);
1213 pa_sink_invalidate_requested_latency(s->monitor_of);
1216 /* Called from main thread */
1217 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1218 pa_source_assert_ref(s);
1220 /* min_latency == 0: no limit
1221 * min_latency anything else: specified limit
1223 * Similar for max_latency */
1225 if (min_latency < ABSOLUTE_MIN_LATENCY)
1226 min_latency = ABSOLUTE_MIN_LATENCY;
1228 if (max_latency <= 0 ||
1229 max_latency > ABSOLUTE_MAX_LATENCY)
1230 max_latency = ABSOLUTE_MAX_LATENCY;
1232 pa_assert(min_latency <= max_latency);
1234 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1235 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1236 max_latency == ABSOLUTE_MAX_LATENCY) ||
1237 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1239 if (PA_SOURCE_IS_LINKED(s->state)) {
1245 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1247 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1250 /* Called from main thread */
1251 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1252 pa_source_assert_ref(s);
1253 pa_assert(min_latency);
1254 pa_assert(max_latency);
1256 if (PA_SOURCE_IS_LINKED(s->state)) {
1257 pa_usec_t r[2] = { 0, 0 };
1259 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1261 *min_latency = r[0];
1262 *max_latency = r[1];
1264 *min_latency = s->thread_info.min_latency;
1265 *max_latency = s->thread_info.max_latency;
1269 /* Called from IO thread, and from main thread before pa_source_put() is called */
1270 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1273 pa_source_assert_ref(s);
1275 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1276 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1277 pa_assert(min_latency <= max_latency);
1279 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1280 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1281 max_latency == ABSOLUTE_MAX_LATENCY) ||
1282 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1285 s->thread_info.min_latency = min_latency;
1286 s->thread_info.max_latency = max_latency;
1288 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1289 pa_source_output *o;
1291 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1292 if (o->update_source_latency_range)
1293 o->update_source_latency_range(o);
1296 pa_source_invalidate_requested_latency(s);
1299 /* Called from main thread, before the source is put */
1300 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1301 pa_source_assert_ref(s);
1303 pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1305 if (latency < ABSOLUTE_MIN_LATENCY)
1306 latency = ABSOLUTE_MIN_LATENCY;
1308 if (latency > ABSOLUTE_MAX_LATENCY)
1309 latency = ABSOLUTE_MAX_LATENCY;
1311 s->fixed_latency = latency;
1314 /* Called from main thread */
1315 size_t pa_source_get_max_rewind(pa_source *s) {
1317 pa_source_assert_ref(s);
1319 if (!PA_SOURCE_IS_LINKED(s->state))
1320 return s->thread_info.max_rewind;
1322 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);