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 DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
46 static PA_DEFINE_CHECK_TYPE(pa_source
, pa_msgobject
);
48 static void source_free(pa_object
*o
);
50 pa_source_new_data
* pa_source_new_data_init(pa_source_new_data
*data
) {
53 memset(data
, 0, sizeof(*data
));
54 data
->proplist
= pa_proplist_new();
59 void pa_source_new_data_set_name(pa_source_new_data
*data
, const char *name
) {
63 data
->name
= pa_xstrdup(name
);
66 void pa_source_new_data_set_sample_spec(pa_source_new_data
*data
, const pa_sample_spec
*spec
) {
69 if ((data
->sample_spec_is_set
= !!spec
))
70 data
->sample_spec
= *spec
;
73 void pa_source_new_data_set_channel_map(pa_source_new_data
*data
, const pa_channel_map
*map
) {
76 if ((data
->channel_map_is_set
= !!map
))
77 data
->channel_map
= *map
;
80 void pa_source_new_data_set_volume(pa_source_new_data
*data
, const pa_cvolume
*volume
) {
83 if ((data
->volume_is_set
= !!volume
))
84 data
->volume
= *volume
;
87 void pa_source_new_data_set_muted(pa_source_new_data
*data
, pa_bool_t mute
) {
90 data
->muted_is_set
= TRUE
;
94 void pa_source_new_data_done(pa_source_new_data
*data
) {
98 pa_proplist_free(data
->proplist
);
101 /* Called from main context */
102 static void reset_callbacks(pa_source
*s
) {
106 s
->get_volume
= NULL
;
107 s
->set_volume
= NULL
;
110 s
->update_requested_latency
= NULL
;
113 /* Called from main context */
114 pa_source
* pa_source_new(
116 pa_source_new_data
*data
,
117 pa_source_flags_t flags
) {
121 char st
[PA_SAMPLE_SPEC_SNPRINT_MAX
], cm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
126 pa_assert(data
->name
);
128 s
= pa_msgobject_new(pa_source
);
130 if (!(name
= pa_namereg_register(core
, data
->name
, PA_NAMEREG_SOURCE
, s
, data
->namereg_fail
))) {
135 pa_source_new_data_set_name(data
, name
);
137 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_NEW
], data
) < 0) {
139 pa_namereg_unregister(core
, name
);
143 pa_return_null_if_fail(!data
->driver
|| pa_utf8_valid(data
->driver
));
144 pa_return_null_if_fail(data
->name
&& pa_utf8_valid(data
->name
) && data
->name
[0]);
146 pa_return_null_if_fail(data
->sample_spec_is_set
&& pa_sample_spec_valid(&data
->sample_spec
));
148 if (!data
->channel_map_is_set
)
149 pa_return_null_if_fail(pa_channel_map_init_auto(&data
->channel_map
, data
->sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
));
151 pa_return_null_if_fail(pa_channel_map_valid(&data
->channel_map
));
152 pa_return_null_if_fail(data
->channel_map
.channels
== data
->sample_spec
.channels
);
154 if (!data
->volume_is_set
)
155 pa_cvolume_reset(&data
->volume
, data
->sample_spec
.channels
);
157 pa_return_null_if_fail(pa_cvolume_valid(&data
->volume
));
158 pa_return_null_if_fail(data
->volume
.channels
== data
->sample_spec
.channels
);
160 if (!data
->muted_is_set
)
164 pa_proplist_update(data
->proplist
, PA_UPDATE_MERGE
, data
->card
->proplist
);
166 pa_device_init_description(data
->proplist
);
167 pa_device_init_icon(data
->proplist
, FALSE
);
169 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_FIXATE
], data
) < 0) {
171 pa_namereg_unregister(core
, name
);
175 s
->parent
.parent
.free
= source_free
;
176 s
->parent
.process_msg
= pa_source_process_msg
;
179 s
->state
= PA_SOURCE_INIT
;
181 s
->name
= pa_xstrdup(name
);
182 s
->proplist
= pa_proplist_copy(data
->proplist
);
183 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
184 s
->module
= data
->module
;
185 s
->card
= data
->card
;
187 s
->sample_spec
= data
->sample_spec
;
188 s
->channel_map
= data
->channel_map
;
190 s
->outputs
= pa_idxset_new(NULL
, NULL
);
192 s
->monitor_of
= NULL
;
194 s
->virtual_volume
= data
->volume
;
195 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
196 s
->base_volume
= PA_VOLUME_NORM
;
197 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
198 s
->muted
= data
->muted
;
199 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
207 pa_silence_memchunk_get(
208 &core
->silence_cache
,
214 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
215 s
->thread_info
.soft_volume
= s
->soft_volume
;
216 s
->thread_info
.soft_muted
= s
->muted
;
217 s
->thread_info
.state
= s
->state
;
218 s
->thread_info
.max_rewind
= 0;
219 s
->thread_info
.requested_latency_valid
= FALSE
;
220 s
->thread_info
.requested_latency
= 0;
221 s
->thread_info
.min_latency
= DEFAULT_MIN_LATENCY
;
222 s
->thread_info
.max_latency
= 0;
224 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
227 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
229 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
230 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
233 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
234 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
241 /* Called from main context */
242 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
244 pa_bool_t suspend_change
;
245 pa_source_state_t original_state
;
249 if (s
->state
== state
)
252 original_state
= s
->state
;
255 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
256 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
259 if ((ret
= s
->set_state(s
, state
)) < 0)
263 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
266 s
->set_state(s
, original_state
);
273 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
274 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
275 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
278 if (suspend_change
) {
282 /* We're suspending or resuming, tell everyone about it */
284 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
)))
285 if (s
->state
== PA_SOURCE_SUSPENDED
&&
286 (o
->flags
& PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND
))
287 pa_source_output_kill(o
);
289 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
296 /* Called from main context */
297 void pa_source_put(pa_source
*s
) {
298 pa_source_assert_ref(s
);
300 pa_assert(s
->state
== PA_SOURCE_INIT
);
302 /* The following fields must be initialized properly when calling _put() */
303 pa_assert(s
->asyncmsgq
);
304 pa_assert(s
->rtpoll
);
305 pa_assert(!s
->thread_info
.min_latency
|| !s
->thread_info
.max_latency
||
306 s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
308 if (!(s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
)) {
309 s
->flags
|= PA_SOURCE_DECIBEL_VOLUME
;
311 s
->thread_info
.soft_volume
= s
->soft_volume
;
312 s
->thread_info
.soft_muted
= s
->muted
;
315 if (s
->flags
& PA_SOURCE_DECIBEL_VOLUME
)
316 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
318 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
320 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
321 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
324 /* Called from main context */
325 void pa_source_unlink(pa_source
*s
) {
327 pa_source_output
*o
, *j
= NULL
;
331 /* See pa_sink_unlink() for a couple of comments how this function
334 linked
= PA_SOURCE_IS_LINKED(s
->state
);
337 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
339 if (s
->state
!= PA_SOURCE_UNLINKED
)
340 pa_namereg_unregister(s
->core
, s
->name
);
341 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
344 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
346 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
348 pa_source_output_kill(o
);
353 source_set_state(s
, PA_SOURCE_UNLINKED
);
355 s
->state
= PA_SOURCE_UNLINKED
;
360 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
361 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
365 /* Called from main context */
366 static void source_free(pa_object
*o
) {
367 pa_source_output
*so
;
368 pa_source
*s
= PA_SOURCE(o
);
371 pa_assert(pa_source_refcnt(s
) == 0);
373 if (PA_SOURCE_IS_LINKED(s
->state
))
376 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
378 pa_idxset_free(s
->outputs
, NULL
, NULL
);
380 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
381 pa_source_output_unref(so
);
383 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
385 if (s
->silence
.memblock
)
386 pa_memblock_unref(s
->silence
.memblock
);
392 pa_proplist_free(s
->proplist
);
397 /* Called from main context */
398 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
399 pa_source_assert_ref(s
);
404 /* Called from main context */
405 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
406 pa_source_assert_ref(s
);
411 /* Called from main context */
412 int pa_source_update_status(pa_source
*s
) {
413 pa_source_assert_ref(s
);
414 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
416 if (s
->state
== PA_SOURCE_SUSPENDED
)
419 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
422 /* Called from main context */
423 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
) {
424 pa_source_assert_ref(s
);
425 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
428 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
430 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
433 /* Called from main context */
434 pa_queue
*pa_source_move_all_start(pa_source
*s
) {
436 pa_source_output
*o
, *n
;
439 pa_source_assert_ref(s
);
440 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
444 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
445 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
447 if (pa_source_output_start_move(o
) >= 0)
448 pa_queue_push(q
, pa_source_output_ref(o
));
454 /* Called from main context */
455 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
458 pa_source_assert_ref(s
);
459 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
462 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
463 if (pa_source_output_finish_move(o
, s
, save
) < 0)
464 pa_source_output_kill(o
);
466 pa_source_output_unref(o
);
469 pa_queue_free(q
, NULL
, NULL
);
472 /* Called from main context */
473 void pa_source_move_all_fail(pa_queue
*q
) {
477 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
478 if (pa_hook_fire(&o
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL
], o
) == PA_HOOK_OK
) {
479 pa_source_output_kill(o
);
480 pa_source_output_unref(o
);
484 pa_queue_free(q
, NULL
, NULL
);
487 /* Called from IO thread context */
488 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
492 pa_source_assert_ref(s
);
493 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
495 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
501 pa_log_debug("Processing rewind...");
503 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
504 pa_source_output_assert_ref(o
);
505 pa_source_output_process_rewind(o
, nbytes
);
509 /* Called from IO thread context */
510 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
514 pa_source_assert_ref(s
);
515 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
518 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
521 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
522 pa_memchunk vchunk
= *chunk
;
524 pa_memblock_ref(vchunk
.memblock
);
525 pa_memchunk_make_writable(&vchunk
, 0);
527 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
528 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
530 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
532 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
533 pa_source_output_assert_ref(o
);
535 if (!o
->thread_info
.direct_on_input
)
536 pa_source_output_push(o
, &vchunk
);
539 pa_memblock_unref(vchunk
.memblock
);
542 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
543 pa_source_output_assert_ref(o
);
545 if (!o
->thread_info
.direct_on_input
)
546 pa_source_output_push(o
, chunk
);
551 /* Called from IO thread context */
552 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
553 pa_source_assert_ref(s
);
554 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
555 pa_source_output_assert_ref(o
);
556 pa_assert(o
->thread_info
.direct_on_input
);
559 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
562 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
563 pa_memchunk vchunk
= *chunk
;
565 pa_memblock_ref(vchunk
.memblock
);
566 pa_memchunk_make_writable(&vchunk
, 0);
568 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
569 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
571 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
573 pa_source_output_push(o
, &vchunk
);
575 pa_memblock_unref(vchunk
.memblock
);
577 pa_source_output_push(o
, chunk
);
580 /* Called from main thread */
581 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
584 pa_source_assert_ref(s
);
585 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
587 if (s
->state
== PA_SOURCE_SUSPENDED
)
590 if (!(s
->flags
& PA_SOURCE_LATENCY
))
593 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
598 /* Called from main thread */
599 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
) {
600 pa_cvolume old_virtual_volume
;
601 pa_bool_t virtual_volume_changed
;
603 pa_source_assert_ref(s
);
604 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
606 pa_assert(pa_cvolume_valid(volume
));
607 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
609 old_virtual_volume
= s
->virtual_volume
;
610 s
->virtual_volume
= *volume
;
611 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
614 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
617 s
->soft_volume
= s
->virtual_volume
;
619 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
621 if (virtual_volume_changed
)
622 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
625 /* Called from main thread. Only to be called by source implementor */
626 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
627 pa_source_assert_ref(s
);
630 if (PA_SOURCE_IS_LINKED(s
->state
))
631 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
633 s
->thread_info
.soft_volume
= *volume
;
636 /* Called from main thread */
637 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
638 pa_source_assert_ref(s
);
639 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
641 if (s
->refresh_volume
|| force_refresh
) {
642 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
647 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
649 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
))
650 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
653 return &s
->virtual_volume
;
656 /* Called from main thread */
657 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
) {
660 pa_source_assert_ref(s
);
661 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
663 old_muted
= s
->muted
;
669 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
671 if (old_muted
!= s
->muted
)
672 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
675 /* Called from main thread */
676 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
678 pa_source_assert_ref(s
);
679 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
681 if (s
->refresh_muted
|| force_refresh
) {
682 pa_bool_t old_muted
= s
->muted
;
687 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
689 if (old_muted
!= s
->muted
)
690 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
696 /* Called from main thread */
697 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
698 pa_source_assert_ref(s
);
701 pa_proplist_update(s
->proplist
, mode
, p
);
703 if (PA_SOURCE_IS_LINKED(s
->state
)) {
704 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
705 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
711 /* Called from main thread */
712 void pa_source_set_description(pa_source
*s
, const char *description
) {
714 pa_source_assert_ref(s
);
716 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
719 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
721 if (old
&& description
&& !strcmp(old
, description
))
725 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
727 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
729 if (PA_SOURCE_IS_LINKED(s
->state
)) {
730 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
731 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
735 /* Called from main thread */
736 unsigned pa_source_linked_by(pa_source
*s
) {
737 pa_source_assert_ref(s
);
738 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
740 return pa_idxset_size(s
->outputs
);
743 /* Called from main thread */
744 unsigned pa_source_used_by(pa_source
*s
) {
747 pa_source_assert_ref(s
);
748 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
750 ret
= pa_idxset_size(s
->outputs
);
751 pa_assert(ret
>= s
->n_corked
);
753 return ret
- s
->n_corked
;
756 /* Called from main thread */
757 unsigned pa_source_check_suspend(pa_source
*s
) {
762 pa_source_assert_ref(s
);
764 if (!PA_SOURCE_IS_LINKED(s
->state
))
769 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
))) {
770 pa_source_output_state_t st
;
772 st
= pa_source_output_get_state(o
);
773 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
775 if (st
== PA_SOURCE_OUTPUT_CORKED
)
778 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
787 /* Called from IO thread, except when it is not */
788 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
789 pa_source
*s
= PA_SOURCE(object
);
790 pa_source_assert_ref(s
);
792 switch ((pa_source_message_t
) code
) {
794 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
795 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
797 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
799 if (o
->direct_on_input
) {
800 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
801 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
804 pa_assert(!o
->thread_info
.attached
);
805 o
->thread_info
.attached
= TRUE
;
810 pa_source_output_set_state_within_thread(o
, o
->state
);
812 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
813 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
815 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
817 /* We don't just invalidate the requested latency here,
818 * because if we are in a move we might need to fix up the
819 * requested latency. */
820 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
825 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
826 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
828 pa_source_output_set_state_within_thread(o
, o
->state
);
833 pa_assert(o
->thread_info
.attached
);
834 o
->thread_info
.attached
= FALSE
;
836 if (o
->thread_info
.direct_on_input
) {
837 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
838 o
->thread_info
.direct_on_input
= NULL
;
841 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
842 pa_source_output_unref(o
);
844 pa_source_invalidate_requested_latency(s
);
849 case PA_SOURCE_MESSAGE_SET_VOLUME
:
850 s
->thread_info
.soft_volume
= s
->soft_volume
;
853 case PA_SOURCE_MESSAGE_GET_VOLUME
:
856 case PA_SOURCE_MESSAGE_SET_MUTE
:
857 s
->thread_info
.soft_muted
= s
->muted
;
860 case PA_SOURCE_MESSAGE_GET_MUTE
:
863 case PA_SOURCE_MESSAGE_SET_STATE
:
864 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
867 case PA_SOURCE_MESSAGE_DETACH
:
869 /* Detach all streams */
870 pa_source_detach_within_thread(s
);
873 case PA_SOURCE_MESSAGE_ATTACH
:
875 /* Reattach all streams */
876 pa_source_attach_within_thread(s
);
879 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
881 pa_usec_t
*usec
= userdata
;
882 *usec
= pa_source_get_requested_latency_within_thread(s
);
884 if (*usec
== (pa_usec_t
) -1)
885 *usec
= s
->thread_info
.max_latency
;
890 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
891 pa_usec_t
*r
= userdata
;
893 pa_source_update_latency_range(s
, r
[0], r
[1]);
898 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
899 pa_usec_t
*r
= userdata
;
901 r
[0] = s
->thread_info
.min_latency
;
902 r
[1] = s
->thread_info
.max_latency
;
907 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
909 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
912 case PA_SOURCE_MESSAGE_GET_LATENCY
:
915 *((pa_usec_t
*) userdata
) = 0;
919 /* Implementors need to overwrite this implementation! */
922 case PA_SOURCE_MESSAGE_MAX
:
929 /* Called from main thread */
930 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
) {
935 pa_core_assert_ref(c
);
937 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
)))
938 ret
-= pa_source_suspend(source
, suspend
) < 0;
943 /* Called from main thread */
944 void pa_source_detach(pa_source
*s
) {
945 pa_source_assert_ref(s
);
946 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
948 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
951 /* Called from main thread */
952 void pa_source_attach(pa_source
*s
) {
953 pa_source_assert_ref(s
);
954 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
956 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
959 /* Called from IO thread */
960 void pa_source_detach_within_thread(pa_source
*s
) {
964 pa_source_assert_ref(s
);
965 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
967 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
972 /* Called from IO thread */
973 void pa_source_attach_within_thread(pa_source
*s
) {
977 pa_source_assert_ref(s
);
978 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
980 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
985 /* Called from IO thread */
986 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
987 pa_usec_t result
= (pa_usec_t
) -1;
991 pa_source_assert_ref(s
);
993 if (s
->thread_info
.requested_latency_valid
)
994 return s
->thread_info
.requested_latency
;
996 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
998 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
999 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1000 result
= o
->thread_info
.requested_source_latency
;
1002 if (result
!= (pa_usec_t
) -1) {
1003 if (s
->thread_info
.max_latency
> 0 && result
> s
->thread_info
.max_latency
)
1004 result
= s
->thread_info
.max_latency
;
1006 if (s
->thread_info
.min_latency
> 0 && result
< s
->thread_info
.min_latency
)
1007 result
= s
->thread_info
.min_latency
;
1010 s
->thread_info
.requested_latency
= result
;
1011 s
->thread_info
.requested_latency_valid
= TRUE
;
1016 /* Called from main thread */
1017 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1020 pa_source_assert_ref(s
);
1021 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1023 if (s
->state
== PA_SOURCE_SUSPENDED
)
1026 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1031 /* Called from IO thread */
1032 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1033 pa_source_output
*o
;
1036 pa_source_assert_ref(s
);
1038 if (max_rewind
== s
->thread_info
.max_rewind
)
1041 s
->thread_info
.max_rewind
= max_rewind
;
1043 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1044 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1045 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1049 void pa_source_invalidate_requested_latency(pa_source
*s
) {
1050 pa_source_output
*o
;
1053 pa_source_assert_ref(s
);
1055 s
->thread_info
.requested_latency_valid
= FALSE
;
1057 if (s
->update_requested_latency
)
1058 s
->update_requested_latency(s
);
1060 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1061 if (o
->update_source_requested_latency
)
1062 o
->update_source_requested_latency(o
);
1065 pa_sink_invalidate_requested_latency(s
->monitor_of
);
1068 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1069 pa_source_assert_ref(s
);
1071 /* min_latency == 0: no limit
1072 * min_latency == (size_t) -1: default limit
1073 * min_latency anything else: specified limit
1075 * Similar for max_latency */
1077 if (min_latency
== (pa_usec_t
) -1)
1078 min_latency
= DEFAULT_MIN_LATENCY
;
1080 if (max_latency
== (pa_usec_t
) -1)
1081 max_latency
= min_latency
;
1083 pa_assert(!min_latency
|| !max_latency
||
1084 min_latency
<= max_latency
);
1086 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1092 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1094 s
->thread_info
.min_latency
= min_latency
;
1095 s
->thread_info
.max_latency
= max_latency
;
1097 s
->thread_info
.requested_latency_valid
= FALSE
;
1101 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1102 pa_source_assert_ref(s
);
1103 pa_assert(min_latency
);
1104 pa_assert(max_latency
);
1106 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1107 pa_usec_t r
[2] = { 0, 0 };
1109 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1111 *min_latency
= r
[0];
1112 *max_latency
= r
[1];
1114 *min_latency
= s
->thread_info
.min_latency
;
1115 *max_latency
= s
->thread_info
.max_latency
;
1119 /* Called from IO thread */
1120 void pa_source_update_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1121 pa_source_output
*o
;
1124 pa_source_assert_ref(s
);
1126 pa_assert(!min_latency
|| !max_latency
||
1127 min_latency
<= max_latency
);
1129 s
->thread_info
.min_latency
= min_latency
;
1130 s
->thread_info
.max_latency
= max_latency
;
1132 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1133 if (o
->update_source_latency_range
)
1134 o
->update_source_latency_range(o
);
1136 pa_source_invalidate_requested_latency(s
);
1139 size_t pa_source_get_max_rewind(pa_source
*s
) {
1141 pa_source_assert_ref(s
);
1143 if (!PA_SOURCE_IS_LINKED(s
->state
))
1144 return s
->thread_info
.max_rewind
;
1146 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);