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 static PA_DEFINE_CHECK_TYPE(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(data
->volume
.channels
== data
->sample_spec
.channels
);
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
;
208 s
->suspend_cause
= 0;
209 s
->name
= pa_xstrdup(name
);
210 s
->proplist
= pa_proplist_copy(data
->proplist
);
211 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
212 s
->module
= data
->module
;
213 s
->card
= data
->card
;
215 s
->sample_spec
= data
->sample_spec
;
216 s
->channel_map
= data
->channel_map
;
218 s
->outputs
= pa_idxset_new(NULL
, NULL
);
220 s
->monitor_of
= NULL
;
222 s
->virtual_volume
= data
->volume
;
223 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
224 s
->base_volume
= PA_VOLUME_NORM
;
225 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
226 s
->muted
= data
->muted
;
227 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
229 s
->fixed_latency
= flags
& PA_SOURCE_DYNAMIC_LATENCY
? 0 : DEFAULT_FIXED_LATENCY
;
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
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
269 s
->thread_info
.soft_volume
= s
->soft_volume
;
270 s
->thread_info
.soft_muted
= s
->muted
;
271 s
->thread_info
.state
= s
->state
;
272 s
->thread_info
.max_rewind
= 0;
273 s
->thread_info
.requested_latency_valid
= FALSE
;
274 s
->thread_info
.requested_latency
= 0;
275 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
276 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
278 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
281 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
283 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
284 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
287 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
288 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
295 /* Called from main context */
296 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
298 pa_bool_t suspend_change
;
299 pa_source_state_t original_state
;
302 pa_assert_ctl_context();
304 if (s
->state
== state
)
307 original_state
= s
->state
;
310 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
311 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
314 if ((ret
= s
->set_state(s
, state
)) < 0)
318 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
321 s
->set_state(s
, original_state
);
328 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
329 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
330 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
333 if (suspend_change
) {
337 /* We're suspending or resuming, tell everyone about it */
339 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
)))
340 if (s
->state
== PA_SOURCE_SUSPENDED
&&
341 (o
->flags
& PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND
))
342 pa_source_output_kill(o
);
344 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
351 /* Called from main context */
352 void pa_source_put(pa_source
*s
) {
353 pa_source_assert_ref(s
);
354 pa_assert_ctl_context();
356 pa_assert(s
->state
== PA_SOURCE_INIT
);
358 /* The following fields must be initialized properly when calling _put() */
359 pa_assert(s
->asyncmsgq
);
360 pa_assert(s
->rtpoll
);
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
->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 */
468 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
469 pa_assert_ctl_context();
470 pa_source_assert_ref(s
);
475 /* Called from main context */
476 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
477 pa_assert_ctl_context();
478 pa_source_assert_ref(s
);
483 /* Called from main context */
484 int pa_source_update_status(pa_source
*s
) {
485 pa_source_assert_ref(s
);
486 pa_assert_ctl_context();
487 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
489 if (s
->state
== PA_SOURCE_SUSPENDED
)
492 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
495 /* Called from main context */
496 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
497 pa_source_assert_ref(s
);
498 pa_assert_ctl_context();
499 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
500 pa_assert(cause
!= 0);
503 return -PA_ERR_NOTSUPPORTED
;
506 s
->suspend_cause
|= cause
;
508 s
->suspend_cause
&= ~cause
;
510 if ((pa_source_get_state(s
) == PA_SOURCE_SUSPENDED
) == !!s
->suspend_cause
)
513 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s
->name
, s
->suspend_cause
, s
->suspend_cause
? "suspending" : "resuming");
516 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
518 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
521 /* Called from main context */
522 int pa_source_sync_suspend(pa_source
*s
) {
523 pa_sink_state_t state
;
525 pa_source_assert_ref(s
);
526 pa_assert_ctl_context();
527 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
528 pa_assert(s
->monitor_of
);
530 state
= pa_sink_get_state(s
->monitor_of
);
532 if (state
== PA_SINK_SUSPENDED
)
533 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
535 pa_assert(PA_SINK_IS_OPENED(state
));
537 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
540 /* Called from main context */
541 pa_queue
*pa_source_move_all_start(pa_source
*s
, pa_queue
*q
) {
542 pa_source_output
*o
, *n
;
545 pa_source_assert_ref(s
);
546 pa_assert_ctl_context();
547 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
552 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
553 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
555 pa_source_output_ref(o
);
557 if (pa_source_output_start_move(o
) >= 0)
560 pa_source_output_unref(o
);
566 /* Called from main context */
567 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
570 pa_source_assert_ref(s
);
571 pa_assert_ctl_context();
572 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
575 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
576 if (pa_source_output_finish_move(o
, s
, save
) < 0)
577 pa_source_output_kill(o
);
579 pa_source_output_unref(o
);
582 pa_queue_free(q
, NULL
, NULL
);
585 /* Called from main context */
586 void pa_source_move_all_fail(pa_queue
*q
) {
589 pa_assert_ctl_context();
592 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
593 if (pa_hook_fire(&o
->core
->hooks
[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL
], o
) == PA_HOOK_OK
) {
594 pa_source_output_kill(o
);
595 pa_source_output_unref(o
);
599 pa_queue_free(q
, NULL
, NULL
);
602 /* Called from IO thread context */
603 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
607 pa_source_assert_ref(s
);
608 pa_source_assert_io_context(s
);
609 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
614 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
617 pa_log_debug("Processing rewind...");
619 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
) {
620 pa_source_output_assert_ref(o
);
621 pa_source_output_process_rewind(o
, nbytes
);
625 /* Called from IO thread context */
626 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
630 pa_source_assert_ref(s
);
631 pa_source_assert_io_context(s
);
632 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
635 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
638 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
639 pa_memchunk vchunk
= *chunk
;
641 pa_memblock_ref(vchunk
.memblock
);
642 pa_memchunk_make_writable(&vchunk
, 0);
644 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
645 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
647 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
649 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
650 pa_source_output_assert_ref(o
);
652 if (!o
->thread_info
.direct_on_input
)
653 pa_source_output_push(o
, &vchunk
);
656 pa_memblock_unref(vchunk
.memblock
);
659 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
660 pa_source_output_assert_ref(o
);
662 if (!o
->thread_info
.direct_on_input
)
663 pa_source_output_push(o
, chunk
);
668 /* Called from IO thread context */
669 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
670 pa_source_assert_ref(s
);
671 pa_source_assert_io_context(s
);
672 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
673 pa_source_output_assert_ref(o
);
674 pa_assert(o
->thread_info
.direct_on_input
);
677 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
680 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
681 pa_memchunk vchunk
= *chunk
;
683 pa_memblock_ref(vchunk
.memblock
);
684 pa_memchunk_make_writable(&vchunk
, 0);
686 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
687 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
689 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
691 pa_source_output_push(o
, &vchunk
);
693 pa_memblock_unref(vchunk
.memblock
);
695 pa_source_output_push(o
, chunk
);
698 /* Called from main thread */
699 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
702 pa_source_assert_ref(s
);
703 pa_assert_ctl_context();
704 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
706 if (s
->state
== PA_SOURCE_SUSPENDED
)
709 if (!(s
->flags
& PA_SOURCE_LATENCY
))
712 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
717 /* Called from IO thread */
718 pa_usec_t
pa_source_get_latency_within_thread(pa_source
*s
) {
722 pa_source_assert_ref(s
);
723 pa_source_assert_io_context(s
);
724 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
726 /* The returned value is supposed to be in the time domain of the sound card! */
728 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
731 if (!(s
->flags
& PA_SOURCE_LATENCY
))
736 /* We probably should make this a proper vtable callback instead of going through process_msg() */
738 if (o
->process_msg(o
, PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
744 /* Called from main thread */
745 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
, pa_bool_t save
) {
746 pa_cvolume old_virtual_volume
;
747 pa_bool_t virtual_volume_changed
;
749 pa_source_assert_ref(s
);
750 pa_assert_ctl_context();
751 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
753 pa_assert(pa_cvolume_valid(volume
));
754 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
756 old_virtual_volume
= s
->virtual_volume
;
757 s
->virtual_volume
= *volume
;
758 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
759 s
->save_volume
= (!virtual_volume_changed
&& s
->save_volume
) || save
;
762 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
765 s
->soft_volume
= s
->virtual_volume
;
767 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
769 if (virtual_volume_changed
)
770 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
773 /* Called from main thread. Only to be called by source implementor */
774 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
775 pa_source_assert_ref(s
);
776 pa_assert_ctl_context();
779 if (PA_SOURCE_IS_LINKED(s
->state
))
780 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
782 s
->thread_info
.soft_volume
= *volume
;
785 /* Called from main thread */
786 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
787 pa_source_assert_ref(s
);
788 pa_assert_ctl_context();
789 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
791 if (s
->refresh_volume
|| force_refresh
) {
792 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
797 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
799 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
)) {
800 s
->save_volume
= TRUE
;
801 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
805 return &s
->virtual_volume
;
808 /* Called from main thread */
809 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
810 pa_source_assert_ref(s
);
811 pa_assert_ctl_context();
812 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
814 /* The source implementor may call this if the volume changed to make sure everyone is notified */
816 if (pa_cvolume_equal(&s
->virtual_volume
, new_volume
))
819 s
->virtual_volume
= *new_volume
;
820 s
->save_volume
= TRUE
;
822 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
825 /* Called from main thread */
826 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
, pa_bool_t save
) {
829 pa_source_assert_ref(s
);
830 pa_assert_ctl_context();
831 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
833 old_muted
= s
->muted
;
835 s
->save_muted
= (old_muted
== s
->muted
&& s
->save_muted
) || save
;
840 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
842 if (old_muted
!= s
->muted
)
843 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
846 /* Called from main thread */
847 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
848 pa_source_assert_ref(s
);
849 pa_assert_ctl_context();
850 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
852 if (s
->refresh_muted
|| force_refresh
) {
853 pa_bool_t old_muted
= s
->muted
;
858 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
860 if (old_muted
!= s
->muted
) {
861 s
->save_muted
= TRUE
;
863 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
865 /* Make sure the soft mute status stays in sync */
866 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
873 /* Called from main thread */
874 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
875 pa_source_assert_ref(s
);
876 pa_assert_ctl_context();
877 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
879 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
881 if (s
->muted
== new_muted
)
884 s
->muted
= new_muted
;
885 s
->save_muted
= TRUE
;
887 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
890 /* Called from main thread */
891 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
892 pa_source_assert_ref(s
);
893 pa_assert_ctl_context();
896 pa_proplist_update(s
->proplist
, mode
, p
);
898 if (PA_SOURCE_IS_LINKED(s
->state
)) {
899 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
900 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
906 /* Called from main thread */
907 /* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
908 void pa_source_set_description(pa_source
*s
, const char *description
) {
910 pa_source_assert_ref(s
);
911 pa_assert_ctl_context();
913 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
916 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
918 if (old
&& description
&& pa_streq(old
, description
))
922 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
924 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
926 if (PA_SOURCE_IS_LINKED(s
->state
)) {
927 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
928 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
932 /* Called from main thread */
933 unsigned pa_source_linked_by(pa_source
*s
) {
934 pa_source_assert_ref(s
);
935 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
936 pa_assert_ctl_context();
938 return pa_idxset_size(s
->outputs
);
941 /* Called from main thread */
942 unsigned pa_source_used_by(pa_source
*s
) {
945 pa_source_assert_ref(s
);
946 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
947 pa_assert_ctl_context();
949 ret
= pa_idxset_size(s
->outputs
);
950 pa_assert(ret
>= s
->n_corked
);
952 return ret
- s
->n_corked
;
955 /* Called from main thread */
956 unsigned pa_source_check_suspend(pa_source
*s
) {
961 pa_source_assert_ref(s
);
962 pa_assert_ctl_context();
964 if (!PA_SOURCE_IS_LINKED(s
->state
))
969 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
) {
970 pa_source_output_state_t st
;
972 st
= pa_source_output_get_state(o
);
973 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
975 if (st
== PA_SOURCE_OUTPUT_CORKED
)
978 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
987 /* Called from IO thread, except when it is not */
988 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
989 pa_source
*s
= PA_SOURCE(object
);
990 pa_source_assert_ref(s
);
992 switch ((pa_source_message_t
) code
) {
994 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
995 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
997 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
999 if (o
->direct_on_input
) {
1000 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
1001 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
1004 pa_assert(!o
->thread_info
.attached
);
1005 o
->thread_info
.attached
= TRUE
;
1010 pa_source_output_set_state_within_thread(o
, o
->state
);
1012 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
1013 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1015 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1017 /* We don't just invalidate the requested latency here,
1018 * because if we are in a move we might need to fix up the
1019 * requested latency. */
1020 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1025 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
1026 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1028 pa_source_output_set_state_within_thread(o
, o
->state
);
1033 pa_assert(o
->thread_info
.attached
);
1034 o
->thread_info
.attached
= FALSE
;
1036 if (o
->thread_info
.direct_on_input
) {
1037 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
1038 o
->thread_info
.direct_on_input
= NULL
;
1041 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
1042 pa_source_output_unref(o
);
1044 pa_source_invalidate_requested_latency(s
);
1049 case PA_SOURCE_MESSAGE_SET_VOLUME
:
1050 s
->thread_info
.soft_volume
= s
->soft_volume
;
1053 case PA_SOURCE_MESSAGE_GET_VOLUME
:
1056 case PA_SOURCE_MESSAGE_SET_MUTE
:
1057 s
->thread_info
.soft_muted
= s
->muted
;
1060 case PA_SOURCE_MESSAGE_GET_MUTE
:
1063 case PA_SOURCE_MESSAGE_SET_STATE
: {
1065 pa_bool_t suspend_change
=
1066 (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
1067 (PA_SOURCE_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SOURCE_SUSPENDED
);
1069 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
1071 if (suspend_change
) {
1072 pa_source_output
*o
;
1075 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1076 if (o
->suspend_within_thread
)
1077 o
->suspend_within_thread(o
, s
->thread_info
.state
== PA_SOURCE_SUSPENDED
);
1084 case PA_SOURCE_MESSAGE_DETACH
:
1086 /* Detach all streams */
1087 pa_source_detach_within_thread(s
);
1090 case PA_SOURCE_MESSAGE_ATTACH
:
1092 /* Reattach all streams */
1093 pa_source_attach_within_thread(s
);
1096 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
1098 pa_usec_t
*usec
= userdata
;
1099 *usec
= pa_source_get_requested_latency_within_thread(s
);
1101 if (*usec
== (pa_usec_t
) -1)
1102 *usec
= s
->thread_info
.max_latency
;
1107 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
1108 pa_usec_t
*r
= userdata
;
1110 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
1115 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
1116 pa_usec_t
*r
= userdata
;
1118 r
[0] = s
->thread_info
.min_latency
;
1119 r
[1] = s
->thread_info
.max_latency
;
1124 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
1126 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1129 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
1131 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
1134 case PA_SOURCE_MESSAGE_GET_LATENCY
:
1136 if (s
->monitor_of
) {
1137 *((pa_usec_t
*) userdata
) = 0;
1141 /* Implementors need to overwrite this implementation! */
1144 case PA_SOURCE_MESSAGE_MAX
:
1151 /* Called from main thread */
1152 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
1157 pa_core_assert_ref(c
);
1158 pa_assert_ctl_context();
1159 pa_assert(cause
!= 0);
1161 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1164 if (source
->monitor_of
)
1167 if ((r
= pa_source_suspend(source
, suspend
, cause
)) < 0)
1174 /* Called from main thread */
1175 void pa_source_detach(pa_source
*s
) {
1176 pa_source_assert_ref(s
);
1177 pa_assert_ctl_context();
1178 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1180 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1183 /* Called from main thread */
1184 void pa_source_attach(pa_source
*s
) {
1185 pa_source_assert_ref(s
);
1186 pa_assert_ctl_context();
1187 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1189 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1192 /* Called from IO thread */
1193 void pa_source_detach_within_thread(pa_source
*s
) {
1194 pa_source_output
*o
;
1197 pa_source_assert_ref(s
);
1198 pa_source_assert_io_context(s
);
1199 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1201 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1206 /* Called from IO thread */
1207 void pa_source_attach_within_thread(pa_source
*s
) {
1208 pa_source_output
*o
;
1211 pa_source_assert_ref(s
);
1212 pa_source_assert_io_context(s
);
1213 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1215 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1220 /* Called from IO thread */
1221 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1222 pa_usec_t result
= (pa_usec_t
) -1;
1223 pa_source_output
*o
;
1226 pa_source_assert_ref(s
);
1227 pa_source_assert_io_context(s
);
1229 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1230 return PA_CLAMP(s
->fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1232 if (s
->thread_info
.requested_latency_valid
)
1233 return s
->thread_info
.requested_latency
;
1235 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1237 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1238 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1239 result
= o
->thread_info
.requested_source_latency
;
1241 if (result
!= (pa_usec_t
) -1)
1242 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1244 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1245 /* Only cache this if we are fully set up */
1246 s
->thread_info
.requested_latency
= result
;
1247 s
->thread_info
.requested_latency_valid
= TRUE
;
1253 /* Called from main thread */
1254 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1257 pa_source_assert_ref(s
);
1258 pa_assert_ctl_context();
1259 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1261 if (s
->state
== PA_SOURCE_SUSPENDED
)
1264 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1269 /* Called from IO thread */
1270 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1271 pa_source_output
*o
;
1274 pa_source_assert_ref(s
);
1275 pa_source_assert_io_context(s
);
1277 if (max_rewind
== s
->thread_info
.max_rewind
)
1280 s
->thread_info
.max_rewind
= max_rewind
;
1282 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
))
1283 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1284 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1287 /* Called from main thread */
1288 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1289 pa_source_assert_ref(s
);
1290 pa_assert_ctl_context();
1292 if (PA_SOURCE_IS_LINKED(s
->state
))
1293 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1295 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1298 /* Called from IO thread */
1299 void pa_source_invalidate_requested_latency(pa_source
*s
) {
1300 pa_source_output
*o
;
1303 pa_source_assert_ref(s
);
1304 pa_source_assert_io_context(s
);
1306 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1309 s
->thread_info
.requested_latency_valid
= FALSE
;
1311 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1313 if (s
->update_requested_latency
)
1314 s
->update_requested_latency(s
);
1316 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1317 if (o
->update_source_requested_latency
)
1318 o
->update_source_requested_latency(o
);
1322 pa_sink_invalidate_requested_latency(s
->monitor_of
);
1325 /* Called from main thread */
1326 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1327 pa_source_assert_ref(s
);
1328 pa_assert_ctl_context();
1330 /* min_latency == 0: no limit
1331 * min_latency anything else: specified limit
1333 * Similar for max_latency */
1335 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1336 min_latency
= ABSOLUTE_MIN_LATENCY
;
1338 if (max_latency
<= 0 ||
1339 max_latency
> ABSOLUTE_MAX_LATENCY
)
1340 max_latency
= ABSOLUTE_MAX_LATENCY
;
1342 pa_assert(min_latency
<= max_latency
);
1344 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1345 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1346 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1347 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1349 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1355 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1357 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1360 /* Called from main thread */
1361 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1362 pa_source_assert_ref(s
);
1363 pa_assert_ctl_context();
1364 pa_assert(min_latency
);
1365 pa_assert(max_latency
);
1367 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1368 pa_usec_t r
[2] = { 0, 0 };
1370 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1372 *min_latency
= r
[0];
1373 *max_latency
= r
[1];
1375 *min_latency
= s
->thread_info
.min_latency
;
1376 *max_latency
= s
->thread_info
.max_latency
;
1380 /* Called from IO thread, and from main thread before pa_source_put() is called */
1381 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1384 pa_source_assert_ref(s
);
1385 pa_source_assert_io_context(s
);
1387 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1388 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1389 pa_assert(min_latency
<= max_latency
);
1391 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1392 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1393 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1394 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1397 s
->thread_info
.min_latency
= min_latency
;
1398 s
->thread_info
.max_latency
= max_latency
;
1400 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1401 pa_source_output
*o
;
1403 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1404 if (o
->update_source_latency_range
)
1405 o
->update_source_latency_range(o
);
1408 pa_source_invalidate_requested_latency(s
);
1411 /* Called from main thread, before the source is put */
1412 void pa_source_set_fixed_latency(pa_source
*s
, pa_usec_t latency
) {
1413 pa_source_assert_ref(s
);
1414 pa_assert_ctl_context();
1416 pa_assert(pa_source_get_state(s
) == PA_SOURCE_INIT
);
1418 if (latency
< ABSOLUTE_MIN_LATENCY
)
1419 latency
= ABSOLUTE_MIN_LATENCY
;
1421 if (latency
> ABSOLUTE_MAX_LATENCY
)
1422 latency
= ABSOLUTE_MAX_LATENCY
;
1424 s
->fixed_latency
= latency
;
1427 /* Called from main thread */
1428 size_t pa_source_get_max_rewind(pa_source
*s
) {
1430 pa_assert_ctl_context();
1431 pa_source_assert_ref(s
);
1433 if (!PA_SOURCE_IS_LINKED(s
->state
))
1434 return s
->thread_info
.max_rewind
;
1436 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);
1441 /* Called from main context */
1442 int pa_source_set_port(pa_source
*s
, const char *name
, pa_bool_t save
) {
1443 pa_device_port
*port
;
1446 pa_assert_ctl_context();
1449 pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s
->index
, s
->name
);
1450 return -PA_ERR_NOTIMPLEMENTED
;
1454 return -PA_ERR_NOENTITY
;
1456 if (!(port
= pa_hashmap_get(s
->ports
, name
)))
1457 return -PA_ERR_NOENTITY
;
1459 if (s
->active_port
== port
) {
1460 s
->save_port
= s
->save_port
|| save
;
1464 if ((s
->set_port(s
, port
)) < 0)
1465 return -PA_ERR_NOENTITY
;
1467 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1469 pa_log_info("Changed port of source %u \"%s\" to %s", s
->index
, s
->name
, port
->name
);
1471 s
->active_port
= port
;
1472 s
->save_port
= save
;