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
;
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
->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(
756 const pa_cvolume
*volume
,
759 pa_bool_t real_changed
;
761 pa_source_assert_ref(s
);
762 pa_assert_ctl_context();
763 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
764 pa_assert(pa_cvolume_valid(volume
));
765 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
767 real_changed
= !pa_cvolume_equal(volume
, &s
->volume
);
769 s
->save_volume
= (!real_changed
&& s
->save_volume
) || save
;
772 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
775 s
->soft_volume
= s
->volume
;
777 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
780 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
783 /* Called from main thread. Only to be called by source implementor */
784 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
785 pa_source_assert_ref(s
);
786 pa_assert_ctl_context();
789 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
791 s
->soft_volume
= *volume
;
793 if (PA_SOURCE_IS_LINKED(s
->state
))
794 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
796 s
->thread_info
.soft_volume
= s
->soft_volume
;
799 /* Called from main thread */
800 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
801 pa_source_assert_ref(s
);
802 pa_assert_ctl_context();
803 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
805 if (s
->refresh_volume
|| force_refresh
) {
806 pa_cvolume old_volume
;
808 old_volume
= s
->volume
;
813 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
815 if (!pa_cvolume_equal(&old_volume
, &s
->volume
)) {
816 s
->save_volume
= TRUE
;
817 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
824 /* Called from main thread */
825 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
826 pa_source_assert_ref(s
);
827 pa_assert_ctl_context();
828 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
830 /* The source implementor may call this if the volume changed to make sure everyone is notified */
832 if (pa_cvolume_equal(&s
->volume
, new_volume
))
835 s
->volume
= *new_volume
;
836 s
->save_volume
= TRUE
;
838 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
841 /* Called from main thread */
842 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
, pa_bool_t save
) {
845 pa_source_assert_ref(s
);
846 pa_assert_ctl_context();
847 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
849 old_muted
= s
->muted
;
851 s
->save_muted
= (old_muted
== s
->muted
&& s
->save_muted
) || save
;
856 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
858 if (old_muted
!= s
->muted
)
859 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
862 /* Called from main thread */
863 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
864 pa_source_assert_ref(s
);
865 pa_assert_ctl_context();
866 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
868 if (s
->refresh_muted
|| force_refresh
) {
869 pa_bool_t old_muted
= s
->muted
;
874 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
876 if (old_muted
!= s
->muted
) {
877 s
->save_muted
= TRUE
;
879 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
881 /* Make sure the soft mute status stays in sync */
882 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
889 /* Called from main thread */
890 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
891 pa_source_assert_ref(s
);
892 pa_assert_ctl_context();
893 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
895 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
897 if (s
->muted
== new_muted
)
900 s
->muted
= new_muted
;
901 s
->save_muted
= TRUE
;
903 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
906 /* Called from main thread */
907 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
908 pa_source_assert_ref(s
);
909 pa_assert_ctl_context();
912 pa_proplist_update(s
->proplist
, mode
, p
);
914 if (PA_SOURCE_IS_LINKED(s
->state
)) {
915 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
916 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
922 /* Called from main thread */
923 /* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
924 void pa_source_set_description(pa_source
*s
, const char *description
) {
926 pa_source_assert_ref(s
);
927 pa_assert_ctl_context();
929 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
932 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
934 if (old
&& description
&& pa_streq(old
, description
))
938 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
940 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
942 if (PA_SOURCE_IS_LINKED(s
->state
)) {
943 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
944 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
948 /* Called from main thread */
949 unsigned pa_source_linked_by(pa_source
*s
) {
950 pa_source_assert_ref(s
);
951 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
952 pa_assert_ctl_context();
954 return pa_idxset_size(s
->outputs
);
957 /* Called from main thread */
958 unsigned pa_source_used_by(pa_source
*s
) {
961 pa_source_assert_ref(s
);
962 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
963 pa_assert_ctl_context();
965 ret
= pa_idxset_size(s
->outputs
);
966 pa_assert(ret
>= s
->n_corked
);
968 return ret
- s
->n_corked
;
971 /* Called from main thread */
972 unsigned pa_source_check_suspend(pa_source
*s
) {
977 pa_source_assert_ref(s
);
978 pa_assert_ctl_context();
980 if (!PA_SOURCE_IS_LINKED(s
->state
))
985 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
) {
986 pa_source_output_state_t st
;
988 st
= pa_source_output_get_state(o
);
989 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
991 if (st
== PA_SOURCE_OUTPUT_CORKED
)
994 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
1003 /* Called from IO thread, except when it is not */
1004 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1005 pa_source
*s
= PA_SOURCE(object
);
1006 pa_source_assert_ref(s
);
1008 switch ((pa_source_message_t
) code
) {
1010 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
1011 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1013 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
1015 if (o
->direct_on_input
) {
1016 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
1017 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
1020 pa_assert(!o
->thread_info
.attached
);
1021 o
->thread_info
.attached
= TRUE
;
1026 pa_source_output_set_state_within_thread(o
, o
->state
);
1028 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
1029 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1031 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1033 /* We don't just invalidate the requested latency here,
1034 * because if we are in a move we might need to fix up the
1035 * requested latency. */
1036 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1041 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
1042 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1044 pa_source_output_set_state_within_thread(o
, o
->state
);
1049 pa_assert(o
->thread_info
.attached
);
1050 o
->thread_info
.attached
= FALSE
;
1052 if (o
->thread_info
.direct_on_input
) {
1053 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
1054 o
->thread_info
.direct_on_input
= NULL
;
1057 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
1058 pa_source_output_unref(o
);
1060 pa_source_invalidate_requested_latency(s
, TRUE
);
1065 case PA_SOURCE_MESSAGE_SET_VOLUME
:
1066 s
->thread_info
.soft_volume
= s
->soft_volume
;
1069 case PA_SOURCE_MESSAGE_GET_VOLUME
:
1072 case PA_SOURCE_MESSAGE_SET_MUTE
:
1073 s
->thread_info
.soft_muted
= s
->muted
;
1076 case PA_SOURCE_MESSAGE_GET_MUTE
:
1079 case PA_SOURCE_MESSAGE_SET_STATE
: {
1081 pa_bool_t suspend_change
=
1082 (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
1083 (PA_SOURCE_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SOURCE_SUSPENDED
);
1085 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
1087 if (suspend_change
) {
1088 pa_source_output
*o
;
1091 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1092 if (o
->suspend_within_thread
)
1093 o
->suspend_within_thread(o
, s
->thread_info
.state
== PA_SOURCE_SUSPENDED
);
1100 case PA_SOURCE_MESSAGE_DETACH
:
1102 /* Detach all streams */
1103 pa_source_detach_within_thread(s
);
1106 case PA_SOURCE_MESSAGE_ATTACH
:
1108 /* Reattach all streams */
1109 pa_source_attach_within_thread(s
);
1112 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
1114 pa_usec_t
*usec
= userdata
;
1115 *usec
= pa_source_get_requested_latency_within_thread(s
);
1117 if (*usec
== (pa_usec_t
) -1)
1118 *usec
= s
->thread_info
.max_latency
;
1123 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
1124 pa_usec_t
*r
= userdata
;
1126 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
1131 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
1132 pa_usec_t
*r
= userdata
;
1134 r
[0] = s
->thread_info
.min_latency
;
1135 r
[1] = s
->thread_info
.max_latency
;
1140 case PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
:
1142 *((pa_usec_t
*) userdata
) = s
->thread_info
.fixed_latency
;
1145 case PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
:
1147 pa_source_set_fixed_latency_within_thread(s
, (pa_usec_t
) offset
);
1150 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
1152 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1155 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
1157 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
1160 case PA_SOURCE_MESSAGE_GET_LATENCY
:
1162 if (s
->monitor_of
) {
1163 *((pa_usec_t
*) userdata
) = 0;
1167 /* Implementors need to overwrite this implementation! */
1170 case PA_SOURCE_MESSAGE_MAX
:
1177 /* Called from main thread */
1178 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
1183 pa_core_assert_ref(c
);
1184 pa_assert_ctl_context();
1185 pa_assert(cause
!= 0);
1187 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1190 if (source
->monitor_of
)
1193 if ((r
= pa_source_suspend(source
, suspend
, cause
)) < 0)
1200 /* Called from main thread */
1201 void pa_source_detach(pa_source
*s
) {
1202 pa_source_assert_ref(s
);
1203 pa_assert_ctl_context();
1204 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1206 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1209 /* Called from main thread */
1210 void pa_source_attach(pa_source
*s
) {
1211 pa_source_assert_ref(s
);
1212 pa_assert_ctl_context();
1213 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1215 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1218 /* Called from IO thread */
1219 void pa_source_detach_within_thread(pa_source
*s
) {
1220 pa_source_output
*o
;
1223 pa_source_assert_ref(s
);
1224 pa_source_assert_io_context(s
);
1225 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1227 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1232 /* Called from IO thread */
1233 void pa_source_attach_within_thread(pa_source
*s
) {
1234 pa_source_output
*o
;
1237 pa_source_assert_ref(s
);
1238 pa_source_assert_io_context(s
);
1239 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1241 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1246 /* Called from IO thread */
1247 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1248 pa_usec_t result
= (pa_usec_t
) -1;
1249 pa_source_output
*o
;
1252 pa_source_assert_ref(s
);
1253 pa_source_assert_io_context(s
);
1255 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1256 return PA_CLAMP(s
->thread_info
.fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1258 if (s
->thread_info
.requested_latency_valid
)
1259 return s
->thread_info
.requested_latency
;
1261 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1262 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1263 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1264 result
= o
->thread_info
.requested_source_latency
;
1266 if (result
!= (pa_usec_t
) -1)
1267 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1269 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1270 /* Only cache this if we are fully set up */
1271 s
->thread_info
.requested_latency
= result
;
1272 s
->thread_info
.requested_latency_valid
= TRUE
;
1278 /* Called from main thread */
1279 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1282 pa_source_assert_ref(s
);
1283 pa_assert_ctl_context();
1284 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1286 if (s
->state
== PA_SOURCE_SUSPENDED
)
1289 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1294 /* Called from IO thread */
1295 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1296 pa_source_output
*o
;
1299 pa_source_assert_ref(s
);
1300 pa_source_assert_io_context(s
);
1302 if (max_rewind
== s
->thread_info
.max_rewind
)
1305 s
->thread_info
.max_rewind
= max_rewind
;
1307 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
))
1308 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1309 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1312 /* Called from main thread */
1313 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1314 pa_source_assert_ref(s
);
1315 pa_assert_ctl_context();
1317 if (PA_SOURCE_IS_LINKED(s
->state
))
1318 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1320 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1323 /* Called from IO thread */
1324 void pa_source_invalidate_requested_latency(pa_source
*s
, pa_bool_t dynamic
) {
1325 pa_source_output
*o
;
1328 pa_source_assert_ref(s
);
1329 pa_source_assert_io_context(s
);
1331 if ((s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1332 s
->thread_info
.requested_latency_valid
= FALSE
;
1336 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1338 if (s
->update_requested_latency
)
1339 s
->update_requested_latency(s
);
1341 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1342 if (o
->update_source_requested_latency
)
1343 o
->update_source_requested_latency(o
);
1347 pa_sink_invalidate_requested_latency(s
->monitor_of
, dynamic
);
1350 /* Called from main thread */
1351 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1352 pa_source_assert_ref(s
);
1353 pa_assert_ctl_context();
1355 /* min_latency == 0: no limit
1356 * min_latency anything else: specified limit
1358 * Similar for max_latency */
1360 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1361 min_latency
= ABSOLUTE_MIN_LATENCY
;
1363 if (max_latency
<= 0 ||
1364 max_latency
> ABSOLUTE_MAX_LATENCY
)
1365 max_latency
= ABSOLUTE_MAX_LATENCY
;
1367 pa_assert(min_latency
<= max_latency
);
1369 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1370 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1371 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1372 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1374 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1380 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1382 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1385 /* Called from main thread */
1386 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1387 pa_source_assert_ref(s
);
1388 pa_assert_ctl_context();
1389 pa_assert(min_latency
);
1390 pa_assert(max_latency
);
1392 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1393 pa_usec_t r
[2] = { 0, 0 };
1395 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1397 *min_latency
= r
[0];
1398 *max_latency
= r
[1];
1400 *min_latency
= s
->thread_info
.min_latency
;
1401 *max_latency
= s
->thread_info
.max_latency
;
1405 /* Called from IO thread, and from main thread before pa_source_put() is called */
1406 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1407 pa_source_assert_ref(s
);
1408 pa_source_assert_io_context(s
);
1410 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1411 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1412 pa_assert(min_latency
<= max_latency
);
1414 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1415 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1416 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1417 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1420 if (s
->thread_info
.min_latency
== min_latency
&&
1421 s
->thread_info
.max_latency
== max_latency
)
1424 s
->thread_info
.min_latency
= min_latency
;
1425 s
->thread_info
.max_latency
= max_latency
;
1427 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1428 pa_source_output
*o
;
1431 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1432 if (o
->update_source_latency_range
)
1433 o
->update_source_latency_range(o
);
1436 pa_source_invalidate_requested_latency(s
, FALSE
);
1439 /* Called from main thread, before the source is put */
1440 void pa_source_set_fixed_latency(pa_source
*s
, pa_usec_t latency
) {
1441 pa_source_assert_ref(s
);
1442 pa_assert_ctl_context();
1444 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1445 pa_assert(latency
== 0);
1449 if (latency
< ABSOLUTE_MIN_LATENCY
)
1450 latency
= ABSOLUTE_MIN_LATENCY
;
1452 if (latency
> ABSOLUTE_MAX_LATENCY
)
1453 latency
= ABSOLUTE_MAX_LATENCY
;
1455 if (PA_SOURCE_IS_LINKED(s
->state
))
1456 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
, NULL
, (int64_t) latency
, NULL
) == 0);
1458 s
->thread_info
.fixed_latency
= latency
;
1461 /* Called from main thread */
1462 pa_usec_t
pa_source_get_fixed_latency(pa_source
*s
) {
1465 pa_source_assert_ref(s
);
1466 pa_assert_ctl_context();
1468 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
)
1471 if (PA_SOURCE_IS_LINKED(s
->state
))
1472 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
, &latency
, 0, NULL
) == 0);
1474 latency
= s
->thread_info
.fixed_latency
;
1479 /* Called from IO thread */
1480 void pa_source_set_fixed_latency_within_thread(pa_source
*s
, pa_usec_t latency
) {
1481 pa_source_assert_ref(s
);
1482 pa_source_assert_io_context(s
);
1484 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1485 pa_assert(latency
== 0);
1489 pa_assert(latency
>= ABSOLUTE_MIN_LATENCY
);
1490 pa_assert(latency
<= ABSOLUTE_MAX_LATENCY
);
1492 if (s
->thread_info
.fixed_latency
== latency
)
1495 s
->thread_info
.fixed_latency
= latency
;
1497 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1498 pa_source_output
*o
;
1501 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1502 if (o
->update_source_fixed_latency
)
1503 o
->update_source_fixed_latency(o
);
1506 pa_source_invalidate_requested_latency(s
, FALSE
);
1509 /* Called from main thread */
1510 size_t pa_source_get_max_rewind(pa_source
*s
) {
1512 pa_assert_ctl_context();
1513 pa_source_assert_ref(s
);
1515 if (!PA_SOURCE_IS_LINKED(s
->state
))
1516 return s
->thread_info
.max_rewind
;
1518 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);
1523 /* Called from main context */
1524 int pa_source_set_port(pa_source
*s
, const char *name
, pa_bool_t save
) {
1525 pa_device_port
*port
;
1528 pa_assert_ctl_context();
1531 pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s
->index
, s
->name
);
1532 return -PA_ERR_NOTIMPLEMENTED
;
1536 return -PA_ERR_NOENTITY
;
1538 if (!(port
= pa_hashmap_get(s
->ports
, name
)))
1539 return -PA_ERR_NOENTITY
;
1541 if (s
->active_port
== port
) {
1542 s
->save_port
= s
->save_port
|| save
;
1546 if ((s
->set_port(s
, port
)) < 0)
1547 return -PA_ERR_NOENTITY
;
1549 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1551 pa_log_info("Changed port of source %u \"%s\" to %s", s
->index
, s
->name
, port
->name
);
1553 s
->active_port
= port
;
1554 s
->save_port
= save
;