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 -PA_ERR_NOTSUPPORTED
;
431 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
433 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
436 /* Called from main context */
437 pa_queue
*pa_source_move_all_start(pa_source
*s
) {
439 pa_source_output
*o
, *n
;
442 pa_source_assert_ref(s
);
443 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
447 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
448 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
450 if (pa_source_output_start_move(o
) >= 0)
451 pa_queue_push(q
, pa_source_output_ref(o
));
457 /* Called from main context */
458 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
461 pa_source_assert_ref(s
);
462 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
465 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
466 if (pa_source_output_finish_move(o
, s
, save
) < 0)
467 pa_source_output_kill(o
);
469 pa_source_output_unref(o
);
472 pa_queue_free(q
, NULL
, NULL
);
475 /* Called from main context */
476 void pa_source_move_all_fail(pa_queue
*q
) {
480 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
481 if (pa_hook_fire(&o
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL
], o
) == PA_HOOK_OK
) {
482 pa_source_output_kill(o
);
483 pa_source_output_unref(o
);
487 pa_queue_free(q
, NULL
, NULL
);
490 /* Called from IO thread context */
491 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
495 pa_source_assert_ref(s
);
496 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
498 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
504 pa_log_debug("Processing rewind...");
506 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
507 pa_source_output_assert_ref(o
);
508 pa_source_output_process_rewind(o
, nbytes
);
512 /* Called from IO thread context */
513 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
517 pa_source_assert_ref(s
);
518 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
521 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
524 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
525 pa_memchunk vchunk
= *chunk
;
527 pa_memblock_ref(vchunk
.memblock
);
528 pa_memchunk_make_writable(&vchunk
, 0);
530 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
531 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
533 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
535 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
536 pa_source_output_assert_ref(o
);
538 if (!o
->thread_info
.direct_on_input
)
539 pa_source_output_push(o
, &vchunk
);
542 pa_memblock_unref(vchunk
.memblock
);
545 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
546 pa_source_output_assert_ref(o
);
548 if (!o
->thread_info
.direct_on_input
)
549 pa_source_output_push(o
, chunk
);
554 /* Called from IO thread context */
555 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
556 pa_source_assert_ref(s
);
557 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
558 pa_source_output_assert_ref(o
);
559 pa_assert(o
->thread_info
.direct_on_input
);
562 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
565 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
566 pa_memchunk vchunk
= *chunk
;
568 pa_memblock_ref(vchunk
.memblock
);
569 pa_memchunk_make_writable(&vchunk
, 0);
571 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
572 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
574 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
576 pa_source_output_push(o
, &vchunk
);
578 pa_memblock_unref(vchunk
.memblock
);
580 pa_source_output_push(o
, chunk
);
583 /* Called from main thread */
584 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
587 pa_source_assert_ref(s
);
588 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
590 if (s
->state
== PA_SOURCE_SUSPENDED
)
593 if (!(s
->flags
& PA_SOURCE_LATENCY
))
596 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
601 /* Called from main thread */
602 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
) {
603 pa_cvolume old_virtual_volume
;
604 pa_bool_t virtual_volume_changed
;
606 pa_source_assert_ref(s
);
607 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
609 pa_assert(pa_cvolume_valid(volume
));
610 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
612 old_virtual_volume
= s
->virtual_volume
;
613 s
->virtual_volume
= *volume
;
614 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
617 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
620 s
->soft_volume
= s
->virtual_volume
;
622 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
624 if (virtual_volume_changed
)
625 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
628 /* Called from main thread. Only to be called by source implementor */
629 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
630 pa_source_assert_ref(s
);
633 if (PA_SOURCE_IS_LINKED(s
->state
))
634 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
636 s
->thread_info
.soft_volume
= *volume
;
639 /* Called from main thread */
640 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
641 pa_source_assert_ref(s
);
642 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
644 if (s
->refresh_volume
|| force_refresh
) {
645 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
650 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
652 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
))
653 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
656 return &s
->virtual_volume
;
659 /* Called from main thread */
660 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
) {
663 pa_source_assert_ref(s
);
664 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
666 old_muted
= s
->muted
;
672 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
674 if (old_muted
!= s
->muted
)
675 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
678 /* Called from main thread */
679 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
681 pa_source_assert_ref(s
);
682 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
684 if (s
->refresh_muted
|| force_refresh
) {
685 pa_bool_t old_muted
= s
->muted
;
690 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
692 if (old_muted
!= s
->muted
)
693 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
699 /* Called from main thread */
700 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
701 pa_source_assert_ref(s
);
704 pa_proplist_update(s
->proplist
, mode
, p
);
706 if (PA_SOURCE_IS_LINKED(s
->state
)) {
707 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
708 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
714 /* Called from main thread */
715 void pa_source_set_description(pa_source
*s
, const char *description
) {
717 pa_source_assert_ref(s
);
719 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
722 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
724 if (old
&& description
&& !strcmp(old
, description
))
728 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
730 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
732 if (PA_SOURCE_IS_LINKED(s
->state
)) {
733 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
734 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
738 /* Called from main thread */
739 unsigned pa_source_linked_by(pa_source
*s
) {
740 pa_source_assert_ref(s
);
741 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
743 return pa_idxset_size(s
->outputs
);
746 /* Called from main thread */
747 unsigned pa_source_used_by(pa_source
*s
) {
750 pa_source_assert_ref(s
);
751 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
753 ret
= pa_idxset_size(s
->outputs
);
754 pa_assert(ret
>= s
->n_corked
);
756 return ret
- s
->n_corked
;
759 /* Called from main thread */
760 unsigned pa_source_check_suspend(pa_source
*s
) {
765 pa_source_assert_ref(s
);
767 if (!PA_SOURCE_IS_LINKED(s
->state
))
772 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
))) {
773 pa_source_output_state_t st
;
775 st
= pa_source_output_get_state(o
);
776 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
778 if (st
== PA_SOURCE_OUTPUT_CORKED
)
781 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
790 /* Called from IO thread, except when it is not */
791 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
792 pa_source
*s
= PA_SOURCE(object
);
793 pa_source_assert_ref(s
);
795 switch ((pa_source_message_t
) code
) {
797 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
798 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
800 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
802 if (o
->direct_on_input
) {
803 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
804 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
807 pa_assert(!o
->thread_info
.attached
);
808 o
->thread_info
.attached
= TRUE
;
813 pa_source_output_set_state_within_thread(o
, o
->state
);
815 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
816 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
818 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
820 /* We don't just invalidate the requested latency here,
821 * because if we are in a move we might need to fix up the
822 * requested latency. */
823 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
828 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
829 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
831 pa_source_output_set_state_within_thread(o
, o
->state
);
836 pa_assert(o
->thread_info
.attached
);
837 o
->thread_info
.attached
= FALSE
;
839 if (o
->thread_info
.direct_on_input
) {
840 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
841 o
->thread_info
.direct_on_input
= NULL
;
844 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
845 pa_source_output_unref(o
);
847 pa_source_invalidate_requested_latency(s
);
852 case PA_SOURCE_MESSAGE_SET_VOLUME
:
853 s
->thread_info
.soft_volume
= s
->soft_volume
;
856 case PA_SOURCE_MESSAGE_GET_VOLUME
:
859 case PA_SOURCE_MESSAGE_SET_MUTE
:
860 s
->thread_info
.soft_muted
= s
->muted
;
863 case PA_SOURCE_MESSAGE_GET_MUTE
:
866 case PA_SOURCE_MESSAGE_SET_STATE
:
867 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
870 case PA_SOURCE_MESSAGE_DETACH
:
872 /* Detach all streams */
873 pa_source_detach_within_thread(s
);
876 case PA_SOURCE_MESSAGE_ATTACH
:
878 /* Reattach all streams */
879 pa_source_attach_within_thread(s
);
882 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
884 pa_usec_t
*usec
= userdata
;
885 *usec
= pa_source_get_requested_latency_within_thread(s
);
887 if (*usec
== (pa_usec_t
) -1)
888 *usec
= s
->thread_info
.max_latency
;
893 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
894 pa_usec_t
*r
= userdata
;
896 pa_source_update_latency_range(s
, r
[0], r
[1]);
901 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
902 pa_usec_t
*r
= userdata
;
904 r
[0] = s
->thread_info
.min_latency
;
905 r
[1] = s
->thread_info
.max_latency
;
910 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
912 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
915 case PA_SOURCE_MESSAGE_GET_LATENCY
:
918 *((pa_usec_t
*) userdata
) = 0;
922 /* Implementors need to overwrite this implementation! */
925 case PA_SOURCE_MESSAGE_MAX
:
932 /* Called from main thread */
933 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
) {
938 pa_core_assert_ref(c
);
940 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
)))
941 ret
-= pa_source_suspend(source
, suspend
) < 0;
946 /* Called from main thread */
947 void pa_source_detach(pa_source
*s
) {
948 pa_source_assert_ref(s
);
949 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
951 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
954 /* Called from main thread */
955 void pa_source_attach(pa_source
*s
) {
956 pa_source_assert_ref(s
);
957 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
959 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
962 /* Called from IO thread */
963 void pa_source_detach_within_thread(pa_source
*s
) {
967 pa_source_assert_ref(s
);
968 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
970 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
975 /* Called from IO thread */
976 void pa_source_attach_within_thread(pa_source
*s
) {
980 pa_source_assert_ref(s
);
981 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
983 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
988 /* Called from IO thread */
989 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
990 pa_usec_t result
= (pa_usec_t
) -1;
994 pa_source_assert_ref(s
);
996 if (s
->thread_info
.requested_latency_valid
)
997 return s
->thread_info
.requested_latency
;
999 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1001 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1002 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1003 result
= o
->thread_info
.requested_source_latency
;
1005 if (result
!= (pa_usec_t
) -1) {
1006 if (s
->thread_info
.max_latency
> 0 && result
> s
->thread_info
.max_latency
)
1007 result
= s
->thread_info
.max_latency
;
1009 if (s
->thread_info
.min_latency
> 0 && result
< s
->thread_info
.min_latency
)
1010 result
= s
->thread_info
.min_latency
;
1013 s
->thread_info
.requested_latency
= result
;
1014 s
->thread_info
.requested_latency_valid
= TRUE
;
1019 /* Called from main thread */
1020 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1023 pa_source_assert_ref(s
);
1024 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1026 if (s
->state
== PA_SOURCE_SUSPENDED
)
1029 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1034 /* Called from IO thread */
1035 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1036 pa_source_output
*o
;
1039 pa_source_assert_ref(s
);
1041 if (max_rewind
== s
->thread_info
.max_rewind
)
1044 s
->thread_info
.max_rewind
= max_rewind
;
1046 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1047 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1048 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1052 void pa_source_invalidate_requested_latency(pa_source
*s
) {
1053 pa_source_output
*o
;
1056 pa_source_assert_ref(s
);
1058 s
->thread_info
.requested_latency_valid
= FALSE
;
1060 if (s
->update_requested_latency
)
1061 s
->update_requested_latency(s
);
1063 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1064 if (o
->update_source_requested_latency
)
1065 o
->update_source_requested_latency(o
);
1068 pa_sink_invalidate_requested_latency(s
->monitor_of
);
1071 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1072 pa_source_assert_ref(s
);
1074 /* min_latency == 0: no limit
1075 * min_latency == (size_t) -1: default limit
1076 * min_latency anything else: specified limit
1078 * Similar for max_latency */
1080 if (min_latency
== (pa_usec_t
) -1)
1081 min_latency
= DEFAULT_MIN_LATENCY
;
1083 if (max_latency
== (pa_usec_t
) -1)
1084 max_latency
= min_latency
;
1086 pa_assert(!min_latency
|| !max_latency
||
1087 min_latency
<= max_latency
);
1089 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1095 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1097 s
->thread_info
.min_latency
= min_latency
;
1098 s
->thread_info
.max_latency
= max_latency
;
1100 s
->thread_info
.requested_latency_valid
= FALSE
;
1104 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1105 pa_source_assert_ref(s
);
1106 pa_assert(min_latency
);
1107 pa_assert(max_latency
);
1109 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1110 pa_usec_t r
[2] = { 0, 0 };
1112 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1114 *min_latency
= r
[0];
1115 *max_latency
= r
[1];
1117 *min_latency
= s
->thread_info
.min_latency
;
1118 *max_latency
= s
->thread_info
.max_latency
;
1122 /* Called from IO thread */
1123 void pa_source_update_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1124 pa_source_output
*o
;
1127 pa_source_assert_ref(s
);
1129 pa_assert(!min_latency
|| !max_latency
||
1130 min_latency
<= max_latency
);
1132 s
->thread_info
.min_latency
= min_latency
;
1133 s
->thread_info
.max_latency
= max_latency
;
1135 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1136 if (o
->update_source_latency_range
)
1137 o
->update_source_latency_range(o
);
1139 pa_source_invalidate_requested_latency(s
);
1142 size_t pa_source_get_max_rewind(pa_source
*s
) {
1144 pa_source_assert_ref(s
);
1146 if (!PA_SOURCE_IS_LINKED(s
->state
))
1147 return s
->thread_info
.max_rewind
;
1149 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);