2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/source-output.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/core-subscribe.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/sample-util.h>
45 #define ABSOLUTE_MIN_LATENCY (500)
46 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
47 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
49 PA_DEFINE_PUBLIC_CLASS(pa_source
, pa_msgobject
);
51 static void source_free(pa_object
*o
);
53 pa_source_new_data
* pa_source_new_data_init(pa_source_new_data
*data
) {
57 data
->proplist
= pa_proplist_new();
62 void pa_source_new_data_set_name(pa_source_new_data
*data
, const char *name
) {
66 data
->name
= pa_xstrdup(name
);
69 void pa_source_new_data_set_sample_spec(pa_source_new_data
*data
, const pa_sample_spec
*spec
) {
72 if ((data
->sample_spec_is_set
= !!spec
))
73 data
->sample_spec
= *spec
;
76 void pa_source_new_data_set_channel_map(pa_source_new_data
*data
, const pa_channel_map
*map
) {
79 if ((data
->channel_map_is_set
= !!map
))
80 data
->channel_map
= *map
;
83 void pa_source_new_data_set_volume(pa_source_new_data
*data
, const pa_cvolume
*volume
) {
86 if ((data
->volume_is_set
= !!volume
))
87 data
->volume
= *volume
;
90 void pa_source_new_data_set_muted(pa_source_new_data
*data
, pa_bool_t mute
) {
93 data
->muted_is_set
= TRUE
;
97 void pa_source_new_data_set_port(pa_source_new_data
*data
, const char *port
) {
100 pa_xfree(data
->active_port
);
101 data
->active_port
= pa_xstrdup(port
);
104 void pa_source_new_data_done(pa_source_new_data
*data
) {
107 pa_proplist_free(data
->proplist
);
112 while ((p
= pa_hashmap_steal_first(data
->ports
)))
113 pa_device_port_free(p
);
115 pa_hashmap_free(data
->ports
, NULL
, NULL
);
118 pa_xfree(data
->name
);
119 pa_xfree(data
->active_port
);
122 /* Called from main context */
123 static void reset_callbacks(pa_source
*s
) {
127 s
->get_volume
= NULL
;
128 s
->set_volume
= NULL
;
131 s
->update_requested_latency
= NULL
;
135 /* Called from main context */
136 pa_source
* pa_source_new(
138 pa_source_new_data
*data
,
139 pa_source_flags_t flags
) {
143 char st
[PA_SAMPLE_SPEC_SNPRINT_MAX
], cm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
148 pa_assert(data
->name
);
149 pa_assert_ctl_context();
151 s
= pa_msgobject_new(pa_source
);
153 if (!(name
= pa_namereg_register(core
, data
->name
, PA_NAMEREG_SOURCE
, s
, data
->namereg_fail
))) {
154 pa_log_debug("Failed to register name %s.", data
->name
);
159 pa_source_new_data_set_name(data
, name
);
161 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_NEW
], data
) < 0) {
163 pa_namereg_unregister(core
, name
);
167 /* FIXME, need to free s here on failure */
169 pa_return_null_if_fail(!data
->driver
|| pa_utf8_valid(data
->driver
));
170 pa_return_null_if_fail(data
->name
&& pa_utf8_valid(data
->name
) && data
->name
[0]);
172 pa_return_null_if_fail(data
->sample_spec_is_set
&& pa_sample_spec_valid(&data
->sample_spec
));
174 if (!data
->channel_map_is_set
)
175 pa_return_null_if_fail(pa_channel_map_init_auto(&data
->channel_map
, data
->sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
));
177 pa_return_null_if_fail(pa_channel_map_valid(&data
->channel_map
));
178 pa_return_null_if_fail(data
->channel_map
.channels
== data
->sample_spec
.channels
);
180 if (!data
->volume_is_set
)
181 pa_cvolume_reset(&data
->volume
, data
->sample_spec
.channels
);
183 pa_return_null_if_fail(pa_cvolume_valid(&data
->volume
));
184 pa_return_null_if_fail(pa_cvolume_compatible(&data
->volume
, &data
->sample_spec
));
186 if (!data
->muted_is_set
)
190 pa_proplist_update(data
->proplist
, PA_UPDATE_MERGE
, data
->card
->proplist
);
192 pa_device_init_description(data
->proplist
);
193 pa_device_init_icon(data
->proplist
, FALSE
);
194 pa_device_init_intended_roles(data
->proplist
);
196 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_FIXATE
], data
) < 0) {
198 pa_namereg_unregister(core
, name
);
202 s
->parent
.parent
.free
= source_free
;
203 s
->parent
.process_msg
= pa_source_process_msg
;
206 s
->state
= PA_SOURCE_INIT
;
209 s
->suspend_cause
= 0;
210 s
->name
= pa_xstrdup(name
);
211 s
->proplist
= pa_proplist_copy(data
->proplist
);
212 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
213 s
->module
= data
->module
;
214 s
->card
= data
->card
;
216 s
->priority
= pa_device_init_priority(s
->proplist
);
218 s
->sample_spec
= data
->sample_spec
;
219 s
->channel_map
= data
->channel_map
;
221 s
->outputs
= pa_idxset_new(NULL
, NULL
);
223 s
->monitor_of
= NULL
;
224 s
->output_from_master
= NULL
;
226 s
->volume
= data
->volume
;
227 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
228 s
->base_volume
= PA_VOLUME_NORM
;
229 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
230 s
->muted
= data
->muted
;
231 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
238 /* As a minor optimization we just steal the list instead of
240 s
->ports
= data
->ports
;
243 s
->active_port
= NULL
;
244 s
->save_port
= FALSE
;
246 if (data
->active_port
&& s
->ports
)
247 if ((s
->active_port
= pa_hashmap_get(s
->ports
, data
->active_port
)))
248 s
->save_port
= data
->save_port
;
250 if (!s
->active_port
&& s
->ports
) {
254 PA_HASHMAP_FOREACH(p
, s
->ports
, state
)
255 if (!s
->active_port
|| p
->priority
> s
->active_port
->priority
)
259 s
->save_volume
= data
->save_volume
;
260 s
->save_muted
= data
->save_muted
;
262 pa_silence_memchunk_get(
263 &core
->silence_cache
,
269 s
->thread_info
.rtpoll
= NULL
;
270 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
271 s
->thread_info
.soft_volume
= s
->soft_volume
;
272 s
->thread_info
.soft_muted
= s
->muted
;
273 s
->thread_info
.state
= s
->state
;
274 s
->thread_info
.max_rewind
= 0;
275 s
->thread_info
.requested_latency_valid
= FALSE
;
276 s
->thread_info
.requested_latency
= 0;
277 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
278 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
279 s
->thread_info
.fixed_latency
= flags
& PA_SOURCE_DYNAMIC_LATENCY
? 0 : DEFAULT_FIXED_LATENCY
;
281 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
284 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
286 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
287 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
290 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
291 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
298 /* Called from main context */
299 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
301 pa_bool_t suspend_change
;
302 pa_source_state_t original_state
;
305 pa_assert_ctl_context();
307 if (s
->state
== state
)
310 original_state
= s
->state
;
313 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
314 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
317 if ((ret
= s
->set_state(s
, state
)) < 0)
321 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
324 s
->set_state(s
, original_state
);
331 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
332 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
333 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
336 if (suspend_change
) {
340 /* We're suspending or resuming, tell everyone about it */
342 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
)
343 if (s
->state
== PA_SOURCE_SUSPENDED
&&
344 (o
->flags
& PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
))
345 pa_source_output_kill(o
);
347 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
353 /* Called from main context */
354 void pa_source_put(pa_source
*s
) {
355 pa_source_assert_ref(s
);
356 pa_assert_ctl_context();
358 pa_assert(s
->state
== PA_SOURCE_INIT
);
360 /* The following fields must be initialized properly when calling _put() */
361 pa_assert(s
->asyncmsgq
);
362 pa_assert(s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
364 /* Generally, flags should be initialized via pa_source_new(). As
365 * a special exception we allow volume related flags to be set
366 * between _new() and _put(). */
368 if (!(s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
))
369 s
->flags
|= PA_SOURCE_DECIBEL_VOLUME
;
371 s
->thread_info
.soft_volume
= s
->soft_volume
;
372 s
->thread_info
.soft_muted
= s
->muted
;
374 pa_assert((s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
) || (s
->base_volume
== PA_VOLUME_NORM
&& s
->flags
& PA_SOURCE_DECIBEL_VOLUME
));
375 pa_assert(!(s
->flags
& PA_SOURCE_DECIBEL_VOLUME
) || s
->n_volume_steps
== PA_VOLUME_NORM
+1);
376 pa_assert(!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) == (s
->thread_info
.fixed_latency
!= 0));
378 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
380 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
381 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
384 /* Called from main context */
385 void pa_source_unlink(pa_source
*s
) {
387 pa_source_output
*o
, *j
= NULL
;
390 pa_assert_ctl_context();
392 /* See pa_sink_unlink() for a couple of comments how this function
395 linked
= PA_SOURCE_IS_LINKED(s
->state
);
398 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
400 if (s
->state
!= PA_SOURCE_UNLINKED
)
401 pa_namereg_unregister(s
->core
, s
->name
);
402 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
405 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
407 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
409 pa_source_output_kill(o
);
414 source_set_state(s
, PA_SOURCE_UNLINKED
);
416 s
->state
= PA_SOURCE_UNLINKED
;
421 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
422 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
426 /* Called from main context */
427 static void source_free(pa_object
*o
) {
428 pa_source_output
*so
;
429 pa_source
*s
= PA_SOURCE(o
);
432 pa_assert_ctl_context();
433 pa_assert(pa_source_refcnt(s
) == 0);
435 if (PA_SOURCE_IS_LINKED(s
->state
))
438 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
440 pa_idxset_free(s
->outputs
, NULL
, NULL
);
442 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
443 pa_source_output_unref(so
);
445 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
447 if (s
->silence
.memblock
)
448 pa_memblock_unref(s
->silence
.memblock
);
454 pa_proplist_free(s
->proplist
);
459 while ((p
= pa_hashmap_steal_first(s
->ports
)))
460 pa_device_port_free(p
);
462 pa_hashmap_free(s
->ports
, NULL
, NULL
);
468 /* Called from main context, and not while the IO thread is active, please */
469 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
470 pa_source_assert_ref(s
);
471 pa_assert_ctl_context();
476 /* Called from main context, and not while the IO thread is active, please */
477 void pa_source_update_flags(pa_source
*s
, pa_source_flags_t mask
, pa_source_flags_t value
) {
478 pa_source_assert_ref(s
);
479 pa_assert_ctl_context();
484 /* For now, allow only a minimal set of flags to be changed. */
485 pa_assert((mask
& ~(PA_SOURCE_DYNAMIC_LATENCY
|PA_SOURCE_LATENCY
)) == 0);
487 s
->flags
= (s
->flags
& ~mask
) | (value
& mask
);
490 /* Called from IO context, or before _put() from main context */
491 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
492 pa_source_assert_ref(s
);
493 pa_source_assert_io_context(s
);
495 s
->thread_info
.rtpoll
= p
;
498 /* Called from main context */
499 int pa_source_update_status(pa_source
*s
) {
500 pa_source_assert_ref(s
);
501 pa_assert_ctl_context();
502 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
504 if (s
->state
== PA_SOURCE_SUSPENDED
)
507 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
510 /* Called from main context */
511 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
512 pa_source_assert_ref(s
);
513 pa_assert_ctl_context();
514 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
515 pa_assert(cause
!= 0);
518 return -PA_ERR_NOTSUPPORTED
;
521 s
->suspend_cause
|= cause
;
523 s
->suspend_cause
&= ~cause
;
525 if ((pa_source_get_state(s
) == PA_SOURCE_SUSPENDED
) == !!s
->suspend_cause
)
528 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s
->name
, s
->suspend_cause
, s
->suspend_cause
? "suspending" : "resuming");
531 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
533 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
536 /* Called from main context */
537 int pa_source_sync_suspend(pa_source
*s
) {
538 pa_sink_state_t state
;
540 pa_source_assert_ref(s
);
541 pa_assert_ctl_context();
542 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
543 pa_assert(s
->monitor_of
);
545 state
= pa_sink_get_state(s
->monitor_of
);
547 if (state
== PA_SINK_SUSPENDED
)
548 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
550 pa_assert(PA_SINK_IS_OPENED(state
));
552 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
555 /* Called from main context */
556 pa_queue
*pa_source_move_all_start(pa_source
*s
, pa_queue
*q
) {
557 pa_source_output
*o
, *n
;
560 pa_source_assert_ref(s
);
561 pa_assert_ctl_context();
562 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
567 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
568 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
570 pa_source_output_ref(o
);
572 if (pa_source_output_start_move(o
) >= 0)
575 pa_source_output_unref(o
);
581 /* Called from main context */
582 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
585 pa_source_assert_ref(s
);
586 pa_assert_ctl_context();
587 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
590 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
591 if (pa_source_output_finish_move(o
, s
, save
) < 0)
592 pa_source_output_fail_move(o
);
594 pa_source_output_unref(o
);
597 pa_queue_free(q
, NULL
, NULL
);
600 /* Called from main context */
601 void pa_source_move_all_fail(pa_queue
*q
) {
604 pa_assert_ctl_context();
607 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
608 pa_source_output_fail_move(o
);
609 pa_source_output_unref(o
);
612 pa_queue_free(q
, NULL
, NULL
);
615 /* Called from IO thread context */
616 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
620 pa_source_assert_ref(s
);
621 pa_source_assert_io_context(s
);
622 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
627 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
630 pa_log_debug("Processing rewind...");
632 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
) {
633 pa_source_output_assert_ref(o
);
634 pa_source_output_process_rewind(o
, nbytes
);
638 /* Called from IO thread context */
639 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
643 pa_source_assert_ref(s
);
644 pa_source_assert_io_context(s
);
645 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
648 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
651 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
652 pa_memchunk vchunk
= *chunk
;
654 pa_memblock_ref(vchunk
.memblock
);
655 pa_memchunk_make_writable(&vchunk
, 0);
657 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
658 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
660 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
662 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
663 pa_source_output_assert_ref(o
);
665 if (!o
->thread_info
.direct_on_input
)
666 pa_source_output_push(o
, &vchunk
);
669 pa_memblock_unref(vchunk
.memblock
);
672 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
673 pa_source_output_assert_ref(o
);
675 if (!o
->thread_info
.direct_on_input
)
676 pa_source_output_push(o
, chunk
);
681 /* Called from IO thread context */
682 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
683 pa_source_assert_ref(s
);
684 pa_source_assert_io_context(s
);
685 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
686 pa_source_output_assert_ref(o
);
687 pa_assert(o
->thread_info
.direct_on_input
);
690 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
693 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
694 pa_memchunk vchunk
= *chunk
;
696 pa_memblock_ref(vchunk
.memblock
);
697 pa_memchunk_make_writable(&vchunk
, 0);
699 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
700 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
702 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
704 pa_source_output_push(o
, &vchunk
);
706 pa_memblock_unref(vchunk
.memblock
);
708 pa_source_output_push(o
, chunk
);
711 /* Called from main thread */
712 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
715 pa_source_assert_ref(s
);
716 pa_assert_ctl_context();
717 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
719 if (s
->state
== PA_SOURCE_SUSPENDED
)
722 if (!(s
->flags
& PA_SOURCE_LATENCY
))
725 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
730 /* Called from IO thread */
731 pa_usec_t
pa_source_get_latency_within_thread(pa_source
*s
) {
735 pa_source_assert_ref(s
);
736 pa_source_assert_io_context(s
);
737 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
739 /* The returned value is supposed to be in the time domain of the sound card! */
741 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
744 if (!(s
->flags
& PA_SOURCE_LATENCY
))
749 /* We probably should make this a proper vtable callback instead of going through process_msg() */
751 if (o
->process_msg(o
, PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
757 /* Called from main thread */
758 void pa_source_set_volume(
760 const pa_cvolume
*volume
,
763 pa_bool_t real_changed
;
764 pa_cvolume old_volume
;
766 pa_source_assert_ref(s
);
767 pa_assert_ctl_context();
768 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
769 pa_assert(pa_cvolume_valid(volume
));
770 pa_assert(volume
->channels
== 1 || pa_cvolume_compatible(volume
, &s
->sample_spec
));
772 old_volume
= s
->volume
;
774 if (pa_cvolume_compatible(volume
, &s
->sample_spec
))
777 pa_cvolume_scale(&s
->volume
, pa_cvolume_max(volume
));
779 real_changed
= !pa_cvolume_equal(&old_volume
, &s
->volume
);
780 s
->save_volume
= (!real_changed
&& s
->save_volume
) || save
;
783 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
786 s
->soft_volume
= s
->volume
;
788 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
791 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
794 /* Called from main thread. Only to be called by source implementor */
795 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
796 pa_source_assert_ref(s
);
797 pa_assert_ctl_context();
800 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
802 s
->soft_volume
= *volume
;
804 if (PA_SOURCE_IS_LINKED(s
->state
))
805 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
807 s
->thread_info
.soft_volume
= s
->soft_volume
;
810 /* Called from main thread */
811 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
812 pa_source_assert_ref(s
);
813 pa_assert_ctl_context();
814 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
816 if (s
->refresh_volume
|| force_refresh
) {
817 pa_cvolume old_volume
;
819 old_volume
= s
->volume
;
824 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
826 if (!pa_cvolume_equal(&old_volume
, &s
->volume
)) {
827 s
->save_volume
= TRUE
;
828 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
835 /* Called from main thread */
836 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
837 pa_source_assert_ref(s
);
838 pa_assert_ctl_context();
839 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
841 /* The source implementor may call this if the volume changed to make sure everyone is notified */
843 if (pa_cvolume_equal(&s
->volume
, new_volume
))
846 s
->volume
= *new_volume
;
847 s
->save_volume
= TRUE
;
849 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
852 /* Called from main thread */
853 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
, pa_bool_t save
) {
856 pa_source_assert_ref(s
);
857 pa_assert_ctl_context();
858 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
860 old_muted
= s
->muted
;
862 s
->save_muted
= (old_muted
== s
->muted
&& s
->save_muted
) || save
;
867 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
869 if (old_muted
!= s
->muted
)
870 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
873 /* Called from main thread */
874 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
875 pa_source_assert_ref(s
);
876 pa_assert_ctl_context();
877 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
879 if (s
->refresh_muted
|| force_refresh
) {
880 pa_bool_t old_muted
= s
->muted
;
885 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
887 if (old_muted
!= s
->muted
) {
888 s
->save_muted
= TRUE
;
890 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
892 /* Make sure the soft mute status stays in sync */
893 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
900 /* Called from main thread */
901 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
902 pa_source_assert_ref(s
);
903 pa_assert_ctl_context();
904 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
906 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
908 if (s
->muted
== new_muted
)
911 s
->muted
= new_muted
;
912 s
->save_muted
= TRUE
;
914 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
917 /* Called from main thread */
918 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
919 pa_source_assert_ref(s
);
920 pa_assert_ctl_context();
923 pa_proplist_update(s
->proplist
, mode
, p
);
925 if (PA_SOURCE_IS_LINKED(s
->state
)) {
926 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
927 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
933 /* Called from main thread */
934 /* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
935 void pa_source_set_description(pa_source
*s
, const char *description
) {
937 pa_source_assert_ref(s
);
938 pa_assert_ctl_context();
940 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
943 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
945 if (old
&& description
&& pa_streq(old
, description
))
949 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
951 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
953 if (PA_SOURCE_IS_LINKED(s
->state
)) {
954 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
955 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
959 /* Called from main thread */
960 unsigned pa_source_linked_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 return pa_idxset_size(s
->outputs
);
968 /* Called from main thread */
969 unsigned pa_source_used_by(pa_source
*s
) {
972 pa_source_assert_ref(s
);
973 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
974 pa_assert_ctl_context();
976 ret
= pa_idxset_size(s
->outputs
);
977 pa_assert(ret
>= s
->n_corked
);
979 return ret
- s
->n_corked
;
982 /* Called from main thread */
983 unsigned pa_source_check_suspend(pa_source
*s
) {
988 pa_source_assert_ref(s
);
989 pa_assert_ctl_context();
991 if (!PA_SOURCE_IS_LINKED(s
->state
))
996 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
) {
997 pa_source_output_state_t st
;
999 st
= pa_source_output_get_state(o
);
1001 /* We do not assert here. It is perfectly valid for a source output to
1002 * be in the INIT state (i.e. created, marked done but not yet put)
1003 * and we should not care if it's unlinked as it won't contribute
1004 * towarards our busy status.
1006 if (!PA_SOURCE_OUTPUT_IS_LINKED(st
))
1009 if (st
== PA_SOURCE_OUTPUT_CORKED
)
1012 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
1021 /* Called from IO thread, except when it is not */
1022 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
1023 pa_source
*s
= PA_SOURCE(object
);
1024 pa_source_assert_ref(s
);
1026 switch ((pa_source_message_t
) code
) {
1028 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
1029 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1031 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
1033 if (o
->direct_on_input
) {
1034 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
1035 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
1038 pa_assert(!o
->thread_info
.attached
);
1039 o
->thread_info
.attached
= TRUE
;
1044 pa_source_output_set_state_within_thread(o
, o
->state
);
1046 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
1047 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1049 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1051 /* We don't just invalidate the requested latency here,
1052 * because if we are in a move we might need to fix up the
1053 * requested latency. */
1054 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1059 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
1060 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1062 pa_source_output_set_state_within_thread(o
, o
->state
);
1067 pa_assert(o
->thread_info
.attached
);
1068 o
->thread_info
.attached
= FALSE
;
1070 if (o
->thread_info
.direct_on_input
) {
1071 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
1072 o
->thread_info
.direct_on_input
= NULL
;
1075 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
1076 pa_source_output_unref(o
);
1078 pa_source_invalidate_requested_latency(s
, TRUE
);
1083 case PA_SOURCE_MESSAGE_SET_VOLUME
:
1084 s
->thread_info
.soft_volume
= s
->soft_volume
;
1087 case PA_SOURCE_MESSAGE_GET_VOLUME
:
1090 case PA_SOURCE_MESSAGE_SET_MUTE
:
1091 s
->thread_info
.soft_muted
= s
->muted
;
1094 case PA_SOURCE_MESSAGE_GET_MUTE
:
1097 case PA_SOURCE_MESSAGE_SET_STATE
: {
1099 pa_bool_t suspend_change
=
1100 (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
1101 (PA_SOURCE_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SOURCE_SUSPENDED
);
1103 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
1105 if (suspend_change
) {
1106 pa_source_output
*o
;
1109 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1110 if (o
->suspend_within_thread
)
1111 o
->suspend_within_thread(o
, s
->thread_info
.state
== PA_SOURCE_SUSPENDED
);
1118 case PA_SOURCE_MESSAGE_DETACH
:
1120 /* Detach all streams */
1121 pa_source_detach_within_thread(s
);
1124 case PA_SOURCE_MESSAGE_ATTACH
:
1126 /* Reattach all streams */
1127 pa_source_attach_within_thread(s
);
1130 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
1132 pa_usec_t
*usec
= userdata
;
1133 *usec
= pa_source_get_requested_latency_within_thread(s
);
1135 if (*usec
== (pa_usec_t
) -1)
1136 *usec
= s
->thread_info
.max_latency
;
1141 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
1142 pa_usec_t
*r
= userdata
;
1144 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
1149 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
1150 pa_usec_t
*r
= userdata
;
1152 r
[0] = s
->thread_info
.min_latency
;
1153 r
[1] = s
->thread_info
.max_latency
;
1158 case PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
:
1160 *((pa_usec_t
*) userdata
) = s
->thread_info
.fixed_latency
;
1163 case PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
:
1165 pa_source_set_fixed_latency_within_thread(s
, (pa_usec_t
) offset
);
1168 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
1170 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1173 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
1175 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
1178 case PA_SOURCE_MESSAGE_GET_LATENCY
:
1180 if (s
->monitor_of
) {
1181 *((pa_usec_t
*) userdata
) = 0;
1185 /* Implementors need to overwrite this implementation! */
1188 case PA_SOURCE_MESSAGE_MAX
:
1195 /* Called from main thread */
1196 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
1201 pa_core_assert_ref(c
);
1202 pa_assert_ctl_context();
1203 pa_assert(cause
!= 0);
1205 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1208 if (source
->monitor_of
)
1211 if ((r
= pa_source_suspend(source
, suspend
, cause
)) < 0)
1218 /* Called from main thread */
1219 void pa_source_detach(pa_source
*s
) {
1220 pa_source_assert_ref(s
);
1221 pa_assert_ctl_context();
1222 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1224 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1227 /* Called from main thread */
1228 void pa_source_attach(pa_source
*s
) {
1229 pa_source_assert_ref(s
);
1230 pa_assert_ctl_context();
1231 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1233 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1236 /* Called from IO thread */
1237 void pa_source_detach_within_thread(pa_source
*s
) {
1238 pa_source_output
*o
;
1241 pa_source_assert_ref(s
);
1242 pa_source_assert_io_context(s
);
1243 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1245 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1250 /* Called from IO thread */
1251 void pa_source_attach_within_thread(pa_source
*s
) {
1252 pa_source_output
*o
;
1255 pa_source_assert_ref(s
);
1256 pa_source_assert_io_context(s
);
1257 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1259 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1264 /* Called from IO thread */
1265 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1266 pa_usec_t result
= (pa_usec_t
) -1;
1267 pa_source_output
*o
;
1270 pa_source_assert_ref(s
);
1271 pa_source_assert_io_context(s
);
1273 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1274 return PA_CLAMP(s
->thread_info
.fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1276 if (s
->thread_info
.requested_latency_valid
)
1277 return s
->thread_info
.requested_latency
;
1279 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1280 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1281 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1282 result
= o
->thread_info
.requested_source_latency
;
1284 if (result
!= (pa_usec_t
) -1)
1285 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1287 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1288 /* Only cache this if we are fully set up */
1289 s
->thread_info
.requested_latency
= result
;
1290 s
->thread_info
.requested_latency_valid
= TRUE
;
1296 /* Called from main thread */
1297 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1300 pa_source_assert_ref(s
);
1301 pa_assert_ctl_context();
1302 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1304 if (s
->state
== PA_SOURCE_SUSPENDED
)
1307 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1312 /* Called from IO thread */
1313 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1314 pa_source_output
*o
;
1317 pa_source_assert_ref(s
);
1318 pa_source_assert_io_context(s
);
1320 if (max_rewind
== s
->thread_info
.max_rewind
)
1323 s
->thread_info
.max_rewind
= max_rewind
;
1325 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
))
1326 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1327 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1330 /* Called from main thread */
1331 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1332 pa_source_assert_ref(s
);
1333 pa_assert_ctl_context();
1335 if (PA_SOURCE_IS_LINKED(s
->state
))
1336 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1338 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1341 /* Called from IO thread */
1342 void pa_source_invalidate_requested_latency(pa_source
*s
, pa_bool_t dynamic
) {
1343 pa_source_output
*o
;
1346 pa_source_assert_ref(s
);
1347 pa_source_assert_io_context(s
);
1349 if ((s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1350 s
->thread_info
.requested_latency_valid
= FALSE
;
1354 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1356 if (s
->update_requested_latency
)
1357 s
->update_requested_latency(s
);
1359 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1360 if (o
->update_source_requested_latency
)
1361 o
->update_source_requested_latency(o
);
1365 pa_sink_invalidate_requested_latency(s
->monitor_of
, dynamic
);
1368 /* Called from main thread */
1369 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1370 pa_source_assert_ref(s
);
1371 pa_assert_ctl_context();
1373 /* min_latency == 0: no limit
1374 * min_latency anything else: specified limit
1376 * Similar for max_latency */
1378 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1379 min_latency
= ABSOLUTE_MIN_LATENCY
;
1381 if (max_latency
<= 0 ||
1382 max_latency
> ABSOLUTE_MAX_LATENCY
)
1383 max_latency
= ABSOLUTE_MAX_LATENCY
;
1385 pa_assert(min_latency
<= max_latency
);
1387 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1388 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1389 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1390 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1392 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1398 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1400 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1403 /* Called from main thread */
1404 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1405 pa_source_assert_ref(s
);
1406 pa_assert_ctl_context();
1407 pa_assert(min_latency
);
1408 pa_assert(max_latency
);
1410 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1411 pa_usec_t r
[2] = { 0, 0 };
1413 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1415 *min_latency
= r
[0];
1416 *max_latency
= r
[1];
1418 *min_latency
= s
->thread_info
.min_latency
;
1419 *max_latency
= s
->thread_info
.max_latency
;
1423 /* Called from IO thread, and from main thread before pa_source_put() is called */
1424 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1425 pa_source_assert_ref(s
);
1426 pa_source_assert_io_context(s
);
1428 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1429 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1430 pa_assert(min_latency
<= max_latency
);
1432 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1433 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1434 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1435 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1438 if (s
->thread_info
.min_latency
== min_latency
&&
1439 s
->thread_info
.max_latency
== max_latency
)
1442 s
->thread_info
.min_latency
= min_latency
;
1443 s
->thread_info
.max_latency
= max_latency
;
1445 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1446 pa_source_output
*o
;
1449 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1450 if (o
->update_source_latency_range
)
1451 o
->update_source_latency_range(o
);
1454 pa_source_invalidate_requested_latency(s
, FALSE
);
1457 /* Called from main thread, before the source is put */
1458 void pa_source_set_fixed_latency(pa_source
*s
, pa_usec_t latency
) {
1459 pa_source_assert_ref(s
);
1460 pa_assert_ctl_context();
1462 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1463 pa_assert(latency
== 0);
1467 if (latency
< ABSOLUTE_MIN_LATENCY
)
1468 latency
= ABSOLUTE_MIN_LATENCY
;
1470 if (latency
> ABSOLUTE_MAX_LATENCY
)
1471 latency
= ABSOLUTE_MAX_LATENCY
;
1473 if (PA_SOURCE_IS_LINKED(s
->state
))
1474 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_FIXED_LATENCY
, NULL
, (int64_t) latency
, NULL
) == 0);
1476 s
->thread_info
.fixed_latency
= latency
;
1479 /* Called from main thread */
1480 pa_usec_t
pa_source_get_fixed_latency(pa_source
*s
) {
1483 pa_source_assert_ref(s
);
1484 pa_assert_ctl_context();
1486 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
)
1489 if (PA_SOURCE_IS_LINKED(s
->state
))
1490 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_FIXED_LATENCY
, &latency
, 0, NULL
) == 0);
1492 latency
= s
->thread_info
.fixed_latency
;
1497 /* Called from IO thread */
1498 void pa_source_set_fixed_latency_within_thread(pa_source
*s
, pa_usec_t latency
) {
1499 pa_source_assert_ref(s
);
1500 pa_source_assert_io_context(s
);
1502 if (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) {
1503 pa_assert(latency
== 0);
1507 pa_assert(latency
>= ABSOLUTE_MIN_LATENCY
);
1508 pa_assert(latency
<= ABSOLUTE_MAX_LATENCY
);
1510 if (s
->thread_info
.fixed_latency
== latency
)
1513 s
->thread_info
.fixed_latency
= latency
;
1515 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1516 pa_source_output
*o
;
1519 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1520 if (o
->update_source_fixed_latency
)
1521 o
->update_source_fixed_latency(o
);
1524 pa_source_invalidate_requested_latency(s
, FALSE
);
1527 /* Called from main thread */
1528 size_t pa_source_get_max_rewind(pa_source
*s
) {
1530 pa_assert_ctl_context();
1531 pa_source_assert_ref(s
);
1533 if (!PA_SOURCE_IS_LINKED(s
->state
))
1534 return s
->thread_info
.max_rewind
;
1536 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);
1541 /* Called from main context */
1542 int pa_source_set_port(pa_source
*s
, const char *name
, pa_bool_t save
) {
1543 pa_device_port
*port
;
1546 pa_assert_ctl_context();
1549 pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s
->index
, s
->name
);
1550 return -PA_ERR_NOTIMPLEMENTED
;
1554 return -PA_ERR_NOENTITY
;
1556 if (!(port
= pa_hashmap_get(s
->ports
, name
)))
1557 return -PA_ERR_NOENTITY
;
1559 if (s
->active_port
== port
) {
1560 s
->save_port
= s
->save_port
|| save
;
1564 if ((s
->set_port(s
, port
)) < 0)
1565 return -PA_ERR_NOENTITY
;
1567 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1569 pa_log_info("Changed port of source %u \"%s\" to %s", s
->index
, s
->name
, port
->name
);
1571 s
->active_port
= port
;
1572 s
->save_port
= save
;
1574 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PORT_CHANGED
], s
);