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
);
171 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_FIXATE
], data
) < 0) {
173 pa_namereg_unregister(core
, name
);
177 if (!(flags
& PA_SOURCE_HW_VOLUME_CTRL
))
178 flags
|= PA_SOURCE_DECIBEL_VOLUME
;
180 s
->parent
.parent
.free
= source_free
;
181 s
->parent
.process_msg
= pa_source_process_msg
;
184 s
->state
= PA_SOURCE_INIT
;
186 s
->name
= pa_xstrdup(name
);
187 s
->proplist
= pa_proplist_copy(data
->proplist
);
188 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
189 s
->module
= data
->module
;
190 s
->card
= data
->card
;
192 s
->sample_spec
= data
->sample_spec
;
193 s
->channel_map
= data
->channel_map
;
195 s
->outputs
= pa_idxset_new(NULL
, NULL
);
197 s
->monitor_of
= NULL
;
199 s
->virtual_volume
= data
->volume
;
200 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
201 s
->base_volume
= PA_VOLUME_NORM
;
202 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
203 s
->muted
= data
->muted
;
204 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
206 s
->fixed_latency
= flags
& PA_SOURCE_DYNAMIC_LATENCY
? 0 : DEFAULT_FIXED_LATENCY
;
214 pa_silence_memchunk_get(
215 &core
->silence_cache
,
221 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
222 s
->thread_info
.soft_volume
= s
->soft_volume
;
223 s
->thread_info
.soft_muted
= s
->muted
;
224 s
->thread_info
.state
= s
->state
;
225 s
->thread_info
.max_rewind
= 0;
226 s
->thread_info
.requested_latency_valid
= FALSE
;
227 s
->thread_info
.requested_latency
= 0;
228 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
229 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
231 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
234 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
236 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
237 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
240 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
241 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
248 /* Called from main context */
249 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
251 pa_bool_t suspend_change
;
252 pa_source_state_t original_state
;
256 if (s
->state
== state
)
259 original_state
= s
->state
;
262 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
263 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
266 if ((ret
= s
->set_state(s
, state
)) < 0)
270 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
273 s
->set_state(s
, original_state
);
280 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
281 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
282 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
285 if (suspend_change
) {
289 /* We're suspending or resuming, tell everyone about it */
291 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
)))
292 if (s
->state
== PA_SOURCE_SUSPENDED
&&
293 (o
->flags
& PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND
))
294 pa_source_output_kill(o
);
296 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
303 /* Called from main context */
304 void pa_source_put(pa_source
*s
) {
305 pa_source_assert_ref(s
);
307 pa_assert(s
->state
== PA_SOURCE_INIT
);
309 /* The following fields must be initialized properly when calling _put() */
310 pa_assert(s
->asyncmsgq
);
311 pa_assert(s
->rtpoll
);
312 pa_assert(s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
314 s
->thread_info
.soft_volume
= s
->soft_volume
;
315 s
->thread_info
.soft_muted
= s
->muted
;
317 pa_assert((s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
) || (s
->base_volume
== PA_VOLUME_NORM
&& s
->flags
& PA_SOURCE_DECIBEL_VOLUME
));
318 pa_assert(!(s
->flags
& PA_SOURCE_DECIBEL_VOLUME
) || s
->n_volume_steps
== PA_VOLUME_NORM
+1);
319 pa_assert(!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) == (s
->fixed_latency
!= 0));
321 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
323 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
324 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
327 /* Called from main context */
328 void pa_source_unlink(pa_source
*s
) {
330 pa_source_output
*o
, *j
= NULL
;
334 /* See pa_sink_unlink() for a couple of comments how this function
337 linked
= PA_SOURCE_IS_LINKED(s
->state
);
340 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
342 if (s
->state
!= PA_SOURCE_UNLINKED
)
343 pa_namereg_unregister(s
->core
, s
->name
);
344 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
347 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
349 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
351 pa_source_output_kill(o
);
356 source_set_state(s
, PA_SOURCE_UNLINKED
);
358 s
->state
= PA_SOURCE_UNLINKED
;
363 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
364 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
368 /* Called from main context */
369 static void source_free(pa_object
*o
) {
370 pa_source_output
*so
;
371 pa_source
*s
= PA_SOURCE(o
);
374 pa_assert(pa_source_refcnt(s
) == 0);
376 if (PA_SOURCE_IS_LINKED(s
->state
))
379 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
381 pa_idxset_free(s
->outputs
, NULL
, NULL
);
383 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
384 pa_source_output_unref(so
);
386 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
388 if (s
->silence
.memblock
)
389 pa_memblock_unref(s
->silence
.memblock
);
395 pa_proplist_free(s
->proplist
);
400 /* Called from main context */
401 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
402 pa_source_assert_ref(s
);
407 /* Called from main context */
408 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
409 pa_source_assert_ref(s
);
414 /* Called from main context */
415 int pa_source_update_status(pa_source
*s
) {
416 pa_source_assert_ref(s
);
417 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
419 if (s
->state
== PA_SOURCE_SUSPENDED
)
422 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
425 /* Called from main context */
426 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
) {
427 pa_source_assert_ref(s
);
428 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
431 return -PA_ERR_NOTSUPPORTED
;
434 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
436 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
439 /* Called from main context */
440 int pa_source_sync_suspend(pa_source
*s
) {
441 pa_sink_state_t state
;
443 pa_source_assert_ref(s
);
444 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
445 pa_assert(s
->monitor_of
);
447 state
= pa_sink_get_state(s
->monitor_of
);
449 if (state
== PA_SINK_SUSPENDED
)
450 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
452 pa_assert(PA_SINK_IS_OPENED(state
));
454 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
457 /* Called from main context */
458 pa_queue
*pa_source_move_all_start(pa_source
*s
) {
460 pa_source_output
*o
, *n
;
463 pa_source_assert_ref(s
);
464 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
468 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
469 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
471 pa_source_output_ref(o
);
473 if (pa_source_output_start_move(o
) >= 0)
476 pa_source_output_unref(o
);
482 /* Called from main context */
483 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
486 pa_source_assert_ref(s
);
487 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
490 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
491 if (pa_source_output_finish_move(o
, s
, save
) < 0)
492 pa_source_output_kill(o
);
494 pa_source_output_unref(o
);
497 pa_queue_free(q
, NULL
, NULL
);
500 /* Called from main context */
501 void pa_source_move_all_fail(pa_queue
*q
) {
505 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
506 if (pa_hook_fire(&o
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL
], o
) == PA_HOOK_OK
) {
507 pa_source_output_kill(o
);
508 pa_source_output_unref(o
);
512 pa_queue_free(q
, NULL
, NULL
);
515 /* Called from IO thread context */
516 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
520 pa_source_assert_ref(s
);
521 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
523 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
529 pa_log_debug("Processing rewind...");
531 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
532 pa_source_output_assert_ref(o
);
533 pa_source_output_process_rewind(o
, nbytes
);
537 /* Called from IO thread context */
538 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
542 pa_source_assert_ref(s
);
543 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
546 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
549 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
550 pa_memchunk vchunk
= *chunk
;
552 pa_memblock_ref(vchunk
.memblock
);
553 pa_memchunk_make_writable(&vchunk
, 0);
555 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
556 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
558 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
560 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
561 pa_source_output_assert_ref(o
);
563 if (!o
->thread_info
.direct_on_input
)
564 pa_source_output_push(o
, &vchunk
);
567 pa_memblock_unref(vchunk
.memblock
);
570 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
571 pa_source_output_assert_ref(o
);
573 if (!o
->thread_info
.direct_on_input
)
574 pa_source_output_push(o
, chunk
);
579 /* Called from IO thread context */
580 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
581 pa_source_assert_ref(s
);
582 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
583 pa_source_output_assert_ref(o
);
584 pa_assert(o
->thread_info
.direct_on_input
);
587 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
590 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
591 pa_memchunk vchunk
= *chunk
;
593 pa_memblock_ref(vchunk
.memblock
);
594 pa_memchunk_make_writable(&vchunk
, 0);
596 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
597 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
599 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
601 pa_source_output_push(o
, &vchunk
);
603 pa_memblock_unref(vchunk
.memblock
);
605 pa_source_output_push(o
, chunk
);
608 /* Called from main thread */
609 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
612 pa_source_assert_ref(s
);
613 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
615 if (s
->state
== PA_SOURCE_SUSPENDED
)
618 if (!(s
->flags
& PA_SOURCE_LATENCY
))
621 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
626 /* Called from IO thread */
627 pa_usec_t
pa_source_get_latency_within_thread(pa_source
*s
) {
631 pa_source_assert_ref(s
);
632 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
634 /* The returned value is supposed to be in the time domain of the sound card! */
636 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
639 if (!(s
->flags
& PA_SOURCE_LATENCY
))
644 /* We probably should make this a proper vtable callback instead of going through process_msg() */
646 if (o
->process_msg(o
, PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
652 /* Called from main thread */
653 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
) {
654 pa_cvolume old_virtual_volume
;
655 pa_bool_t virtual_volume_changed
;
657 pa_source_assert_ref(s
);
658 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
660 pa_assert(pa_cvolume_valid(volume
));
661 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
663 old_virtual_volume
= s
->virtual_volume
;
664 s
->virtual_volume
= *volume
;
665 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
668 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
671 s
->soft_volume
= s
->virtual_volume
;
673 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
675 if (virtual_volume_changed
)
676 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
679 /* Called from main thread. Only to be called by source implementor */
680 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
681 pa_source_assert_ref(s
);
684 if (PA_SOURCE_IS_LINKED(s
->state
))
685 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
687 s
->thread_info
.soft_volume
= *volume
;
690 /* Called from main thread */
691 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
692 pa_source_assert_ref(s
);
693 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
695 if (s
->refresh_volume
|| force_refresh
) {
696 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
701 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
703 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
))
704 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
707 return &s
->virtual_volume
;
710 /* Called from main thread */
711 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
712 pa_source_assert_ref(s
);
714 /* The source implementor may call this if the volume changed to make sure everyone is notified */
716 if (pa_cvolume_equal(&s
->virtual_volume
, new_volume
))
719 s
->virtual_volume
= *new_volume
;
720 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
723 /* Called from main thread */
724 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
) {
727 pa_source_assert_ref(s
);
728 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
730 old_muted
= s
->muted
;
736 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
738 if (old_muted
!= s
->muted
)
739 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
742 /* Called from main thread */
743 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
744 pa_source_assert_ref(s
);
745 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
747 if (s
->refresh_muted
|| force_refresh
) {
748 pa_bool_t old_muted
= s
->muted
;
753 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_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
);
762 /* Called from main thread */
763 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
764 pa_source_assert_ref(s
);
766 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
768 if (s
->muted
== new_muted
)
771 s
->muted
= new_muted
;
772 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
775 /* Called from main thread */
776 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
777 pa_source_assert_ref(s
);
780 pa_proplist_update(s
->proplist
, mode
, p
);
782 if (PA_SOURCE_IS_LINKED(s
->state
)) {
783 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
784 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
790 /* Called from main thread */
791 void pa_source_set_description(pa_source
*s
, const char *description
) {
793 pa_source_assert_ref(s
);
795 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
798 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
800 if (old
&& description
&& !strcmp(old
, description
))
804 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
806 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
808 if (PA_SOURCE_IS_LINKED(s
->state
)) {
809 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
810 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
814 /* Called from main thread */
815 unsigned pa_source_linked_by(pa_source
*s
) {
816 pa_source_assert_ref(s
);
817 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
819 return pa_idxset_size(s
->outputs
);
822 /* Called from main thread */
823 unsigned pa_source_used_by(pa_source
*s
) {
826 pa_source_assert_ref(s
);
827 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
829 ret
= pa_idxset_size(s
->outputs
);
830 pa_assert(ret
>= s
->n_corked
);
832 return ret
- s
->n_corked
;
835 /* Called from main thread */
836 unsigned pa_source_check_suspend(pa_source
*s
) {
841 pa_source_assert_ref(s
);
843 if (!PA_SOURCE_IS_LINKED(s
->state
))
848 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
))) {
849 pa_source_output_state_t st
;
851 st
= pa_source_output_get_state(o
);
852 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
854 if (st
== PA_SOURCE_OUTPUT_CORKED
)
857 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
866 /* Called from IO thread, except when it is not */
867 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
868 pa_source
*s
= PA_SOURCE(object
);
869 pa_source_assert_ref(s
);
871 switch ((pa_source_message_t
) code
) {
873 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
874 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
876 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
878 if (o
->direct_on_input
) {
879 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
880 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
883 pa_assert(!o
->thread_info
.attached
);
884 o
->thread_info
.attached
= TRUE
;
889 pa_source_output_set_state_within_thread(o
, o
->state
);
891 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
892 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
894 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
896 /* We don't just invalidate the requested latency here,
897 * because if we are in a move we might need to fix up the
898 * requested latency. */
899 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
904 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
905 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
907 pa_source_output_set_state_within_thread(o
, o
->state
);
912 pa_assert(o
->thread_info
.attached
);
913 o
->thread_info
.attached
= FALSE
;
915 if (o
->thread_info
.direct_on_input
) {
916 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
917 o
->thread_info
.direct_on_input
= NULL
;
920 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
921 pa_source_output_unref(o
);
923 pa_source_invalidate_requested_latency(s
);
928 case PA_SOURCE_MESSAGE_SET_VOLUME
:
929 s
->thread_info
.soft_volume
= s
->soft_volume
;
932 case PA_SOURCE_MESSAGE_GET_VOLUME
:
935 case PA_SOURCE_MESSAGE_SET_MUTE
:
936 s
->thread_info
.soft_muted
= s
->muted
;
939 case PA_SOURCE_MESSAGE_GET_MUTE
:
942 case PA_SOURCE_MESSAGE_SET_STATE
: {
944 pa_bool_t suspend_change
=
945 (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
946 (PA_SOURCE_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SOURCE_SUSPENDED
);
948 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
950 if (suspend_change
) {
954 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
955 if (o
->suspend_within_thread
)
956 o
->suspend_within_thread(o
, s
->thread_info
.state
== PA_SOURCE_SUSPENDED
);
963 case PA_SOURCE_MESSAGE_DETACH
:
965 /* Detach all streams */
966 pa_source_detach_within_thread(s
);
969 case PA_SOURCE_MESSAGE_ATTACH
:
971 /* Reattach all streams */
972 pa_source_attach_within_thread(s
);
975 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
977 pa_usec_t
*usec
= userdata
;
978 *usec
= pa_source_get_requested_latency_within_thread(s
);
980 if (*usec
== (pa_usec_t
) -1)
981 *usec
= s
->thread_info
.max_latency
;
986 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
987 pa_usec_t
*r
= userdata
;
989 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
994 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
995 pa_usec_t
*r
= userdata
;
997 r
[0] = s
->thread_info
.min_latency
;
998 r
[1] = s
->thread_info
.max_latency
;
1003 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
1005 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1008 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
1010 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
1013 case PA_SOURCE_MESSAGE_GET_LATENCY
:
1015 if (s
->monitor_of
) {
1016 *((pa_usec_t
*) userdata
) = 0;
1020 /* Implementors need to overwrite this implementation! */
1023 case PA_SOURCE_MESSAGE_MAX
:
1030 /* Called from main thread */
1031 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
) {
1036 pa_core_assert_ref(c
);
1038 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1041 if (source
->monitor_of
)
1044 if ((r
= pa_source_suspend(source
, suspend
)) < 0)
1051 /* Called from main thread */
1052 void pa_source_detach(pa_source
*s
) {
1053 pa_source_assert_ref(s
);
1054 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1056 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1059 /* Called from main thread */
1060 void pa_source_attach(pa_source
*s
) {
1061 pa_source_assert_ref(s
);
1062 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1064 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1067 /* Called from IO thread */
1068 void pa_source_detach_within_thread(pa_source
*s
) {
1069 pa_source_output
*o
;
1072 pa_source_assert_ref(s
);
1073 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1075 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1080 /* Called from IO thread */
1081 void pa_source_attach_within_thread(pa_source
*s
) {
1082 pa_source_output
*o
;
1085 pa_source_assert_ref(s
);
1086 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1088 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1093 /* Called from IO thread */
1094 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1095 pa_usec_t result
= (pa_usec_t
) -1;
1096 pa_source_output
*o
;
1099 pa_source_assert_ref(s
);
1101 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1102 return PA_CLAMP(s
->fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1104 if (s
->thread_info
.requested_latency_valid
)
1105 return s
->thread_info
.requested_latency
;
1107 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1109 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1110 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1111 result
= o
->thread_info
.requested_source_latency
;
1113 if (result
!= (pa_usec_t
) -1)
1114 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1116 s
->thread_info
.requested_latency
= result
;
1117 s
->thread_info
.requested_latency_valid
= TRUE
;
1122 /* Called from main thread */
1123 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1126 pa_source_assert_ref(s
);
1127 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1129 if (s
->state
== PA_SOURCE_SUSPENDED
)
1132 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1137 /* Called from IO thread */
1138 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1139 pa_source_output
*o
;
1142 pa_source_assert_ref(s
);
1144 if (max_rewind
== s
->thread_info
.max_rewind
)
1147 s
->thread_info
.max_rewind
= max_rewind
;
1149 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1150 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1151 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1155 /* Called from main thread */
1156 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1157 pa_source_assert_ref(s
);
1159 if (PA_SOURCE_IS_LINKED(s
->state
))
1160 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1162 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1165 /* Called from IO thread */
1166 void pa_source_invalidate_requested_latency(pa_source
*s
) {
1167 pa_source_output
*o
;
1170 pa_source_assert_ref(s
);
1172 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1175 s
->thread_info
.requested_latency_valid
= FALSE
;
1177 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1179 if (s
->update_requested_latency
)
1180 s
->update_requested_latency(s
);
1182 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1183 if (o
->update_source_requested_latency
)
1184 o
->update_source_requested_latency(o
);
1188 pa_sink_invalidate_requested_latency(s
->monitor_of
);
1191 /* Called from main thread */
1192 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1193 pa_source_assert_ref(s
);
1195 /* min_latency == 0: no limit
1196 * min_latency anything else: specified limit
1198 * Similar for max_latency */
1200 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1201 min_latency
= ABSOLUTE_MIN_LATENCY
;
1203 if (max_latency
<= 0 ||
1204 max_latency
> ABSOLUTE_MAX_LATENCY
)
1205 max_latency
= ABSOLUTE_MAX_LATENCY
;
1207 pa_assert(min_latency
<= max_latency
);
1209 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1210 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1211 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1212 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1214 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1220 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1222 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1225 /* Called from main thread */
1226 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1227 pa_source_assert_ref(s
);
1228 pa_assert(min_latency
);
1229 pa_assert(max_latency
);
1231 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1232 pa_usec_t r
[2] = { 0, 0 };
1234 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1236 *min_latency
= r
[0];
1237 *max_latency
= r
[1];
1239 *min_latency
= s
->thread_info
.min_latency
;
1240 *max_latency
= s
->thread_info
.max_latency
;
1244 /* Called from IO thread, and from main thread before pa_source_put() is called */
1245 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1248 pa_source_assert_ref(s
);
1250 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1251 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1252 pa_assert(min_latency
<= max_latency
);
1254 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1255 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1256 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1257 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1260 s
->thread_info
.min_latency
= min_latency
;
1261 s
->thread_info
.max_latency
= max_latency
;
1263 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1264 pa_source_output
*o
;
1266 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1267 if (o
->update_source_latency_range
)
1268 o
->update_source_latency_range(o
);
1271 pa_source_invalidate_requested_latency(s
);
1274 /* Called from main thread, before the source is put */
1275 void pa_source_set_fixed_latency(pa_source
*s
, pa_usec_t latency
) {
1276 pa_source_assert_ref(s
);
1278 pa_assert(pa_source_get_state(s
) == PA_SOURCE_INIT
);
1280 if (latency
< ABSOLUTE_MIN_LATENCY
)
1281 latency
= ABSOLUTE_MIN_LATENCY
;
1283 if (latency
> ABSOLUTE_MAX_LATENCY
)
1284 latency
= ABSOLUTE_MAX_LATENCY
;
1286 s
->fixed_latency
= latency
;
1289 /* Called from main thread */
1290 size_t pa_source_get_max_rewind(pa_source
*s
) {
1292 pa_source_assert_ref(s
);
1294 if (!PA_SOURCE_IS_LINKED(s
->state
))
1295 return s
->thread_info
.max_rewind
;
1297 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);