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/core-util.h>
37 #include <pulsecore/source-output.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/core-subscribe.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/sample-util.h>
45 #define ABSOLUTE_MIN_LATENCY (500)
46 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
47 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
49 PA_DEFINE_PUBLIC_CLASS(pa_source
, pa_msgobject
);
51 static void source_free(pa_object
*o
);
53 pa_source_new_data
* pa_source_new_data_init(pa_source_new_data
*data
) {
57 data
->proplist
= pa_proplist_new();
62 void pa_source_new_data_set_name(pa_source_new_data
*data
, const char *name
) {
66 data
->name
= pa_xstrdup(name
);
69 void pa_source_new_data_set_sample_spec(pa_source_new_data
*data
, const pa_sample_spec
*spec
) {
72 if ((data
->sample_spec_is_set
= !!spec
))
73 data
->sample_spec
= *spec
;
76 void pa_source_new_data_set_channel_map(pa_source_new_data
*data
, const pa_channel_map
*map
) {
79 if ((data
->channel_map_is_set
= !!map
))
80 data
->channel_map
= *map
;
83 void pa_source_new_data_set_volume(pa_source_new_data
*data
, const pa_cvolume
*volume
) {
86 if ((data
->volume_is_set
= !!volume
))
87 data
->volume
= *volume
;
90 void pa_source_new_data_set_muted(pa_source_new_data
*data
, pa_bool_t mute
) {
93 data
->muted_is_set
= TRUE
;
97 void pa_source_new_data_set_port(pa_source_new_data
*data
, const char *port
) {
100 pa_xfree(data
->active_port
);
101 data
->active_port
= pa_xstrdup(port
);
104 void pa_source_new_data_done(pa_source_new_data
*data
) {
107 pa_proplist_free(data
->proplist
);
112 while ((p
= pa_hashmap_steal_first(data
->ports
)))
113 pa_device_port_free(p
);
115 pa_hashmap_free(data
->ports
, NULL
, NULL
);
118 pa_xfree(data
->name
);
119 pa_xfree(data
->active_port
);
122 /* Called from main context */
123 static void reset_callbacks(pa_source
*s
) {
127 s
->get_volume
= NULL
;
128 s
->set_volume
= NULL
;
131 s
->update_requested_latency
= NULL
;
135 /* Called from main context */
136 pa_source
* pa_source_new(
138 pa_source_new_data
*data
,
139 pa_source_flags_t flags
) {
143 char st
[PA_SAMPLE_SPEC_SNPRINT_MAX
], cm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
148 pa_assert(data
->name
);
149 pa_assert_ctl_context();
151 s
= pa_msgobject_new(pa_source
);
153 if (!(name
= pa_namereg_register(core
, data
->name
, PA_NAMEREG_SOURCE
, s
, data
->namereg_fail
))) {
154 pa_log_debug("Failed to register name %s.", data
->name
);
159 pa_source_new_data_set_name(data
, name
);
161 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_NEW
], data
) < 0) {
163 pa_namereg_unregister(core
, name
);
167 /* FIXME, need to free s here on failure */
169 pa_return_null_if_fail(!data
->driver
|| pa_utf8_valid(data
->driver
));
170 pa_return_null_if_fail(data
->name
&& pa_utf8_valid(data
->name
) && data
->name
[0]);
172 pa_return_null_if_fail(data
->sample_spec_is_set
&& pa_sample_spec_valid(&data
->sample_spec
));
174 if (!data
->channel_map_is_set
)
175 pa_return_null_if_fail(pa_channel_map_init_auto(&data
->channel_map
, data
->sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
));
177 pa_return_null_if_fail(pa_channel_map_valid(&data
->channel_map
));
178 pa_return_null_if_fail(data
->channel_map
.channels
== data
->sample_spec
.channels
);
180 if (!data
->volume_is_set
)
181 pa_cvolume_reset(&data
->volume
, data
->sample_spec
.channels
);
183 pa_return_null_if_fail(pa_cvolume_valid(&data
->volume
));
184 pa_return_null_if_fail(pa_cvolume_compatible(&data
->volume
, &data
->sample_spec
));
186 if (!data
->muted_is_set
)
190 pa_proplist_update(data
->proplist
, PA_UPDATE_MERGE
, data
->card
->proplist
);
192 pa_device_init_description(data
->proplist
);
193 pa_device_init_icon(data
->proplist
, FALSE
);
194 pa_device_init_intended_roles(data
->proplist
);
196 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_FIXATE
], data
) < 0) {
198 pa_namereg_unregister(core
, name
);
202 s
->parent
.parent
.free
= source_free
;
203 s
->parent
.process_msg
= pa_source_process_msg
;
206 s
->state
= PA_SOURCE_INIT
;
209 s
->suspend_cause
= 0;
210 s
->name
= pa_xstrdup(name
);
211 s
->proplist
= pa_proplist_copy(data
->proplist
);
212 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
213 s
->module
= data
->module
;
214 s
->card
= data
->card
;
216 s
->priority
= pa_device_init_priority(s
->proplist
);
218 s
->sample_spec
= data
->sample_spec
;
219 s
->channel_map
= data
->channel_map
;
221 s
->outputs
= pa_idxset_new(NULL
, NULL
);
223 s
->monitor_of
= NULL
;
225 s
->volume
= data
->volume
;
226 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
227 s
->base_volume
= PA_VOLUME_NORM
;
228 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
229 s
->muted
= data
->muted
;
230 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
237 /* As a minor optimization we just steal the list instead of
239 s
->ports
= data
->ports
;
242 s
->active_port
= NULL
;
243 s
->save_port
= FALSE
;
245 if (data
->active_port
&& s
->ports
)
246 if ((s
->active_port
= pa_hashmap_get(s
->ports
, data
->active_port
)))
247 s
->save_port
= data
->save_port
;
249 if (!s
->active_port
&& s
->ports
) {
253 PA_HASHMAP_FOREACH(p
, s
->ports
, state
)
254 if (!s
->active_port
|| p
->priority
> s
->active_port
->priority
)
258 s
->save_volume
= data
->save_volume
;
259 s
->save_muted
= data
->save_muted
;
261 pa_silence_memchunk_get(
262 &core
->silence_cache
,
268 s
->thread_info
.rtpoll
= NULL
;
269 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
270 s
->thread_info
.soft_volume
= s
->soft_volume
;
271 s
->thread_info
.soft_muted
= s
->muted
;
272 s
->thread_info
.state
= s
->state
;
273 s
->thread_info
.max_rewind
= 0;
274 s
->thread_info
.requested_latency_valid
= FALSE
;
275 s
->thread_info
.requested_latency
= 0;
276 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
277 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
278 s
->thread_info
.fixed_latency
= flags
& PA_SOURCE_DYNAMIC_LATENCY
? 0 : DEFAULT_FIXED_LATENCY
;
280 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
283 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
285 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
286 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
289 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
290 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
297 /* Called from main context */
298 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
300 pa_bool_t suspend_change
;
301 pa_source_state_t original_state
;
304 pa_assert_ctl_context();
306 if (s
->state
== state
)
309 original_state
= s
->state
;
312 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
313 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
316 if ((ret
= s
->set_state(s
, state
)) < 0)
320 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
323 s
->set_state(s
, original_state
);
330 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
331 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
332 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
335 if (suspend_change
) {
339 /* We're suspending or resuming, tell everyone about it */
341 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
)
342 if (s
->state
== PA_SOURCE_SUSPENDED
&&
343 (o
->flags
& PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
))
344 pa_source_output_kill(o
);
346 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
352 /* Called from main context */
353 void pa_source_put(pa_source
*s
) {
354 pa_source_assert_ref(s
);
355 pa_assert_ctl_context();
357 pa_assert(s
->state
== PA_SOURCE_INIT
);
359 /* The following fields must be initialized properly when calling _put() */
360 pa_assert(s
->asyncmsgq
);
361 pa_assert(s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
363 /* Generally, flags should be initialized via pa_source_new(). As
364 * a special exception we allow volume related flags to be set
365 * between _new() and _put(). */
367 if (!(s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
))
368 s
->flags
|= PA_SOURCE_DECIBEL_VOLUME
;
370 s
->thread_info
.soft_volume
= s
->soft_volume
;
371 s
->thread_info
.soft_muted
= s
->muted
;
373 pa_assert((s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
) || (s
->base_volume
== PA_VOLUME_NORM
&& s
->flags
& PA_SOURCE_DECIBEL_VOLUME
));
374 pa_assert(!(s
->flags
& PA_SOURCE_DECIBEL_VOLUME
) || s
->n_volume_steps
== PA_VOLUME_NORM
+1);
375 pa_assert(!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) == (s
->thread_info
.fixed_latency
!= 0));
377 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
379 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
380 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
383 /* Called from main context */
384 void pa_source_unlink(pa_source
*s
) {
386 pa_source_output
*o
, *j
= NULL
;
389 pa_assert_ctl_context();
391 /* See pa_sink_unlink() for a couple of comments how this function
394 linked
= PA_SOURCE_IS_LINKED(s
->state
);
397 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
399 if (s
->state
!= PA_SOURCE_UNLINKED
)
400 pa_namereg_unregister(s
->core
, s
->name
);
401 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
404 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
406 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
408 pa_source_output_kill(o
);
413 source_set_state(s
, PA_SOURCE_UNLINKED
);
415 s
->state
= PA_SOURCE_UNLINKED
;
420 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
421 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
425 /* Called from main context */
426 static void source_free(pa_object
*o
) {
427 pa_source_output
*so
;
428 pa_source
*s
= PA_SOURCE(o
);
431 pa_assert_ctl_context();
432 pa_assert(pa_source_refcnt(s
) == 0);
434 if (PA_SOURCE_IS_LINKED(s
->state
))
437 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
439 pa_idxset_free(s
->outputs
, NULL
, NULL
);
441 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
442 pa_source_output_unref(so
);
444 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
446 if (s
->silence
.memblock
)
447 pa_memblock_unref(s
->silence
.memblock
);
453 pa_proplist_free(s
->proplist
);
458 while ((p
= pa_hashmap_steal_first(s
->ports
)))
459 pa_device_port_free(p
);
461 pa_hashmap_free(s
->ports
, NULL
, NULL
);
467 /* Called from main context, and not while the IO thread is active, please */
468 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
469 pa_source_assert_ref(s
);
470 pa_assert_ctl_context();
475 /* Called from main context, and not while the IO thread is active, please */
476 void pa_source_update_flags(pa_source
*s
, pa_source_flags_t mask
, pa_source_flags_t value
) {
477 pa_source_assert_ref(s
);
478 pa_assert_ctl_context();
483 /* For now, allow only a minimal set of flags to be changed. */
484 pa_assert((mask
& ~(PA_SOURCE_DYNAMIC_LATENCY
|PA_SOURCE_LATENCY
)) == 0);
486 s
->flags
= (s
->flags
& ~mask
) | (value
& mask
);
489 /* Called from IO context, or before _put() from main context */
490 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
491 pa_source_assert_ref(s
);
492 pa_source_assert_io_context(s
);
494 s
->thread_info
.rtpoll
= p
;
497 /* Called from main context */
498 int pa_source_update_status(pa_source
*s
) {
499 pa_source_assert_ref(s
);
500 pa_assert_ctl_context();
501 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
503 if (s
->state
== PA_SOURCE_SUSPENDED
)
506 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
509 /* Called from main context */
510 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
511 pa_source_assert_ref(s
);
512 pa_assert_ctl_context();
513 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
514 pa_assert(cause
!= 0);
517 return -PA_ERR_NOTSUPPORTED
;
520 s
->suspend_cause
|= cause
;
522 s
->suspend_cause
&= ~cause
;
524 if ((pa_source_get_state(s
) == PA_SOURCE_SUSPENDED
) == !!s
->suspend_cause
)
527 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s
->name
, s
->suspend_cause
, s
->suspend_cause
? "suspending" : "resuming");
530 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
532 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
535 /* Called from main context */
536 int pa_source_sync_suspend(pa_source
*s
) {
537 pa_sink_state_t state
;
539 pa_source_assert_ref(s
);
540 pa_assert_ctl_context();
541 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
542 pa_assert(s
->monitor_of
);
544 state
= pa_sink_get_state(s
->monitor_of
);
546 if (state
== PA_SINK_SUSPENDED
)
547 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
549 pa_assert(PA_SINK_IS_OPENED(state
));
551 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
554 /* Called from main context */
555 pa_queue
*pa_source_move_all_start(pa_source
*s
, pa_queue
*q
) {
556 pa_source_output
*o
, *n
;
559 pa_source_assert_ref(s
);
560 pa_assert_ctl_context();
561 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
566 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
567 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
569 pa_source_output_ref(o
);
571 if (pa_source_output_start_move(o
) >= 0)
574 pa_source_output_unref(o
);
580 /* Called from main context */
581 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
584 pa_source_assert_ref(s
);
585 pa_assert_ctl_context();
586 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
589 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
590 if (pa_source_output_finish_move(o
, s
, save
) < 0)
591 pa_source_output_fail_move(o
);
593 pa_source_output_unref(o
);
596 pa_queue_free(q
, NULL
, NULL
);
599 /* Called from main context */
600 void pa_source_move_all_fail(pa_queue
*q
) {
603 pa_assert_ctl_context();
606 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
607 pa_source_output_fail_move(o
);
608 pa_source_output_unref(o
);
611 pa_queue_free(q
, NULL
, NULL
);
614 /* Called from IO thread context */
615 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
619 pa_source_assert_ref(s
);
620 pa_source_assert_io_context(s
);
621 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
626 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
629 pa_log_debug("Processing rewind...");
631 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
) {
632 pa_source_output_assert_ref(o
);
633 pa_source_output_process_rewind(o
, nbytes
);
637 /* Called from IO thread context */
638 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
642 pa_source_assert_ref(s
);
643 pa_source_assert_io_context(s
);
644 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
647 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
650 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
651 pa_memchunk vchunk
= *chunk
;
653 pa_memblock_ref(vchunk
.memblock
);
654 pa_memchunk_make_writable(&vchunk
, 0);
656 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
657 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
659 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
661 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
662 pa_source_output_assert_ref(o
);
664 if (!o
->thread_info
.direct_on_input
)
665 pa_source_output_push(o
, &vchunk
);
668 pa_memblock_unref(vchunk
.memblock
);
671 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
672 pa_source_output_assert_ref(o
);
674 if (!o
->thread_info
.direct_on_input
)
675 pa_source_output_push(o
, chunk
);
680 /* Called from IO thread context */
681 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
682 pa_source_assert_ref(s
);
683 pa_source_assert_io_context(s
);
684 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
685 pa_source_output_assert_ref(o
);
686 pa_assert(o
->thread_info
.direct_on_input
);
689 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
692 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
693 pa_memchunk vchunk
= *chunk
;
695 pa_memblock_ref(vchunk
.memblock
);
696 pa_memchunk_make_writable(&vchunk
, 0);
698 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
699 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
701 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
703 pa_source_output_push(o
, &vchunk
);
705 pa_memblock_unref(vchunk
.memblock
);
707 pa_source_output_push(o
, chunk
);
710 /* Called from main thread */
711 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
714 pa_source_assert_ref(s
);
715 pa_assert_ctl_context();
716 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
718 if (s
->state
== PA_SOURCE_SUSPENDED
)
721 if (!(s
->flags
& PA_SOURCE_LATENCY
))
724 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
729 /* Called from IO thread */
730 pa_usec_t
pa_source_get_latency_within_thread(pa_source
*s
) {
734 pa_source_assert_ref(s
);
735 pa_source_assert_io_context(s
);
736 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
738 /* The returned value is supposed to be in the time domain of the sound card! */
740 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
743 if (!(s
->flags
& PA_SOURCE_LATENCY
))
748 /* We probably should make this a proper vtable callback instead of going through process_msg() */
750 if (o
->process_msg(o
, PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
756 /* Called from main thread */
757 void pa_source_set_volume(
759 const pa_cvolume
*volume
,
762 pa_bool_t real_changed
;
763 pa_cvolume old_volume
;
765 pa_source_assert_ref(s
);
766 pa_assert_ctl_context();
767 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
768 pa_assert(pa_cvolume_valid(volume
));
769 pa_assert(volume
->channels
== 1 || pa_cvolume_compatible(volume
, &s
->sample_spec
));
771 old_volume
= s
->volume
;
773 if (pa_cvolume_compatible(volume
, &s
->sample_spec
))
776 pa_cvolume_scale(&s
->volume
, pa_cvolume_max(volume
));
778 real_changed
= !pa_cvolume_equal(&old_volume
, &s
->volume
);
779 s
->save_volume
= (!real_changed
&& s
->save_volume
) || save
;
782 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
785 s
->soft_volume
= s
->volume
;
787 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
790 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
793 /* Called from main thread. Only to be called by source implementor */
794 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
795 pa_source_assert_ref(s
);
796 pa_assert_ctl_context();
799 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
801 s
->soft_volume
= *volume
;
803 if (PA_SOURCE_IS_LINKED(s
->state
))
804 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
806 s
->thread_info
.soft_volume
= s
->soft_volume
;
809 /* Called from main thread */
810 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
811 pa_source_assert_ref(s
);
812 pa_assert_ctl_context();
813 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
815 if (s
->refresh_volume
|| force_refresh
) {
816 pa_cvolume old_volume
;
818 old_volume
= s
->volume
;
823 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
825 if (!pa_cvolume_equal(&old_volume
, &s
->volume
)) {
826 s
->save_volume
= TRUE
;
827 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
834 /* Called from main thread */
835 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
836 pa_source_assert_ref(s
);
837 pa_assert_ctl_context();
838 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
840 /* The source implementor may call this if the volume changed to make sure everyone is notified */
842 if (pa_cvolume_equal(&s
->volume
, new_volume
))
845 s
->volume
= *new_volume
;
846 s
->save_volume
= TRUE
;
848 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
851 /* Called from main thread */
852 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
, pa_bool_t save
) {
855 pa_source_assert_ref(s
);
856 pa_assert_ctl_context();
857 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
859 old_muted
= s
->muted
;
861 s
->save_muted
= (old_muted
== s
->muted
&& s
->save_muted
) || save
;
866 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
868 if (old_muted
!= s
->muted
)
869 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
872 /* Called from main thread */
873 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
874 pa_source_assert_ref(s
);
875 pa_assert_ctl_context();
876 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
878 if (s
->refresh_muted
|| force_refresh
) {
879 pa_bool_t old_muted
= s
->muted
;
884 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
886 if (old_muted
!= s
->muted
) {
887 s
->save_muted
= TRUE
;
889 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
891 /* Make sure the soft mute status stays in sync */
892 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
899 /* Called from main thread */
900 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
901 pa_source_assert_ref(s
);
902 pa_assert_ctl_context();
903 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
905 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
907 if (s
->muted
== new_muted
)
910 s
->muted
= new_muted
;
911 s
->save_muted
= TRUE
;
913 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
916 /* Called from main thread */
917 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
918 pa_source_assert_ref(s
);
919 pa_assert_ctl_context();
922 pa_proplist_update(s
->proplist
, mode
, p
);
924 if (PA_SOURCE_IS_LINKED(s
->state
)) {
925 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
926 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
932 /* Called from main thread */
933 /* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
934 void pa_source_set_description(pa_source
*s
, const char *description
) {
936 pa_source_assert_ref(s
);
937 pa_assert_ctl_context();
939 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
942 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
944 if (old
&& description
&& pa_streq(old
, description
))
948 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
950 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
952 if (PA_SOURCE_IS_LINKED(s
->state
)) {
953 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
954 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
958 /* Called from main thread */
959 unsigned pa_source_linked_by(pa_source
*s
) {
960 pa_source_assert_ref(s
);
961 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
962 pa_assert_ctl_context();
964 return pa_idxset_size(s
->outputs
);
967 /* Called from main thread */
968 unsigned pa_source_used_by(pa_source
*s
) {
971 pa_source_assert_ref(s
);
972 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
973 pa_assert_ctl_context();
975 ret
= pa_idxset_size(s
->outputs
);
976 pa_assert(ret
>= s
->n_corked
);
978 return ret
- s
->n_corked
;
981 /* Called from main thread */
982 unsigned pa_source_check_suspend(pa_source
*s
) {
987 pa_source_assert_ref(s
);
988 pa_assert_ctl_context();
990 if (!PA_SOURCE_IS_LINKED(s
->state
))
995 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
) {
996 pa_source_output_state_t st
;
998 st
= pa_source_output_get_state(o
);
1000 /* We do not assert here. It is perfectly valid for a source output to
1001 * be in the INIT state (i.e. created, marked done but not yet put)
1002 * and we should not care if it's unlinked as it won't contribute
1003 * towarards our busy status.
1005 if (!PA_SOURCE_OUTPUT_IS_LINKED(st
))
1008 if (st
== PA_SOURCE_OUTPUT_CORKED
)
1011 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
1020 /* Called from IO thread, except when it is not */
1021 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1022 pa_source
*s
= PA_SOURCE(object
);
1023 pa_source_assert_ref(s
);
1025 switch ((pa_source_message_t
) code
) {
1027 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
1028 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1030 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
1032 if (o
->direct_on_input
) {
1033 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
1034 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
1037 pa_assert(!o
->thread_info
.attached
);
1038 o
->thread_info
.attached
= TRUE
;
1043 pa_source_output_set_state_within_thread(o
, o
->state
);
1045 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
1046 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1048 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1050 /* We don't just invalidate the requested latency here,
1051 * because if we are in a move we might need to fix up the
1052 * requested latency. */
1053 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1058 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
1059 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1061 pa_source_output_set_state_within_thread(o
, o
->state
);
1066 pa_assert(o
->thread_info
.attached
);
1067 o
->thread_info
.attached
= FALSE
;
1069 if (o
->thread_info
.direct_on_input
) {
1070 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
1071 o
->thread_info
.direct_on_input
= NULL
;
1074 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
1075 pa_source_output_unref(o
);
1077 pa_source_invalidate_requested_latency(s
, TRUE
);
1082 case PA_SOURCE_MESSAGE_SET_VOLUME
:
1083 s
->thread_info
.soft_volume
= s
->soft_volume
;
1086 case PA_SOURCE_MESSAGE_GET_VOLUME
:
1089 case PA_SOURCE_MESSAGE_SET_MUTE
:
1090 s
->thread_info
.soft_muted
= s
->muted
;
1093 case PA_SOURCE_MESSAGE_GET_MUTE
:
1096 case PA_SOURCE_MESSAGE_SET_STATE
: {
1098 pa_bool_t suspend_change
=
1099 (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
1100 (PA_SOURCE_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SOURCE_SUSPENDED
);
1102 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
1104 if (suspend_change
) {
1105 pa_source_output
*o
;
1108 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1109 if (o
->suspend_within_thread
)
1110 o
->suspend_within_thread(o
, s
->thread_info
.state
== PA_SOURCE_SUSPENDED
);
1117 case PA_SOURCE_MESSAGE_DETACH
:
1119 /* Detach all streams */
1120 pa_source_detach_within_thread(s
);
1123 case PA_SOURCE_MESSAGE_ATTACH
:
1125 /* Reattach all streams */
1126 pa_source_attach_within_thread(s
);
1129 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
1131 pa_usec_t
*usec
= userdata
;
1132 *usec
= pa_source_get_requested_latency_within_thread(s
);
1134 if (*usec
== (pa_usec_t
) -1)
1135 *usec
= s
->thread_info
.max_latency
;
1140 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
1141 pa_usec_t
*r
= userdata
;
1143 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
1148 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
1149 pa_usec_t
*r
= userdata
;
1151 r
[0] = s
->thread_info
.min_latency
;
1152 r
[1] = s
->thread_info
.max_latency
;
1157 case PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
:
1159 *((pa_usec_t
*) userdata
) = s
->thread_info
.fixed_latency
;
1162 case PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
:
1164 pa_source_set_fixed_latency_within_thread(s
, (pa_usec_t
) offset
);
1167 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
1169 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1172 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
1174 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
1177 case PA_SOURCE_MESSAGE_GET_LATENCY
:
1179 if (s
->monitor_of
) {
1180 *((pa_usec_t
*) userdata
) = 0;
1184 /* Implementors need to overwrite this implementation! */
1187 case PA_SOURCE_MESSAGE_MAX
:
1194 /* Called from main thread */
1195 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
1200 pa_core_assert_ref(c
);
1201 pa_assert_ctl_context();
1202 pa_assert(cause
!= 0);
1204 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1207 if (source
->monitor_of
)
1210 if ((r
= pa_source_suspend(source
, suspend
, cause
)) < 0)
1217 /* Called from main thread */
1218 void pa_source_detach(pa_source
*s
) {
1219 pa_source_assert_ref(s
);
1220 pa_assert_ctl_context();
1221 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1223 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1226 /* Called from main thread */
1227 void pa_source_attach(pa_source
*s
) {
1228 pa_source_assert_ref(s
);
1229 pa_assert_ctl_context();
1230 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1232 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1235 /* Called from IO thread */
1236 void pa_source_detach_within_thread(pa_source
*s
) {
1237 pa_source_output
*o
;
1240 pa_source_assert_ref(s
);
1241 pa_source_assert_io_context(s
);
1242 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1244 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1249 /* Called from IO thread */
1250 void pa_source_attach_within_thread(pa_source
*s
) {
1251 pa_source_output
*o
;
1254 pa_source_assert_ref(s
);
1255 pa_source_assert_io_context(s
);
1256 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1258 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1263 /* Called from IO thread */
1264 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1265 pa_usec_t result
= (pa_usec_t
) -1;
1266 pa_source_output
*o
;
1269 pa_source_assert_ref(s
);
1270 pa_source_assert_io_context(s
);
1272 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1273 return PA_CLAMP(s
->thread_info
.fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1275 if (s
->thread_info
.requested_latency_valid
)
1276 return s
->thread_info
.requested_latency
;
1278 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1279 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1280 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1281 result
= o
->thread_info
.requested_source_latency
;
1283 if (result
!= (pa_usec_t
) -1)
1284 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1286 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1287 /* Only cache this if we are fully set up */
1288 s
->thread_info
.requested_latency
= result
;
1289 s
->thread_info
.requested_latency_valid
= TRUE
;
1295 /* Called from main thread */
1296 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1299 pa_source_assert_ref(s
);
1300 pa_assert_ctl_context();
1301 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1303 if (s
->state
== PA_SOURCE_SUSPENDED
)
1306 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1311 /* Called from IO thread */
1312 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1313 pa_source_output
*o
;
1316 pa_source_assert_ref(s
);
1317 pa_source_assert_io_context(s
);
1319 if (max_rewind
== s
->thread_info
.max_rewind
)
1322 s
->thread_info
.max_rewind
= max_rewind
;
1324 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
))
1325 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1326 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1329 /* Called from main thread */
1330 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1331 pa_source_assert_ref(s
);
1332 pa_assert_ctl_context();
1334 if (PA_SOURCE_IS_LINKED(s
->state
))
1335 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1337 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1340 /* Called from IO thread */
1341 void pa_source_invalidate_requested_latency(pa_source
*s
, pa_bool_t dynamic
) {
1342 pa_source_output
*o
;
1345 pa_source_assert_ref(s
);
1346 pa_source_assert_io_context(s
);
1348 if ((s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1349 s
->thread_info
.requested_latency_valid
= FALSE
;
1353 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1355 if (s
->update_requested_latency
)
1356 s
->update_requested_latency(s
);
1358 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1359 if (o
->update_source_requested_latency
)
1360 o
->update_source_requested_latency(o
);
1364 pa_sink_invalidate_requested_latency(s
->monitor_of
, dynamic
);
1367 /* Called from main thread */
1368 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1369 pa_source_assert_ref(s
);
1370 pa_assert_ctl_context();
1372 /* min_latency == 0: no limit
1373 * min_latency anything else: specified limit
1375 * Similar for max_latency */
1377 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1378 min_latency
= ABSOLUTE_MIN_LATENCY
;
1380 if (max_latency
<= 0 ||
1381 max_latency
> ABSOLUTE_MAX_LATENCY
)
1382 max_latency
= ABSOLUTE_MAX_LATENCY
;
1384 pa_assert(min_latency
<= max_latency
);
1386 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1387 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1388 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1389 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1391 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1397 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1399 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1402 /* Called from main thread */
1403 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1404 pa_source_assert_ref(s
);
1405 pa_assert_ctl_context();
1406 pa_assert(min_latency
);
1407 pa_assert(max_latency
);
1409 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1410 pa_usec_t r
[2] = { 0, 0 };
1412 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1414 *min_latency
= r
[0];
1415 *max_latency
= r
[1];
1417 *min_latency
= s
->thread_info
.min_latency
;
1418 *max_latency
= s
->thread_info
.max_latency
;
1422 /* Called from IO thread, and from main thread before pa_source_put() is called */
1423 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1424 pa_source_assert_ref(s
);
1425 pa_source_assert_io_context(s
);
1427 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1428 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1429 pa_assert(min_latency
<= max_latency
);
1431 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1432 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1433 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1434 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1437 if (s
->thread_info
.min_latency
== min_latency
&&
1438 s
->thread_info
.max_latency
== max_latency
)
1441 s
->thread_info
.min_latency
= min_latency
;
1442 s
->thread_info
.max_latency
= max_latency
;
1444 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1445 pa_source_output
*o
;
1448 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1449 if (o
->update_source_latency_range
)
1450 o
->update_source_latency_range(o
);
1453 pa_source_invalidate_requested_latency(s
, FALSE
);
1456 /* Called from main thread, before the source is put */
1457 void pa_source_set_fixed_latency(pa_source
*s
, pa_usec_t latency
) {
1458 pa_source_assert_ref(s
);
1459 pa_assert_ctl_context();
1461 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1462 pa_assert(latency
== 0);
1466 if (latency
< ABSOLUTE_MIN_LATENCY
)
1467 latency
= ABSOLUTE_MIN_LATENCY
;
1469 if (latency
> ABSOLUTE_MAX_LATENCY
)
1470 latency
= ABSOLUTE_MAX_LATENCY
;
1472 if (PA_SOURCE_IS_LINKED(s
->state
))
1473 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
, NULL
, (int64_t) latency
, NULL
) == 0);
1475 s
->thread_info
.fixed_latency
= latency
;
1478 /* Called from main thread */
1479 pa_usec_t
pa_source_get_fixed_latency(pa_source
*s
) {
1482 pa_source_assert_ref(s
);
1483 pa_assert_ctl_context();
1485 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
)
1488 if (PA_SOURCE_IS_LINKED(s
->state
))
1489 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
, &latency
, 0, NULL
) == 0);
1491 latency
= s
->thread_info
.fixed_latency
;
1496 /* Called from IO thread */
1497 void pa_source_set_fixed_latency_within_thread(pa_source
*s
, pa_usec_t latency
) {
1498 pa_source_assert_ref(s
);
1499 pa_source_assert_io_context(s
);
1501 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1502 pa_assert(latency
== 0);
1506 pa_assert(latency
>= ABSOLUTE_MIN_LATENCY
);
1507 pa_assert(latency
<= ABSOLUTE_MAX_LATENCY
);
1509 if (s
->thread_info
.fixed_latency
== latency
)
1512 s
->thread_info
.fixed_latency
= latency
;
1514 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1515 pa_source_output
*o
;
1518 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1519 if (o
->update_source_fixed_latency
)
1520 o
->update_source_fixed_latency(o
);
1523 pa_source_invalidate_requested_latency(s
, FALSE
);
1526 /* Called from main thread */
1527 size_t pa_source_get_max_rewind(pa_source
*s
) {
1529 pa_assert_ctl_context();
1530 pa_source_assert_ref(s
);
1532 if (!PA_SOURCE_IS_LINKED(s
->state
))
1533 return s
->thread_info
.max_rewind
;
1535 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);
1540 /* Called from main context */
1541 int pa_source_set_port(pa_source
*s
, const char *name
, pa_bool_t save
) {
1542 pa_device_port
*port
;
1545 pa_assert_ctl_context();
1548 pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s
->index
, s
->name
);
1549 return -PA_ERR_NOTIMPLEMENTED
;
1553 return -PA_ERR_NOENTITY
;
1555 if (!(port
= pa_hashmap_get(s
->ports
, name
)))
1556 return -PA_ERR_NOENTITY
;
1558 if (s
->active_port
== port
) {
1559 s
->save_port
= s
->save_port
|| save
;
1563 if ((s
->set_port(s
, port
)) < 0)
1564 return -PA_ERR_NOENTITY
;
1566 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1568 pa_log_info("Changed port of source %u \"%s\" to %s", s
->index
, s
->name
, port
->name
);
1570 s
->active_port
= port
;
1571 s
->save_port
= save
;