2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/source-output.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/core-subscribe.h>
40 #include <pulsecore/log.h>
41 #include <pulsecore/sample-util.h>
45 #define ABSOLUTE_MIN_LATENCY (500)
46 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
47 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
49 static PA_DEFINE_CHECK_TYPE(pa_source
, pa_msgobject
);
51 static void source_free(pa_object
*o
);
53 pa_source_new_data
* pa_source_new_data_init(pa_source_new_data
*data
) {
57 data
->proplist
= pa_proplist_new();
62 void pa_source_new_data_set_name(pa_source_new_data
*data
, const char *name
) {
66 data
->name
= pa_xstrdup(name
);
69 void pa_source_new_data_set_sample_spec(pa_source_new_data
*data
, const pa_sample_spec
*spec
) {
72 if ((data
->sample_spec_is_set
= !!spec
))
73 data
->sample_spec
= *spec
;
76 void pa_source_new_data_set_channel_map(pa_source_new_data
*data
, const pa_channel_map
*map
) {
79 if ((data
->channel_map_is_set
= !!map
))
80 data
->channel_map
= *map
;
83 void pa_source_new_data_set_volume(pa_source_new_data
*data
, const pa_cvolume
*volume
) {
86 if ((data
->volume_is_set
= !!volume
))
87 data
->volume
= *volume
;
90 void pa_source_new_data_set_muted(pa_source_new_data
*data
, pa_bool_t mute
) {
93 data
->muted_is_set
= TRUE
;
97 void pa_source_new_data_set_port(pa_source_new_data
*data
, const char *port
) {
100 pa_xfree(data
->active_port
);
101 data
->active_port
= pa_xstrdup(port
);
104 void pa_source_new_data_done(pa_source_new_data
*data
) {
107 pa_proplist_free(data
->proplist
);
112 while ((p
= pa_hashmap_steal_first(data
->ports
)))
113 pa_device_port_free(p
);
115 pa_hashmap_free(data
->ports
, NULL
, NULL
);
118 pa_xfree(data
->name
);
119 pa_xfree(data
->active_port
);
122 /* Called from main context */
123 static void reset_callbacks(pa_source
*s
) {
127 s
->get_volume
= NULL
;
128 s
->set_volume
= NULL
;
131 s
->update_requested_latency
= NULL
;
135 /* Called from main context */
136 pa_source
* pa_source_new(
138 pa_source_new_data
*data
,
139 pa_source_flags_t flags
) {
143 char st
[PA_SAMPLE_SPEC_SNPRINT_MAX
], cm
[PA_CHANNEL_MAP_SNPRINT_MAX
];
148 pa_assert(data
->name
);
149 pa_assert_ctl_context();
151 s
= pa_msgobject_new(pa_source
);
153 if (!(name
= pa_namereg_register(core
, data
->name
, PA_NAMEREG_SOURCE
, s
, data
->namereg_fail
))) {
154 pa_log_debug("Failed to register name %s.", data
->name
);
159 pa_source_new_data_set_name(data
, name
);
161 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_NEW
], data
) < 0) {
163 pa_namereg_unregister(core
, name
);
167 /* FIXME, need to free s here on failure */
169 pa_return_null_if_fail(!data
->driver
|| pa_utf8_valid(data
->driver
));
170 pa_return_null_if_fail(data
->name
&& pa_utf8_valid(data
->name
) && data
->name
[0]);
172 pa_return_null_if_fail(data
->sample_spec_is_set
&& pa_sample_spec_valid(&data
->sample_spec
));
174 if (!data
->channel_map_is_set
)
175 pa_return_null_if_fail(pa_channel_map_init_auto(&data
->channel_map
, data
->sample_spec
.channels
, PA_CHANNEL_MAP_DEFAULT
));
177 pa_return_null_if_fail(pa_channel_map_valid(&data
->channel_map
));
178 pa_return_null_if_fail(data
->channel_map
.channels
== data
->sample_spec
.channels
);
180 if (!data
->volume_is_set
)
181 pa_cvolume_reset(&data
->volume
, data
->sample_spec
.channels
);
183 pa_return_null_if_fail(pa_cvolume_valid(&data
->volume
));
184 pa_return_null_if_fail(data
->volume
.channels
== data
->sample_spec
.channels
);
186 if (!data
->muted_is_set
)
190 pa_proplist_update(data
->proplist
, PA_UPDATE_MERGE
, data
->card
->proplist
);
192 pa_device_init_description(data
->proplist
);
193 pa_device_init_icon(data
->proplist
, FALSE
);
194 pa_device_init_intended_roles(data
->proplist
);
196 if (pa_hook_fire(&core
->hooks
[PA_CORE_HOOK_SOURCE_FIXATE
], data
) < 0) {
198 pa_namereg_unregister(core
, name
);
202 s
->parent
.parent
.free
= source_free
;
203 s
->parent
.process_msg
= pa_source_process_msg
;
206 s
->state
= PA_SOURCE_INIT
;
208 s
->suspend_cause
= 0;
209 s
->name
= pa_xstrdup(name
);
210 s
->proplist
= pa_proplist_copy(data
->proplist
);
211 s
->driver
= pa_xstrdup(pa_path_get_filename(data
->driver
));
212 s
->module
= data
->module
;
213 s
->card
= data
->card
;
215 s
->sample_spec
= data
->sample_spec
;
216 s
->channel_map
= data
->channel_map
;
218 s
->outputs
= pa_idxset_new(NULL
, NULL
);
220 s
->monitor_of
= NULL
;
222 s
->virtual_volume
= data
->volume
;
223 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
224 s
->base_volume
= PA_VOLUME_NORM
;
225 s
->n_volume_steps
= PA_VOLUME_NORM
+1;
226 s
->muted
= data
->muted
;
227 s
->refresh_volume
= s
->refresh_muted
= FALSE
;
229 s
->fixed_latency
= flags
& PA_SOURCE_DYNAMIC_LATENCY
? 0 : DEFAULT_FIXED_LATENCY
;
237 /* As a minor optimization we just steal the list instead of
239 s
->ports
= data
->ports
;
242 s
->active_port
= NULL
;
243 s
->save_port
= FALSE
;
245 if (data
->active_port
&& s
->ports
)
246 if ((s
->active_port
= pa_hashmap_get(s
->ports
, data
->active_port
)))
247 s
->save_port
= data
->save_port
;
249 if (!s
->active_port
&& s
->ports
) {
253 PA_HASHMAP_FOREACH(p
, s
->ports
, state
)
254 if (!s
->active_port
|| p
->priority
> s
->active_port
->priority
)
258 s
->save_volume
= data
->save_volume
;
259 s
->save_muted
= data
->save_muted
;
261 pa_silence_memchunk_get(
262 &core
->silence_cache
,
268 s
->thread_info
.outputs
= pa_hashmap_new(pa_idxset_trivial_hash_func
, pa_idxset_trivial_compare_func
);
269 s
->thread_info
.soft_volume
= s
->soft_volume
;
270 s
->thread_info
.soft_muted
= s
->muted
;
271 s
->thread_info
.state
= s
->state
;
272 s
->thread_info
.max_rewind
= 0;
273 s
->thread_info
.requested_latency_valid
= FALSE
;
274 s
->thread_info
.requested_latency
= 0;
275 s
->thread_info
.min_latency
= ABSOLUTE_MIN_LATENCY
;
276 s
->thread_info
.max_latency
= ABSOLUTE_MAX_LATENCY
;
278 pa_assert_se(pa_idxset_put(core
->sources
, s
, &s
->index
) >= 0);
281 pa_assert_se(pa_idxset_put(s
->card
->sources
, s
, NULL
) >= 0);
283 pt
= pa_proplist_to_string_sep(s
->proplist
, "\n ");
284 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
287 pa_sample_spec_snprint(st
, sizeof(st
), &s
->sample_spec
),
288 pa_channel_map_snprint(cm
, sizeof(cm
), &s
->channel_map
),
295 /* Called from main context */
296 static int source_set_state(pa_source
*s
, pa_source_state_t state
) {
298 pa_bool_t suspend_change
;
299 pa_source_state_t original_state
;
302 pa_assert_ctl_context();
304 if (s
->state
== state
)
307 original_state
= s
->state
;
310 (original_state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(state
)) ||
311 (PA_SOURCE_IS_OPENED(original_state
) && state
== PA_SOURCE_SUSPENDED
);
314 if ((ret
= s
->set_state(s
, state
)) < 0)
318 if ((ret
= pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_STATE
, PA_UINT_TO_PTR(state
), 0, NULL
)) < 0) {
321 s
->set_state(s
, original_state
);
328 if (state
!= PA_SOURCE_UNLINKED
) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
329 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_STATE_CHANGED
], s
);
330 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
333 if (suspend_change
) {
337 /* We're suspending or resuming, tell everyone about it */
339 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
)
340 if (s
->state
== PA_SOURCE_SUSPENDED
&&
341 (o
->flags
& PA_SOURCE_OUTPUT_KILL_ON_SUSPEND
))
342 pa_source_output_kill(o
);
344 o
->suspend(o
, state
== PA_SOURCE_SUSPENDED
);
350 /* Called from main context */
351 void pa_source_put(pa_source
*s
) {
352 pa_source_assert_ref(s
);
353 pa_assert_ctl_context();
355 pa_assert(s
->state
== PA_SOURCE_INIT
);
357 /* The following fields must be initialized properly when calling _put() */
358 pa_assert(s
->asyncmsgq
);
359 pa_assert(s
->rtpoll
);
360 pa_assert(s
->thread_info
.min_latency
<= s
->thread_info
.max_latency
);
362 /* Generally, flags should be initialized via pa_source_new(). As
363 * a special exception we allow volume related flags to be set
364 * between _new() and _put(). */
366 if (!(s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
))
367 s
->flags
|= PA_SOURCE_DECIBEL_VOLUME
;
369 s
->thread_info
.soft_volume
= s
->soft_volume
;
370 s
->thread_info
.soft_muted
= s
->muted
;
372 pa_assert((s
->flags
& PA_SOURCE_HW_VOLUME_CTRL
) || (s
->base_volume
== PA_VOLUME_NORM
&& s
->flags
& PA_SOURCE_DECIBEL_VOLUME
));
373 pa_assert(!(s
->flags
& PA_SOURCE_DECIBEL_VOLUME
) || s
->n_volume_steps
== PA_VOLUME_NORM
+1);
374 pa_assert(!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) == (s
->fixed_latency
!= 0));
376 pa_assert_se(source_set_state(s
, PA_SOURCE_IDLE
) == 0);
378 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_NEW
, s
->index
);
379 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PUT
], s
);
382 /* Called from main context */
383 void pa_source_unlink(pa_source
*s
) {
385 pa_source_output
*o
, *j
= NULL
;
388 pa_assert_ctl_context();
390 /* See pa_sink_unlink() for a couple of comments how this function
393 linked
= PA_SOURCE_IS_LINKED(s
->state
);
396 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK
], s
);
398 if (s
->state
!= PA_SOURCE_UNLINKED
)
399 pa_namereg_unregister(s
->core
, s
->name
);
400 pa_idxset_remove_by_data(s
->core
->sources
, s
, NULL
);
403 pa_idxset_remove_by_data(s
->card
->sources
, s
, NULL
);
405 while ((o
= pa_idxset_first(s
->outputs
, NULL
))) {
407 pa_source_output_kill(o
);
412 source_set_state(s
, PA_SOURCE_UNLINKED
);
414 s
->state
= PA_SOURCE_UNLINKED
;
419 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
| PA_SUBSCRIPTION_EVENT_REMOVE
, s
->index
);
420 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_UNLINK_POST
], s
);
424 /* Called from main context */
425 static void source_free(pa_object
*o
) {
426 pa_source_output
*so
;
427 pa_source
*s
= PA_SOURCE(o
);
430 pa_assert_ctl_context();
431 pa_assert(pa_source_refcnt(s
) == 0);
433 if (PA_SOURCE_IS_LINKED(s
->state
))
436 pa_log_info("Freeing source %u \"%s\"", s
->index
, s
->name
);
438 pa_idxset_free(s
->outputs
, NULL
, NULL
);
440 while ((so
= pa_hashmap_steal_first(s
->thread_info
.outputs
)))
441 pa_source_output_unref(so
);
443 pa_hashmap_free(s
->thread_info
.outputs
, NULL
, NULL
);
445 if (s
->silence
.memblock
)
446 pa_memblock_unref(s
->silence
.memblock
);
452 pa_proplist_free(s
->proplist
);
457 while ((p
= pa_hashmap_steal_first(s
->ports
)))
458 pa_device_port_free(p
);
460 pa_hashmap_free(s
->ports
, NULL
, NULL
);
466 /* Called from main context */
467 void pa_source_set_asyncmsgq(pa_source
*s
, pa_asyncmsgq
*q
) {
468 pa_assert_ctl_context();
469 pa_source_assert_ref(s
);
474 /* Called from main context */
475 void pa_source_set_rtpoll(pa_source
*s
, pa_rtpoll
*p
) {
476 pa_assert_ctl_context();
477 pa_source_assert_ref(s
);
482 /* Called from main context */
483 int pa_source_update_status(pa_source
*s
) {
484 pa_source_assert_ref(s
);
485 pa_assert_ctl_context();
486 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
488 if (s
->state
== PA_SOURCE_SUSPENDED
)
491 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
494 /* Called from main context */
495 int pa_source_suspend(pa_source
*s
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
496 pa_source_assert_ref(s
);
497 pa_assert_ctl_context();
498 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
499 pa_assert(cause
!= 0);
502 return -PA_ERR_NOTSUPPORTED
;
505 s
->suspend_cause
|= cause
;
507 s
->suspend_cause
&= ~cause
;
509 if ((pa_source_get_state(s
) == PA_SOURCE_SUSPENDED
) == !!s
->suspend_cause
)
512 pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s
->name
, s
->suspend_cause
, s
->suspend_cause
? "suspending" : "resuming");
515 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
517 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
520 /* Called from main context */
521 int pa_source_sync_suspend(pa_source
*s
) {
522 pa_sink_state_t state
;
524 pa_source_assert_ref(s
);
525 pa_assert_ctl_context();
526 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
527 pa_assert(s
->monitor_of
);
529 state
= pa_sink_get_state(s
->monitor_of
);
531 if (state
== PA_SINK_SUSPENDED
)
532 return source_set_state(s
, PA_SOURCE_SUSPENDED
);
534 pa_assert(PA_SINK_IS_OPENED(state
));
536 return source_set_state(s
, pa_source_used_by(s
) ? PA_SOURCE_RUNNING
: PA_SOURCE_IDLE
);
539 /* Called from main context */
540 pa_queue
*pa_source_move_all_start(pa_source
*s
, pa_queue
*q
) {
541 pa_source_output
*o
, *n
;
544 pa_source_assert_ref(s
);
545 pa_assert_ctl_context();
546 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
551 for (o
= PA_SOURCE_OUTPUT(pa_idxset_first(s
->outputs
, &idx
)); o
; o
= n
) {
552 n
= PA_SOURCE_OUTPUT(pa_idxset_next(s
->outputs
, &idx
));
554 pa_source_output_ref(o
);
556 if (pa_source_output_start_move(o
) >= 0)
559 pa_source_output_unref(o
);
565 /* Called from main context */
566 void pa_source_move_all_finish(pa_source
*s
, pa_queue
*q
, pa_bool_t save
) {
569 pa_source_assert_ref(s
);
570 pa_assert_ctl_context();
571 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
574 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
575 if (pa_source_output_finish_move(o
, s
, save
) < 0)
576 pa_source_output_fail_move(o
);
578 pa_source_output_unref(o
);
581 pa_queue_free(q
, NULL
, NULL
);
584 /* Called from main context */
585 void pa_source_move_all_fail(pa_queue
*q
) {
588 pa_assert_ctl_context();
591 while ((o
= PA_SOURCE_OUTPUT(pa_queue_pop(q
)))) {
592 pa_source_output_fail_move(o
);
593 pa_source_output_unref(o
);
596 pa_queue_free(q
, NULL
, NULL
);
599 /* Called from IO thread context */
600 void pa_source_process_rewind(pa_source
*s
, size_t nbytes
) {
604 pa_source_assert_ref(s
);
605 pa_source_assert_io_context(s
);
606 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
611 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
614 pa_log_debug("Processing rewind...");
616 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
) {
617 pa_source_output_assert_ref(o
);
618 pa_source_output_process_rewind(o
, nbytes
);
622 /* Called from IO thread context */
623 void pa_source_post(pa_source
*s
, const pa_memchunk
*chunk
) {
627 pa_source_assert_ref(s
);
628 pa_source_assert_io_context(s
);
629 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
632 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
635 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
636 pa_memchunk vchunk
= *chunk
;
638 pa_memblock_ref(vchunk
.memblock
);
639 pa_memchunk_make_writable(&vchunk
, 0);
641 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
642 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
644 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
646 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
647 pa_source_output_assert_ref(o
);
649 if (!o
->thread_info
.direct_on_input
)
650 pa_source_output_push(o
, &vchunk
);
653 pa_memblock_unref(vchunk
.memblock
);
656 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
))) {
657 pa_source_output_assert_ref(o
);
659 if (!o
->thread_info
.direct_on_input
)
660 pa_source_output_push(o
, chunk
);
665 /* Called from IO thread context */
666 void pa_source_post_direct(pa_source
*s
, pa_source_output
*o
, const pa_memchunk
*chunk
) {
667 pa_source_assert_ref(s
);
668 pa_source_assert_io_context(s
);
669 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
670 pa_source_output_assert_ref(o
);
671 pa_assert(o
->thread_info
.direct_on_input
);
674 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
677 if (s
->thread_info
.soft_muted
|| !pa_cvolume_is_norm(&s
->thread_info
.soft_volume
)) {
678 pa_memchunk vchunk
= *chunk
;
680 pa_memblock_ref(vchunk
.memblock
);
681 pa_memchunk_make_writable(&vchunk
, 0);
683 if (s
->thread_info
.soft_muted
|| pa_cvolume_is_muted(&s
->thread_info
.soft_volume
))
684 pa_silence_memchunk(&vchunk
, &s
->sample_spec
);
686 pa_volume_memchunk(&vchunk
, &s
->sample_spec
, &s
->thread_info
.soft_volume
);
688 pa_source_output_push(o
, &vchunk
);
690 pa_memblock_unref(vchunk
.memblock
);
692 pa_source_output_push(o
, chunk
);
695 /* Called from main thread */
696 pa_usec_t
pa_source_get_latency(pa_source
*s
) {
699 pa_source_assert_ref(s
);
700 pa_assert_ctl_context();
701 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
703 if (s
->state
== PA_SOURCE_SUSPENDED
)
706 if (!(s
->flags
& PA_SOURCE_LATENCY
))
709 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) == 0);
714 /* Called from IO thread */
715 pa_usec_t
pa_source_get_latency_within_thread(pa_source
*s
) {
719 pa_source_assert_ref(s
);
720 pa_source_assert_io_context(s
);
721 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
723 /* The returned value is supposed to be in the time domain of the sound card! */
725 if (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
)
728 if (!(s
->flags
& PA_SOURCE_LATENCY
))
733 /* We probably should make this a proper vtable callback instead of going through process_msg() */
735 if (o
->process_msg(o
, PA_SOURCE_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
741 /* Called from main thread */
742 void pa_source_set_volume(pa_source
*s
, const pa_cvolume
*volume
, pa_bool_t save
) {
743 pa_cvolume old_virtual_volume
;
744 pa_bool_t virtual_volume_changed
;
746 pa_source_assert_ref(s
);
747 pa_assert_ctl_context();
748 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
750 pa_assert(pa_cvolume_valid(volume
));
751 pa_assert(pa_cvolume_compatible(volume
, &s
->sample_spec
));
753 old_virtual_volume
= s
->virtual_volume
;
754 s
->virtual_volume
= *volume
;
755 virtual_volume_changed
= !pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
);
756 s
->save_volume
= (!virtual_volume_changed
&& s
->save_volume
) || save
;
759 pa_cvolume_reset(&s
->soft_volume
, s
->sample_spec
.channels
);
762 s
->soft_volume
= s
->virtual_volume
;
764 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
766 if (virtual_volume_changed
)
767 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
770 /* Called from main thread. Only to be called by source implementor */
771 void pa_source_set_soft_volume(pa_source
*s
, const pa_cvolume
*volume
) {
772 pa_source_assert_ref(s
);
773 pa_assert_ctl_context();
776 if (PA_SOURCE_IS_LINKED(s
->state
))
777 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_VOLUME
, NULL
, 0, NULL
) == 0);
779 s
->thread_info
.soft_volume
= *volume
;
782 /* Called from main thread */
783 const pa_cvolume
*pa_source_get_volume(pa_source
*s
, pa_bool_t force_refresh
) {
784 pa_source_assert_ref(s
);
785 pa_assert_ctl_context();
786 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
788 if (s
->refresh_volume
|| force_refresh
) {
789 pa_cvolume old_virtual_volume
= s
->virtual_volume
;
794 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_VOLUME
, NULL
, 0, NULL
) == 0);
796 if (!pa_cvolume_equal(&old_virtual_volume
, &s
->virtual_volume
)) {
797 s
->save_volume
= TRUE
;
798 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
802 return &s
->virtual_volume
;
805 /* Called from main thread */
806 void pa_source_volume_changed(pa_source
*s
, const pa_cvolume
*new_volume
) {
807 pa_source_assert_ref(s
);
808 pa_assert_ctl_context();
809 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
811 /* The source implementor may call this if the volume changed to make sure everyone is notified */
813 if (pa_cvolume_equal(&s
->virtual_volume
, new_volume
))
816 s
->virtual_volume
= *new_volume
;
817 s
->save_volume
= TRUE
;
819 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
822 /* Called from main thread */
823 void pa_source_set_mute(pa_source
*s
, pa_bool_t mute
, pa_bool_t save
) {
826 pa_source_assert_ref(s
);
827 pa_assert_ctl_context();
828 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
830 old_muted
= s
->muted
;
832 s
->save_muted
= (old_muted
== s
->muted
&& s
->save_muted
) || save
;
837 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
839 if (old_muted
!= s
->muted
)
840 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
843 /* Called from main thread */
844 pa_bool_t
pa_source_get_mute(pa_source
*s
, pa_bool_t force_refresh
) {
845 pa_source_assert_ref(s
);
846 pa_assert_ctl_context();
847 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
849 if (s
->refresh_muted
|| force_refresh
) {
850 pa_bool_t old_muted
= s
->muted
;
855 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MUTE
, NULL
, 0, NULL
) == 0);
857 if (old_muted
!= s
->muted
) {
858 s
->save_muted
= TRUE
;
860 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
862 /* Make sure the soft mute status stays in sync */
863 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MUTE
, NULL
, 0, NULL
) == 0);
870 /* Called from main thread */
871 void pa_source_mute_changed(pa_source
*s
, pa_bool_t new_muted
) {
872 pa_source_assert_ref(s
);
873 pa_assert_ctl_context();
874 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
876 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
878 if (s
->muted
== new_muted
)
881 s
->muted
= new_muted
;
882 s
->save_muted
= TRUE
;
884 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
887 /* Called from main thread */
888 pa_bool_t
pa_source_update_proplist(pa_source
*s
, pa_update_mode_t mode
, pa_proplist
*p
) {
889 pa_source_assert_ref(s
);
890 pa_assert_ctl_context();
893 pa_proplist_update(s
->proplist
, mode
, p
);
895 if (PA_SOURCE_IS_LINKED(s
->state
)) {
896 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
897 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
903 /* Called from main thread */
904 /* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
905 void pa_source_set_description(pa_source
*s
, const char *description
) {
907 pa_source_assert_ref(s
);
908 pa_assert_ctl_context();
910 if (!description
&& !pa_proplist_contains(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
))
913 old
= pa_proplist_gets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
915 if (old
&& description
&& pa_streq(old
, description
))
919 pa_proplist_sets(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
, description
);
921 pa_proplist_unset(s
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
923 if (PA_SOURCE_IS_LINKED(s
->state
)) {
924 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
925 pa_hook_fire(&s
->core
->hooks
[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED
], s
);
929 /* Called from main thread */
930 unsigned pa_source_linked_by(pa_source
*s
) {
931 pa_source_assert_ref(s
);
932 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
933 pa_assert_ctl_context();
935 return pa_idxset_size(s
->outputs
);
938 /* Called from main thread */
939 unsigned pa_source_used_by(pa_source
*s
) {
942 pa_source_assert_ref(s
);
943 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
944 pa_assert_ctl_context();
946 ret
= pa_idxset_size(s
->outputs
);
947 pa_assert(ret
>= s
->n_corked
);
949 return ret
- s
->n_corked
;
952 /* Called from main thread */
953 unsigned pa_source_check_suspend(pa_source
*s
) {
958 pa_source_assert_ref(s
);
959 pa_assert_ctl_context();
961 if (!PA_SOURCE_IS_LINKED(s
->state
))
966 PA_IDXSET_FOREACH(o
, s
->outputs
, idx
) {
967 pa_source_output_state_t st
;
969 st
= pa_source_output_get_state(o
);
970 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st
));
972 if (st
== PA_SOURCE_OUTPUT_CORKED
)
975 if (o
->flags
& PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND
)
984 /* Called from IO thread, except when it is not */
985 int pa_source_process_msg(pa_msgobject
*object
, int code
, void *userdata
, int64_t offset
, pa_memchunk
*chunk
) {
986 pa_source
*s
= PA_SOURCE(object
);
987 pa_source_assert_ref(s
);
989 switch ((pa_source_message_t
) code
) {
991 case PA_SOURCE_MESSAGE_ADD_OUTPUT
: {
992 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
994 pa_hashmap_put(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
), pa_source_output_ref(o
));
996 if (o
->direct_on_input
) {
997 o
->thread_info
.direct_on_input
= o
->direct_on_input
;
998 pa_hashmap_put(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
), o
);
1001 pa_assert(!o
->thread_info
.attached
);
1002 o
->thread_info
.attached
= TRUE
;
1007 pa_source_output_set_state_within_thread(o
, o
->state
);
1009 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1)
1010 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1012 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1014 /* We don't just invalidate the requested latency here,
1015 * because if we are in a move we might need to fix up the
1016 * requested latency. */
1017 pa_source_output_set_requested_latency_within_thread(o
, o
->thread_info
.requested_source_latency
);
1022 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT
: {
1023 pa_source_output
*o
= PA_SOURCE_OUTPUT(userdata
);
1025 pa_source_output_set_state_within_thread(o
, o
->state
);
1030 pa_assert(o
->thread_info
.attached
);
1031 o
->thread_info
.attached
= FALSE
;
1033 if (o
->thread_info
.direct_on_input
) {
1034 pa_hashmap_remove(o
->thread_info
.direct_on_input
->thread_info
.direct_outputs
, PA_UINT32_TO_PTR(o
->index
));
1035 o
->thread_info
.direct_on_input
= NULL
;
1038 if (pa_hashmap_remove(s
->thread_info
.outputs
, PA_UINT32_TO_PTR(o
->index
)))
1039 pa_source_output_unref(o
);
1041 pa_source_invalidate_requested_latency(s
);
1046 case PA_SOURCE_MESSAGE_SET_VOLUME
:
1047 s
->thread_info
.soft_volume
= s
->soft_volume
;
1050 case PA_SOURCE_MESSAGE_GET_VOLUME
:
1053 case PA_SOURCE_MESSAGE_SET_MUTE
:
1054 s
->thread_info
.soft_muted
= s
->muted
;
1057 case PA_SOURCE_MESSAGE_GET_MUTE
:
1060 case PA_SOURCE_MESSAGE_SET_STATE
: {
1062 pa_bool_t suspend_change
=
1063 (s
->thread_info
.state
== PA_SOURCE_SUSPENDED
&& PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata
))) ||
1064 (PA_SOURCE_IS_OPENED(s
->thread_info
.state
) && PA_PTR_TO_UINT(userdata
) == PA_SOURCE_SUSPENDED
);
1066 s
->thread_info
.state
= PA_PTR_TO_UINT(userdata
);
1068 if (suspend_change
) {
1069 pa_source_output
*o
;
1072 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1073 if (o
->suspend_within_thread
)
1074 o
->suspend_within_thread(o
, s
->thread_info
.state
== PA_SOURCE_SUSPENDED
);
1081 case PA_SOURCE_MESSAGE_DETACH
:
1083 /* Detach all streams */
1084 pa_source_detach_within_thread(s
);
1087 case PA_SOURCE_MESSAGE_ATTACH
:
1089 /* Reattach all streams */
1090 pa_source_attach_within_thread(s
);
1093 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
: {
1095 pa_usec_t
*usec
= userdata
;
1096 *usec
= pa_source_get_requested_latency_within_thread(s
);
1098 if (*usec
== (pa_usec_t
) -1)
1099 *usec
= s
->thread_info
.max_latency
;
1104 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
: {
1105 pa_usec_t
*r
= userdata
;
1107 pa_source_set_latency_range_within_thread(s
, r
[0], r
[1]);
1112 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
: {
1113 pa_usec_t
*r
= userdata
;
1115 r
[0] = s
->thread_info
.min_latency
;
1116 r
[1] = s
->thread_info
.max_latency
;
1121 case PA_SOURCE_MESSAGE_GET_MAX_REWIND
:
1123 *((size_t*) userdata
) = s
->thread_info
.max_rewind
;
1126 case PA_SOURCE_MESSAGE_SET_MAX_REWIND
:
1128 pa_source_set_max_rewind_within_thread(s
, (size_t) offset
);
1131 case PA_SOURCE_MESSAGE_GET_LATENCY
:
1133 if (s
->monitor_of
) {
1134 *((pa_usec_t
*) userdata
) = 0;
1138 /* Implementors need to overwrite this implementation! */
1141 case PA_SOURCE_MESSAGE_MAX
:
1148 /* Called from main thread */
1149 int pa_source_suspend_all(pa_core
*c
, pa_bool_t suspend
, pa_suspend_cause_t cause
) {
1154 pa_core_assert_ref(c
);
1155 pa_assert_ctl_context();
1156 pa_assert(cause
!= 0);
1158 for (source
= PA_SOURCE(pa_idxset_first(c
->sources
, &idx
)); source
; source
= PA_SOURCE(pa_idxset_next(c
->sources
, &idx
))) {
1161 if (source
->monitor_of
)
1164 if ((r
= pa_source_suspend(source
, suspend
, cause
)) < 0)
1171 /* Called from main thread */
1172 void pa_source_detach(pa_source
*s
) {
1173 pa_source_assert_ref(s
);
1174 pa_assert_ctl_context();
1175 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1177 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_DETACH
, NULL
, 0, NULL
) == 0);
1180 /* Called from main thread */
1181 void pa_source_attach(pa_source
*s
) {
1182 pa_source_assert_ref(s
);
1183 pa_assert_ctl_context();
1184 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1186 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_ATTACH
, NULL
, 0, NULL
) == 0);
1189 /* Called from IO thread */
1190 void pa_source_detach_within_thread(pa_source
*s
) {
1191 pa_source_output
*o
;
1194 pa_source_assert_ref(s
);
1195 pa_source_assert_io_context(s
);
1196 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1198 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1203 /* Called from IO thread */
1204 void pa_source_attach_within_thread(pa_source
*s
) {
1205 pa_source_output
*o
;
1208 pa_source_assert_ref(s
);
1209 pa_source_assert_io_context(s
);
1210 pa_assert(PA_SOURCE_IS_LINKED(s
->thread_info
.state
));
1212 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1217 /* Called from IO thread */
1218 pa_usec_t
pa_source_get_requested_latency_within_thread(pa_source
*s
) {
1219 pa_usec_t result
= (pa_usec_t
) -1;
1220 pa_source_output
*o
;
1223 pa_source_assert_ref(s
);
1224 pa_source_assert_io_context(s
);
1226 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1227 return PA_CLAMP(s
->fixed_latency
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1229 if (s
->thread_info
.requested_latency_valid
)
1230 return s
->thread_info
.requested_latency
;
1232 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1234 if (o
->thread_info
.requested_source_latency
!= (pa_usec_t
) -1 &&
1235 (result
== (pa_usec_t
) -1 || result
> o
->thread_info
.requested_source_latency
))
1236 result
= o
->thread_info
.requested_source_latency
;
1238 if (result
!= (pa_usec_t
) -1)
1239 result
= PA_CLAMP(result
, s
->thread_info
.min_latency
, s
->thread_info
.max_latency
);
1241 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1242 /* Only cache this if we are fully set up */
1243 s
->thread_info
.requested_latency
= result
;
1244 s
->thread_info
.requested_latency_valid
= TRUE
;
1250 /* Called from main thread */
1251 pa_usec_t
pa_source_get_requested_latency(pa_source
*s
) {
1254 pa_source_assert_ref(s
);
1255 pa_assert_ctl_context();
1256 pa_assert(PA_SOURCE_IS_LINKED(s
->state
));
1258 if (s
->state
== PA_SOURCE_SUSPENDED
)
1261 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY
, &usec
, 0, NULL
) == 0);
1266 /* Called from IO thread */
1267 void pa_source_set_max_rewind_within_thread(pa_source
*s
, size_t max_rewind
) {
1268 pa_source_output
*o
;
1271 pa_source_assert_ref(s
);
1272 pa_source_assert_io_context(s
);
1274 if (max_rewind
== s
->thread_info
.max_rewind
)
1277 s
->thread_info
.max_rewind
= max_rewind
;
1279 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
))
1280 PA_HASHMAP_FOREACH(o
, s
->thread_info
.outputs
, state
)
1281 pa_source_output_update_max_rewind(o
, s
->thread_info
.max_rewind
);
1284 /* Called from main thread */
1285 void pa_source_set_max_rewind(pa_source
*s
, size_t max_rewind
) {
1286 pa_source_assert_ref(s
);
1287 pa_assert_ctl_context();
1289 if (PA_SOURCE_IS_LINKED(s
->state
))
1290 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_MAX_REWIND
, NULL
, max_rewind
, NULL
) == 0);
1292 pa_source_set_max_rewind_within_thread(s
, max_rewind
);
1295 /* Called from IO thread */
1296 void pa_source_invalidate_requested_latency(pa_source
*s
) {
1297 pa_source_output
*o
;
1300 pa_source_assert_ref(s
);
1301 pa_source_assert_io_context(s
);
1303 if (!(s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
))
1306 s
->thread_info
.requested_latency_valid
= FALSE
;
1308 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1310 if (s
->update_requested_latency
)
1311 s
->update_requested_latency(s
);
1313 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1314 if (o
->update_source_requested_latency
)
1315 o
->update_source_requested_latency(o
);
1319 pa_sink_invalidate_requested_latency(s
->monitor_of
);
1322 /* Called from main thread */
1323 void pa_source_set_latency_range(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1324 pa_source_assert_ref(s
);
1325 pa_assert_ctl_context();
1327 /* min_latency == 0: no limit
1328 * min_latency anything else: specified limit
1330 * Similar for max_latency */
1332 if (min_latency
< ABSOLUTE_MIN_LATENCY
)
1333 min_latency
= ABSOLUTE_MIN_LATENCY
;
1335 if (max_latency
<= 0 ||
1336 max_latency
> ABSOLUTE_MAX_LATENCY
)
1337 max_latency
= ABSOLUTE_MAX_LATENCY
;
1339 pa_assert(min_latency
<= max_latency
);
1341 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1342 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1343 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1344 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
));
1346 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1352 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1354 pa_source_set_latency_range_within_thread(s
, min_latency
, max_latency
);
1357 /* Called from main thread */
1358 void pa_source_get_latency_range(pa_source
*s
, pa_usec_t
*min_latency
, pa_usec_t
*max_latency
) {
1359 pa_source_assert_ref(s
);
1360 pa_assert_ctl_context();
1361 pa_assert(min_latency
);
1362 pa_assert(max_latency
);
1364 if (PA_SOURCE_IS_LINKED(s
->state
)) {
1365 pa_usec_t r
[2] = { 0, 0 };
1367 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE
, r
, 0, NULL
) == 0);
1369 *min_latency
= r
[0];
1370 *max_latency
= r
[1];
1372 *min_latency
= s
->thread_info
.min_latency
;
1373 *max_latency
= s
->thread_info
.max_latency
;
1377 /* Called from IO thread, and from main thread before pa_source_put() is called */
1378 void pa_source_set_latency_range_within_thread(pa_source
*s
, pa_usec_t min_latency
, pa_usec_t max_latency
) {
1381 pa_source_assert_ref(s
);
1382 pa_source_assert_io_context(s
);
1384 pa_assert(min_latency
>= ABSOLUTE_MIN_LATENCY
);
1385 pa_assert(max_latency
<= ABSOLUTE_MAX_LATENCY
);
1386 pa_assert(min_latency
<= max_latency
);
1388 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1389 pa_assert((min_latency
== ABSOLUTE_MIN_LATENCY
&&
1390 max_latency
== ABSOLUTE_MAX_LATENCY
) ||
1391 (s
->flags
& PA_SOURCE_DYNAMIC_LATENCY
) ||
1394 s
->thread_info
.min_latency
= min_latency
;
1395 s
->thread_info
.max_latency
= max_latency
;
1397 if (PA_SOURCE_IS_LINKED(s
->thread_info
.state
)) {
1398 pa_source_output
*o
;
1400 while ((o
= pa_hashmap_iterate(s
->thread_info
.outputs
, &state
, NULL
)))
1401 if (o
->update_source_latency_range
)
1402 o
->update_source_latency_range(o
);
1405 pa_source_invalidate_requested_latency(s
);
1408 /* Called from main thread, before the source is put */
1409 void pa_source_set_fixed_latency(pa_source
*s
, pa_usec_t latency
) {
1410 pa_source_assert_ref(s
);
1411 pa_assert_ctl_context();
1413 pa_assert(pa_source_get_state(s
) == PA_SOURCE_INIT
);
1415 if (latency
< ABSOLUTE_MIN_LATENCY
)
1416 latency
= ABSOLUTE_MIN_LATENCY
;
1418 if (latency
> ABSOLUTE_MAX_LATENCY
)
1419 latency
= ABSOLUTE_MAX_LATENCY
;
1421 s
->fixed_latency
= latency
;
1424 /* Called from main thread */
1425 size_t pa_source_get_max_rewind(pa_source
*s
) {
1427 pa_assert_ctl_context();
1428 pa_source_assert_ref(s
);
1430 if (!PA_SOURCE_IS_LINKED(s
->state
))
1431 return s
->thread_info
.max_rewind
;
1433 pa_assert_se(pa_asyncmsgq_send(s
->asyncmsgq
, PA_MSGOBJECT(s
), PA_SOURCE_MESSAGE_GET_MAX_REWIND
, &r
, 0, NULL
) == 0);
1438 /* Called from main context */
1439 int pa_source_set_port(pa_source
*s
, const char *name
, pa_bool_t save
) {
1440 pa_device_port
*port
;
1443 pa_assert_ctl_context();
1446 pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s
->index
, s
->name
);
1447 return -PA_ERR_NOTIMPLEMENTED
;
1451 return -PA_ERR_NOENTITY
;
1453 if (!(port
= pa_hashmap_get(s
->ports
, name
)))
1454 return -PA_ERR_NOENTITY
;
1456 if (s
->active_port
== port
) {
1457 s
->save_port
= s
->save_port
|| save
;
1461 if ((s
->set_port(s
, port
)) < 0)
1462 return -PA_ERR_NOENTITY
;
1464 pa_subscription_post(s
->core
, PA_SUBSCRIPTION_EVENT_SOURCE
|PA_SUBSCRIPTION_EVENT_CHANGE
, s
->index
);
1466 pa_log_info("Changed port of source %u \"%s\" to %s", s
->index
, s
->name
, port
->name
);
1468 s
->active_port
= port
;
1469 s
->save_port
= save
;