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
;
234 /* As a minor optimization we just steal the list instead of
236 s
->ports
= data
->ports
;
239 s
->active_port
= NULL
;
240 s
->save_port
= FALSE
;
242 if (data
->active_port
&& s
->ports
)
243 if ((s
->active_port
= pa_hashmap_get(s
->ports
, data
->active_port
)))
244 s
->save_port
= data
->save_port
;
246 if (!s
->active_port
&& s
->ports
) {
250 PA_HASHMAP_FOREACH(p
, s
->ports
, state
)
251 if (!s
->active_port
|| p
->priority
> s
->active_port
->priority
)
255 s
->save_volume
= data
->save_volume
;
256 s
->save_muted
= data
->save_muted
;
258 pa_silence_memchunk_get(
259 &core
->silence_cache
,
265 s
->thread_info
.rtpoll
= NULL
;
266 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
267 s
->thread_info
.soft_volume
= s
->soft_volume
;
268 s
->thread_info
.soft_muted
= s
->muted
;
269 s
->thread_info
.state
= s
->state
;
270 s
->thread_info
.max_rewind
= 0;
271 s
->thread_info
.requested_latency_valid
= FALSE
;
272 s
->thread_info
.requested_latency
= 0;
273 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
274 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
275 s
->thread_info
.fixed_latency
= flags
& PA_SOURCE_DYNAMIC_LATENCY
? 0 : DEFAULT_FIXED_LATENCY
;
277 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
280 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
282 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
283 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
286 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
287 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
294 /* Called from main context */
295 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
297 pa_bool_t suspend_change
;
298 pa_source_state_t original_state
;
301 pa_assert_ctl_context();
303 if (s
->state
== state
)
306 original_state
= s
->state
;
309 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
310 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
313 if ((ret
= s
->set_state(s
, state
)) < 0)
317 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
320 s
->set_state(s
, original_state
);
327 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
328 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
329 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
332 if (suspend_change
) {
336 /* We're suspending or resuming, tell everyone about it */
338 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
)
339 if (s
->state
== PA_SOURCE_SUSPENDED
&&
340 (o
->flags
& PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
))
341 pa_source_output_kill(o
);
343 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
349 /* Called from main context */
350 void pa_source_put(pa_source
*s
) {
351 pa_source_assert_ref(s
);
352 pa_assert_ctl_context();
354 pa_assert(s
->state
== PA_SOURCE_INIT
);
356 /* The following fields must be initialized properly when calling _put() */
357 pa_assert(s
->asyncmsgq
);
358 pa_assert(s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
360 /* Generally, flags should be initialized via pa_source_new(). As
361 * a special exception we allow volume related flags to be set
362 * between _new() and _put(). */
364 if (!(s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
))
365 s
->flags
|= PA_SOURCE_DECIBEL_VOLUME
;
367 s
->thread_info
.soft_volume
= s
->soft_volume
;
368 s
->thread_info
.soft_muted
= s
->muted
;
370 pa_assert((s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
) || (s
->base_volume
== PA_VOLUME_NORM
&& s
->flags
& PA_SOURCE_DECIBEL_VOLUME
));
371 pa_assert(!(s
->flags
& PA_SOURCE_DECIBEL_VOLUME
) || s
->n_volume_steps
== PA_VOLUME_NORM
+1);
372 pa_assert(!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) == (s
->thread_info
.fixed_latency
!= 0));
374 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
376 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
377 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
380 /* Called from main context */
381 void pa_source_unlink(pa_source
*s
) {
383 pa_source_output
*o
, *j
= NULL
;
386 pa_assert_ctl_context();
388 /* See pa_sink_unlink() for a couple of comments how this function
391 linked
= PA_SOURCE_IS_LINKED(s
->state
);
394 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
396 if (s
->state
!= PA_SOURCE_UNLINKED
)
397 pa_namereg_unregister(s
->core
, s
->name
);
398 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
401 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
403 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
405 pa_source_output_kill(o
);
410 source_set_state(s
, PA_SOURCE_UNLINKED
);
412 s
->state
= PA_SOURCE_UNLINKED
;
417 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
418 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
422 /* Called from main context */
423 static void source_free(pa_object
*o
) {
424 pa_source_output
*so
;
425 pa_source
*s
= PA_SOURCE(o
);
428 pa_assert_ctl_context();
429 pa_assert(pa_source_refcnt(s
) == 0);
431 if (PA_SOURCE_IS_LINKED(s
->state
))
434 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
436 pa_idxset_free(s
->outputs
, NULL
, NULL
);
438 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
439 pa_source_output_unref(so
);
441 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
443 if (s
->silence
.memblock
)
444 pa_memblock_unref(s
->silence
.memblock
);
450 pa_proplist_free(s
->proplist
);
455 while ((p
= pa_hashmap_steal_first(s
->ports
)))
456 pa_device_port_free(p
);
458 pa_hashmap_free(s
->ports
, NULL
, NULL
);
464 /* Called from main context, and not while the IO thread is active, please */
465 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
466 pa_source_assert_ref(s
);
467 pa_assert_ctl_context();
472 /* Called from main context, and not while the IO thread is active, please */
473 void pa_source_update_flags(pa_source
*s
, pa_source_flags_t mask
, pa_source_flags_t value
) {
474 pa_source_assert_ref(s
);
475 pa_assert_ctl_context();
480 /* For now, allow only a minimal set of flags to be changed. */
481 pa_assert((mask
& ~(PA_SOURCE_DYNAMIC_LATENCY
|PA_SOURCE_LATENCY
)) == 0);
483 s
->flags
= (s
->flags
& ~mask
) | (value
& mask
);
486 /* Called from IO context, or before _put() from main context */
487 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
488 pa_source_assert_ref(s
);
489 pa_source_assert_io_context(s
);
491 s
->thread_info
.rtpoll
= p
;
494 /* Called from main context */
495 int pa_source_update_status(pa_source
*s
) {
496 pa_source_assert_ref(s
);
497 pa_assert_ctl_context();
498 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
500 if (s
->state
== PA_SOURCE_SUSPENDED
)
503 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
506 /* Called from main context */
507 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
508 pa_source_assert_ref(s
);
509 pa_assert_ctl_context();
510 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
511 pa_assert(cause
!= 0);
514 return -PA_ERR_NOTSUPPORTED
;
517 s
->suspend_cause
|= cause
;
519 s
->suspend_cause
&= ~cause
;
521 if ((pa_source_get_state(s
) == PA_SOURCE_SUSPENDED
) == !!s
->suspend_cause
)
524 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s
->name
, s
->suspend_cause
, s
->suspend_cause
? "suspending" : "resuming");
527 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
529 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
532 /* Called from main context */
533 int pa_source_sync_suspend(pa_source
*s
) {
534 pa_sink_state_t state
;
536 pa_source_assert_ref(s
);
537 pa_assert_ctl_context();
538 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
539 pa_assert(s
->monitor_of
);
541 state
= pa_sink_get_state(s
->monitor_of
);
543 if (state
== PA_SINK_SUSPENDED
)
544 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
546 pa_assert(PA_SINK_IS_OPENED(state
));
548 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
551 /* Called from main context */
552 pa_queue
*pa_source_move_all_start(pa_source
*s
, pa_queue
*q
) {
553 pa_source_output
*o
, *n
;
556 pa_source_assert_ref(s
);
557 pa_assert_ctl_context();
558 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
563 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
564 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
566 pa_source_output_ref(o
);
568 if (pa_source_output_start_move(o
) >= 0)
571 pa_source_output_unref(o
);
577 /* Called from main context */
578 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
581 pa_source_assert_ref(s
);
582 pa_assert_ctl_context();
583 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
586 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
587 if (pa_source_output_finish_move(o
, s
, save
) < 0)
588 pa_source_output_fail_move(o
);
590 pa_source_output_unref(o
);
593 pa_queue_free(q
, NULL
, NULL
);
596 /* Called from main context */
597 void pa_source_move_all_fail(pa_queue
*q
) {
600 pa_assert_ctl_context();
603 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
604 pa_source_output_fail_move(o
);
605 pa_source_output_unref(o
);
608 pa_queue_free(q
, NULL
, NULL
);
611 /* Called from IO thread context */
612 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
616 pa_source_assert_ref(s
);
617 pa_source_assert_io_context(s
);
618 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
623 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
626 pa_log_debug("Processing rewind...");
628 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
) {
629 pa_source_output_assert_ref(o
);
630 pa_source_output_process_rewind(o
, nbytes
);
634 /* Called from IO thread context */
635 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
639 pa_source_assert_ref(s
);
640 pa_source_assert_io_context(s
);
641 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
644 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
647 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
648 pa_memchunk vchunk
= *chunk
;
650 pa_memblock_ref(vchunk
.memblock
);
651 pa_memchunk_make_writable(&vchunk
, 0);
653 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
654 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
656 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
658 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
659 pa_source_output_assert_ref(o
);
661 if (!o
->thread_info
.direct_on_input
)
662 pa_source_output_push(o
, &vchunk
);
665 pa_memblock_unref(vchunk
.memblock
);
668 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
669 pa_source_output_assert_ref(o
);
671 if (!o
->thread_info
.direct_on_input
)
672 pa_source_output_push(o
, chunk
);
677 /* Called from IO thread context */
678 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
679 pa_source_assert_ref(s
);
680 pa_source_assert_io_context(s
);
681 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
682 pa_source_output_assert_ref(o
);
683 pa_assert(o
->thread_info
.direct_on_input
);
686 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
689 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
690 pa_memchunk vchunk
= *chunk
;
692 pa_memblock_ref(vchunk
.memblock
);
693 pa_memchunk_make_writable(&vchunk
, 0);
695 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
696 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
698 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
700 pa_source_output_push(o
, &vchunk
);
702 pa_memblock_unref(vchunk
.memblock
);
704 pa_source_output_push(o
, chunk
);
707 /* Called from main thread */
708 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
711 pa_source_assert_ref(s
);
712 pa_assert_ctl_context();
713 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
715 if (s
->state
== PA_SOURCE_SUSPENDED
)
718 if (!(s
->flags
& PA_SOURCE_LATENCY
))
721 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
726 /* Called from IO thread */
727 pa_usec_t
pa_source_get_latency_within_thread(pa_source
*s
) {
731 pa_source_assert_ref(s
);
732 pa_source_assert_io_context(s
);
733 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
735 /* The returned value is supposed to be in the time domain of the sound card! */
737 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
740 if (!(s
->flags
& PA_SOURCE_LATENCY
))
745 /* We probably should make this a proper vtable callback instead of going through process_msg() */
747 if (o
->process_msg(o
, PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
753 /* Called from main thread */
754 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
, pa_bool_t save
) {
755 pa_cvolume old_virtual_volume
;
756 pa_bool_t virtual_volume_changed
;
758 pa_source_assert_ref(s
);
759 pa_assert_ctl_context();
760 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
762 pa_assert(pa_cvolume_valid(volume
));
763 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
765 old_virtual_volume
= s
->virtual_volume
;
766 s
->virtual_volume
= *volume
;
767 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
768 s
->save_volume
= (!virtual_volume_changed
&& s
->save_volume
) || save
;
771 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
774 s
->soft_volume
= s
->virtual_volume
;
776 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
778 if (virtual_volume_changed
)
779 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
782 /* Called from main thread. Only to be called by source implementor */
783 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
784 pa_source_assert_ref(s
);
785 pa_assert_ctl_context();
788 if (PA_SOURCE_IS_LINKED(s
->state
))
789 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
791 s
->thread_info
.soft_volume
= *volume
;
794 /* Called from main thread */
795 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
796 pa_source_assert_ref(s
);
797 pa_assert_ctl_context();
798 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
800 if (s
->refresh_volume
|| force_refresh
) {
801 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
806 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
808 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
)) {
809 s
->save_volume
= TRUE
;
810 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
814 return &s
->virtual_volume
;
817 /* Called from main thread */
818 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
819 pa_source_assert_ref(s
);
820 pa_assert_ctl_context();
821 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
823 /* The source implementor may call this if the volume changed to make sure everyone is notified */
825 if (pa_cvolume_equal(&s
->virtual_volume
, new_volume
))
828 s
->virtual_volume
= *new_volume
;
829 s
->save_volume
= TRUE
;
831 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
834 /* Called from main thread */
835 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
, pa_bool_t save
) {
838 pa_source_assert_ref(s
);
839 pa_assert_ctl_context();
840 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
842 old_muted
= s
->muted
;
844 s
->save_muted
= (old_muted
== s
->muted
&& s
->save_muted
) || save
;
849 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
851 if (old_muted
!= s
->muted
)
852 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
855 /* Called from main thread */
856 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
857 pa_source_assert_ref(s
);
858 pa_assert_ctl_context();
859 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
861 if (s
->refresh_muted
|| force_refresh
) {
862 pa_bool_t old_muted
= s
->muted
;
867 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
869 if (old_muted
!= s
->muted
) {
870 s
->save_muted
= TRUE
;
872 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
874 /* Make sure the soft mute status stays in sync */
875 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
882 /* Called from main thread */
883 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
884 pa_source_assert_ref(s
);
885 pa_assert_ctl_context();
886 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
888 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
890 if (s
->muted
== new_muted
)
893 s
->muted
= new_muted
;
894 s
->save_muted
= TRUE
;
896 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
899 /* Called from main thread */
900 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
901 pa_source_assert_ref(s
);
902 pa_assert_ctl_context();
905 pa_proplist_update(s
->proplist
, mode
, p
);
907 if (PA_SOURCE_IS_LINKED(s
->state
)) {
908 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
909 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
915 /* Called from main thread */
916 /* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
917 void pa_source_set_description(pa_source
*s
, const char *description
) {
919 pa_source_assert_ref(s
);
920 pa_assert_ctl_context();
922 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
925 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
927 if (old
&& description
&& pa_streq(old
, description
))
931 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
933 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
935 if (PA_SOURCE_IS_LINKED(s
->state
)) {
936 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
937 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
941 /* Called from main thread */
942 unsigned pa_source_linked_by(pa_source
*s
) {
943 pa_source_assert_ref(s
);
944 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
945 pa_assert_ctl_context();
947 return pa_idxset_size(s
->outputs
);
950 /* Called from main thread */
951 unsigned pa_source_used_by(pa_source
*s
) {
954 pa_source_assert_ref(s
);
955 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
956 pa_assert_ctl_context();
958 ret
= pa_idxset_size(s
->outputs
);
959 pa_assert(ret
>= s
->n_corked
);
961 return ret
- s
->n_corked
;
964 /* Called from main thread */
965 unsigned pa_source_check_suspend(pa_source
*s
) {
970 pa_source_assert_ref(s
);
971 pa_assert_ctl_context();
973 if (!PA_SOURCE_IS_LINKED(s
->state
))
978 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
) {
979 pa_source_output_state_t st
;
981 st
= pa_source_output_get_state(o
);
982 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
984 if (st
== PA_SOURCE_OUTPUT_CORKED
)
987 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
996 /* Called from IO thread, except when it is not */
997 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
998 pa_source
*s
= PA_SOURCE(object
);
999 pa_source_assert_ref(s
);
1001 switch ((pa_source_message_t
) code
) {
1003 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
1004 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1006 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
1008 if (o
->direct_on_input
) {
1009 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
1010 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
1013 pa_assert(!o
->thread_info
.attached
);
1014 o
->thread_info
.attached
= TRUE
;
1019 pa_source_output_set_state_within_thread(o
, o
->state
);
1021 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
1022 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1024 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1026 /* We don't just invalidate the requested latency here,
1027 * because if we are in a move we might need to fix up the
1028 * requested latency. */
1029 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1034 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
1035 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1037 pa_source_output_set_state_within_thread(o
, o
->state
);
1042 pa_assert(o
->thread_info
.attached
);
1043 o
->thread_info
.attached
= FALSE
;
1045 if (o
->thread_info
.direct_on_input
) {
1046 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
1047 o
->thread_info
.direct_on_input
= NULL
;
1050 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
1051 pa_source_output_unref(o
);
1053 pa_source_invalidate_requested_latency(s
, TRUE
);
1058 case PA_SOURCE_MESSAGE_SET_VOLUME
:
1059 s
->thread_info
.soft_volume
= s
->soft_volume
;
1062 case PA_SOURCE_MESSAGE_GET_VOLUME
:
1065 case PA_SOURCE_MESSAGE_SET_MUTE
:
1066 s
->thread_info
.soft_muted
= s
->muted
;
1069 case PA_SOURCE_MESSAGE_GET_MUTE
:
1072 case PA_SOURCE_MESSAGE_SET_STATE
: {
1074 pa_bool_t suspend_change
=
1075 (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
1076 (PA_SOURCE_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SOURCE_SUSPENDED
);
1078 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
1080 if (suspend_change
) {
1081 pa_source_output
*o
;
1084 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1085 if (o
->suspend_within_thread
)
1086 o
->suspend_within_thread(o
, s
->thread_info
.state
== PA_SOURCE_SUSPENDED
);
1093 case PA_SOURCE_MESSAGE_DETACH
:
1095 /* Detach all streams */
1096 pa_source_detach_within_thread(s
);
1099 case PA_SOURCE_MESSAGE_ATTACH
:
1101 /* Reattach all streams */
1102 pa_source_attach_within_thread(s
);
1105 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
1107 pa_usec_t
*usec
= userdata
;
1108 *usec
= pa_source_get_requested_latency_within_thread(s
);
1110 if (*usec
== (pa_usec_t
) -1)
1111 *usec
= s
->thread_info
.max_latency
;
1116 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
1117 pa_usec_t
*r
= userdata
;
1119 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
1124 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
1125 pa_usec_t
*r
= userdata
;
1127 r
[0] = s
->thread_info
.min_latency
;
1128 r
[1] = s
->thread_info
.max_latency
;
1133 case PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
:
1135 *((pa_usec_t
*) userdata
) = s
->thread_info
.fixed_latency
;
1138 case PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
:
1140 pa_source_set_fixed_latency_within_thread(s
, (pa_usec_t
) offset
);
1143 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
1145 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1148 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
1150 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
1153 case PA_SOURCE_MESSAGE_GET_LATENCY
:
1155 if (s
->monitor_of
) {
1156 *((pa_usec_t
*) userdata
) = 0;
1160 /* Implementors need to overwrite this implementation! */
1163 case PA_SOURCE_MESSAGE_MAX
:
1170 /* Called from main thread */
1171 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
1176 pa_core_assert_ref(c
);
1177 pa_assert_ctl_context();
1178 pa_assert(cause
!= 0);
1180 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1183 if (source
->monitor_of
)
1186 if ((r
= pa_source_suspend(source
, suspend
, cause
)) < 0)
1193 /* Called from main thread */
1194 void pa_source_detach(pa_source
*s
) {
1195 pa_source_assert_ref(s
);
1196 pa_assert_ctl_context();
1197 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1199 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1202 /* Called from main thread */
1203 void pa_source_attach(pa_source
*s
) {
1204 pa_source_assert_ref(s
);
1205 pa_assert_ctl_context();
1206 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1208 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1211 /* Called from IO thread */
1212 void pa_source_detach_within_thread(pa_source
*s
) {
1213 pa_source_output
*o
;
1216 pa_source_assert_ref(s
);
1217 pa_source_assert_io_context(s
);
1218 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1220 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1225 /* Called from IO thread */
1226 void pa_source_attach_within_thread(pa_source
*s
) {
1227 pa_source_output
*o
;
1230 pa_source_assert_ref(s
);
1231 pa_source_assert_io_context(s
);
1232 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1234 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1239 /* Called from IO thread */
1240 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1241 pa_usec_t result
= (pa_usec_t
) -1;
1242 pa_source_output
*o
;
1245 pa_source_assert_ref(s
);
1246 pa_source_assert_io_context(s
);
1248 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1249 return PA_CLAMP(s
->thread_info
.fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1251 if (s
->thread_info
.requested_latency_valid
)
1252 return s
->thread_info
.requested_latency
;
1254 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1255 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1256 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1257 result
= o
->thread_info
.requested_source_latency
;
1259 if (result
!= (pa_usec_t
) -1)
1260 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1262 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1263 /* Only cache this if we are fully set up */
1264 s
->thread_info
.requested_latency
= result
;
1265 s
->thread_info
.requested_latency_valid
= TRUE
;
1271 /* Called from main thread */
1272 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1275 pa_source_assert_ref(s
);
1276 pa_assert_ctl_context();
1277 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1279 if (s
->state
== PA_SOURCE_SUSPENDED
)
1282 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1287 /* Called from IO thread */
1288 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1289 pa_source_output
*o
;
1292 pa_source_assert_ref(s
);
1293 pa_source_assert_io_context(s
);
1295 if (max_rewind
== s
->thread_info
.max_rewind
)
1298 s
->thread_info
.max_rewind
= max_rewind
;
1300 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
))
1301 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1302 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1305 /* Called from main thread */
1306 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1307 pa_source_assert_ref(s
);
1308 pa_assert_ctl_context();
1310 if (PA_SOURCE_IS_LINKED(s
->state
))
1311 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1313 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1316 /* Called from IO thread */
1317 void pa_source_invalidate_requested_latency(pa_source
*s
, pa_bool_t dynamic
) {
1318 pa_source_output
*o
;
1321 pa_source_assert_ref(s
);
1322 pa_source_assert_io_context(s
);
1324 if ((s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1325 s
->thread_info
.requested_latency_valid
= FALSE
;
1329 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1331 if (s
->update_requested_latency
)
1332 s
->update_requested_latency(s
);
1334 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1335 if (o
->update_source_requested_latency
)
1336 o
->update_source_requested_latency(o
);
1340 pa_sink_invalidate_requested_latency(s
->monitor_of
, dynamic
);
1343 /* Called from main thread */
1344 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1345 pa_source_assert_ref(s
);
1346 pa_assert_ctl_context();
1348 /* min_latency == 0: no limit
1349 * min_latency anything else: specified limit
1351 * Similar for max_latency */
1353 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1354 min_latency
= ABSOLUTE_MIN_LATENCY
;
1356 if (max_latency
<= 0 ||
1357 max_latency
> ABSOLUTE_MAX_LATENCY
)
1358 max_latency
= ABSOLUTE_MAX_LATENCY
;
1360 pa_assert(min_latency
<= max_latency
);
1362 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1363 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1364 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1365 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1367 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1373 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1375 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1378 /* Called from main thread */
1379 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1380 pa_source_assert_ref(s
);
1381 pa_assert_ctl_context();
1382 pa_assert(min_latency
);
1383 pa_assert(max_latency
);
1385 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1386 pa_usec_t r
[2] = { 0, 0 };
1388 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1390 *min_latency
= r
[0];
1391 *max_latency
= r
[1];
1393 *min_latency
= s
->thread_info
.min_latency
;
1394 *max_latency
= s
->thread_info
.max_latency
;
1398 /* Called from IO thread, and from main thread before pa_source_put() is called */
1399 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1400 pa_source_assert_ref(s
);
1401 pa_source_assert_io_context(s
);
1403 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1404 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1405 pa_assert(min_latency
<= max_latency
);
1407 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1408 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1409 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1410 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1413 if (s
->thread_info
.min_latency
== min_latency
&&
1414 s
->thread_info
.max_latency
== max_latency
)
1417 s
->thread_info
.min_latency
= min_latency
;
1418 s
->thread_info
.max_latency
= max_latency
;
1420 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1421 pa_source_output
*o
;
1424 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1425 if (o
->update_source_latency_range
)
1426 o
->update_source_latency_range(o
);
1429 pa_source_invalidate_requested_latency(s
, FALSE
);
1432 /* Called from main thread, before the source is put */
1433 void pa_source_set_fixed_latency(pa_source
*s
, pa_usec_t latency
) {
1434 pa_source_assert_ref(s
);
1435 pa_assert_ctl_context();
1437 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1438 pa_assert(latency
== 0);
1442 if (latency
< ABSOLUTE_MIN_LATENCY
)
1443 latency
= ABSOLUTE_MIN_LATENCY
;
1445 if (latency
> ABSOLUTE_MAX_LATENCY
)
1446 latency
= ABSOLUTE_MAX_LATENCY
;
1448 if (PA_SOURCE_IS_LINKED(s
->state
))
1449 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
, NULL
, (int64_t) latency
, NULL
) == 0);
1451 s
->thread_info
.fixed_latency
= latency
;
1454 /* Called from main thread */
1455 pa_usec_t
pa_source_get_fixed_latency(pa_source
*s
) {
1458 pa_source_assert_ref(s
);
1459 pa_assert_ctl_context();
1461 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
)
1464 if (PA_SOURCE_IS_LINKED(s
->state
))
1465 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
, &latency
, 0, NULL
) == 0);
1467 latency
= s
->thread_info
.fixed_latency
;
1472 /* Called from IO thread */
1473 void pa_source_set_fixed_latency_within_thread(pa_source
*s
, pa_usec_t latency
) {
1474 pa_source_assert_ref(s
);
1475 pa_source_assert_io_context(s
);
1477 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1478 pa_assert(latency
== 0);
1482 pa_assert(latency
>= ABSOLUTE_MIN_LATENCY
);
1483 pa_assert(latency
<= ABSOLUTE_MAX_LATENCY
);
1485 if (s
->thread_info
.fixed_latency
== latency
)
1488 s
->thread_info
.fixed_latency
= latency
;
1490 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1491 pa_source_output
*o
;
1494 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1495 if (o
->update_source_fixed_latency
)
1496 o
->update_source_fixed_latency(o
);
1499 pa_source_invalidate_requested_latency(s
, FALSE
);
1502 /* Called from main thread */
1503 size_t pa_source_get_max_rewind(pa_source
*s
) {
1505 pa_assert_ctl_context();
1506 pa_source_assert_ref(s
);
1508 if (!PA_SOURCE_IS_LINKED(s
->state
))
1509 return s
->thread_info
.max_rewind
;
1511 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);
1516 /* Called from main context */
1517 int pa_source_set_port(pa_source
*s
, const char *name
, pa_bool_t save
) {
1518 pa_device_port
*port
;
1521 pa_assert_ctl_context();
1524 pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s
->index
, s
->name
);
1525 return -PA_ERR_NOTIMPLEMENTED
;
1529 return -PA_ERR_NOENTITY
;
1531 if (!(port
= pa_hashmap_get(s
->ports
, name
)))
1532 return -PA_ERR_NOENTITY
;
1534 if (s
->active_port
== port
) {
1535 s
->save_port
= s
->save_port
|| save
;
1539 if ((s
->set_port(s
, port
)) < 0)
1540 return -PA_ERR_NOENTITY
;
1542 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1544 pa_log_info("Changed port of source %u \"%s\" to %s", s
->index
, s
->name
, port
->name
);
1546 s
->active_port
= port
;
1547 s
->save_port
= save
;