]> code.delx.au - pulseaudio/blob - src/pulsecore/source.c
core: introduce pa_{sink,source}_set_fixed_latency()
[pulseaudio] / src / pulsecore / source.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
35
36 #include <pulsecore/source-output.h>
37 #include <pulsecore/namereg.h>
38 #include <pulsecore/core-subscribe.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/sample-util.h>
41
42 #include "source.h"
43
44 #define ABSOLUTE_MIN_LATENCY (500)
45 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
46 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
47
48 static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
49
50 static void source_free(pa_object *o);
51
52 pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
53 pa_assert(data);
54
55 memset(data, 0, sizeof(*data));
56 data->proplist = pa_proplist_new();
57
58 return data;
59 }
60
61 void pa_source_new_data_set_name(pa_source_new_data *data, const char *name) {
62 pa_assert(data);
63
64 pa_xfree(data->name);
65 data->name = pa_xstrdup(name);
66 }
67
68 void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sample_spec *spec) {
69 pa_assert(data);
70
71 if ((data->sample_spec_is_set = !!spec))
72 data->sample_spec = *spec;
73 }
74
75 void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_channel_map *map) {
76 pa_assert(data);
77
78 if ((data->channel_map_is_set = !!map))
79 data->channel_map = *map;
80 }
81
82 void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume) {
83 pa_assert(data);
84
85 if ((data->volume_is_set = !!volume))
86 data->volume = *volume;
87 }
88
89 void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute) {
90 pa_assert(data);
91
92 data->muted_is_set = TRUE;
93 data->muted = !!mute;
94 }
95
96 void pa_source_new_data_done(pa_source_new_data *data) {
97 pa_assert(data);
98
99 pa_xfree(data->name);
100 pa_proplist_free(data->proplist);
101 }
102
103 /* Called from main context */
104 static void reset_callbacks(pa_source *s) {
105 pa_assert(s);
106
107 s->set_state = NULL;
108 s->get_volume = NULL;
109 s->set_volume = NULL;
110 s->get_mute = NULL;
111 s->set_mute = NULL;
112 s->update_requested_latency = NULL;
113 }
114
115 /* Called from main context */
116 pa_source* pa_source_new(
117 pa_core *core,
118 pa_source_new_data *data,
119 pa_source_flags_t flags) {
120
121 pa_source *s;
122 const char *name;
123 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
124 char *pt;
125
126 pa_assert(core);
127 pa_assert(data);
128 pa_assert(data->name);
129
130 s = pa_msgobject_new(pa_source);
131
132 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
133 pa_xfree(s);
134 return NULL;
135 }
136
137 pa_source_new_data_set_name(data, name);
138
139 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
140 pa_xfree(s);
141 pa_namereg_unregister(core, name);
142 return NULL;
143 }
144
145 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
146 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
147
148 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
149
150 if (!data->channel_map_is_set)
151 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
152
153 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
154 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
155
156 if (!data->volume_is_set)
157 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
158
159 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
160 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
161
162 if (!data->muted_is_set)
163 data->muted = FALSE;
164
165 if (data->card)
166 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
167
168 pa_device_init_description(data->proplist);
169 pa_device_init_icon(data->proplist, FALSE);
170
171 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
172 pa_xfree(s);
173 pa_namereg_unregister(core, name);
174 return NULL;
175 }
176
177 s->parent.parent.free = source_free;
178 s->parent.process_msg = pa_source_process_msg;
179
180 s->core = core;
181 s->state = PA_SOURCE_INIT;
182 s->flags = flags;
183 s->name = pa_xstrdup(name);
184 s->proplist = pa_proplist_copy(data->proplist);
185 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
186 s->module = data->module;
187 s->card = data->card;
188
189 s->sample_spec = data->sample_spec;
190 s->channel_map = data->channel_map;
191
192 s->outputs = pa_idxset_new(NULL, NULL);
193 s->n_corked = 0;
194 s->monitor_of = NULL;
195
196 s->virtual_volume = data->volume;
197 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
198 s->base_volume = PA_VOLUME_NORM;
199 s->n_volume_steps = PA_VOLUME_NORM+1;
200 s->muted = data->muted;
201 s->refresh_volume = s->refresh_muted = FALSE;
202
203 s->fixed_latency = flags & PA_SOURCE_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
204
205 reset_callbacks(s);
206 s->userdata = NULL;
207
208 s->asyncmsgq = NULL;
209 s->rtpoll = NULL;
210
211 pa_silence_memchunk_get(
212 &core->silence_cache,
213 core->mempool,
214 &s->silence,
215 &s->sample_spec,
216 0);
217
218 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
219 s->thread_info.soft_volume = s->soft_volume;
220 s->thread_info.soft_muted = s->muted;
221 s->thread_info.state = s->state;
222 s->thread_info.max_rewind = 0;
223 s->thread_info.requested_latency_valid = FALSE;
224 s->thread_info.requested_latency = 0;
225 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
226 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
227
228 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
229
230 if (s->card)
231 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
232
233 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
234 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
235 s->index,
236 s->name,
237 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
238 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
239 pt);
240 pa_xfree(pt);
241
242 return s;
243 }
244
245 /* Called from main context */
246 static int source_set_state(pa_source *s, pa_source_state_t state) {
247 int ret;
248 pa_bool_t suspend_change;
249 pa_source_state_t original_state;
250
251 pa_assert(s);
252
253 if (s->state == state)
254 return 0;
255
256 original_state = s->state;
257
258 suspend_change =
259 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
260 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
261
262 if (s->set_state)
263 if ((ret = s->set_state(s, state)) < 0)
264 return ret;
265
266 if (s->asyncmsgq)
267 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
268
269 if (s->set_state)
270 s->set_state(s, original_state);
271
272 return ret;
273 }
274
275 s->state = state;
276
277 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
278 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
279 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
280 }
281
282 if (suspend_change) {
283 pa_source_output *o;
284 uint32_t idx;
285
286 /* We're suspending or resuming, tell everyone about it */
287
288 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
289 if (s->state == PA_SOURCE_SUSPENDED &&
290 (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
291 pa_source_output_kill(o);
292 else if (o->suspend)
293 o->suspend(o, state == PA_SOURCE_SUSPENDED);
294 }
295
296
297 return 0;
298 }
299
300 /* Called from main context */
301 void pa_source_put(pa_source *s) {
302 pa_source_assert_ref(s);
303
304 pa_assert(s->state == PA_SOURCE_INIT);
305
306 /* The following fields must be initialized properly when calling _put() */
307 pa_assert(s->asyncmsgq);
308 pa_assert(s->rtpoll);
309 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
310
311 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) {
312 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
313
314 s->thread_info.soft_volume = s->soft_volume;
315 s->thread_info.soft_muted = s->muted;
316 }
317
318 if (s->flags & PA_SOURCE_DECIBEL_VOLUME)
319 s->n_volume_steps = PA_VOLUME_NORM+1;
320
321 if (s->flags & PA_SOURCE_DYNAMIC_LATENCY)
322 s->fixed_latency = 0;
323 else if (s->fixed_latency <= 0)
324 s->fixed_latency = DEFAULT_FIXED_LATENCY;
325
326 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
327
328 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
329 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
330 }
331
332 /* Called from main context */
333 void pa_source_unlink(pa_source *s) {
334 pa_bool_t linked;
335 pa_source_output *o, *j = NULL;
336
337 pa_assert(s);
338
339 /* See pa_sink_unlink() for a couple of comments how this function
340 * works. */
341
342 linked = PA_SOURCE_IS_LINKED(s->state);
343
344 if (linked)
345 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
346
347 if (s->state != PA_SOURCE_UNLINKED)
348 pa_namereg_unregister(s->core, s->name);
349 pa_idxset_remove_by_data(s->core->sources, s, NULL);
350
351 if (s->card)
352 pa_idxset_remove_by_data(s->card->sources, s, NULL);
353
354 while ((o = pa_idxset_first(s->outputs, NULL))) {
355 pa_assert(o != j);
356 pa_source_output_kill(o);
357 j = o;
358 }
359
360 if (linked)
361 source_set_state(s, PA_SOURCE_UNLINKED);
362 else
363 s->state = PA_SOURCE_UNLINKED;
364
365 reset_callbacks(s);
366
367 if (linked) {
368 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
369 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
370 }
371 }
372
373 /* Called from main context */
374 static void source_free(pa_object *o) {
375 pa_source_output *so;
376 pa_source *s = PA_SOURCE(o);
377
378 pa_assert(s);
379 pa_assert(pa_source_refcnt(s) == 0);
380
381 if (PA_SOURCE_IS_LINKED(s->state))
382 pa_source_unlink(s);
383
384 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
385
386 pa_idxset_free(s->outputs, NULL, NULL);
387
388 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
389 pa_source_output_unref(so);
390
391 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
392
393 if (s->silence.memblock)
394 pa_memblock_unref(s->silence.memblock);
395
396 pa_xfree(s->name);
397 pa_xfree(s->driver);
398
399 if (s->proplist)
400 pa_proplist_free(s->proplist);
401
402 pa_xfree(s);
403 }
404
405 /* Called from main context */
406 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
407 pa_source_assert_ref(s);
408
409 s->asyncmsgq = q;
410 }
411
412 /* Called from main context */
413 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
414 pa_source_assert_ref(s);
415
416 s->rtpoll = p;
417 }
418
419 /* Called from main context */
420 int pa_source_update_status(pa_source*s) {
421 pa_source_assert_ref(s);
422 pa_assert(PA_SOURCE_IS_LINKED(s->state));
423
424 if (s->state == PA_SOURCE_SUSPENDED)
425 return 0;
426
427 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
428 }
429
430 /* Called from main context */
431 int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
432 pa_source_assert_ref(s);
433 pa_assert(PA_SOURCE_IS_LINKED(s->state));
434
435 if (s->monitor_of)
436 return -PA_ERR_NOTSUPPORTED;
437
438 if (suspend)
439 return source_set_state(s, PA_SOURCE_SUSPENDED);
440 else
441 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
442 }
443
444 /* Called from main context */
445 int pa_source_sync_suspend(pa_source *s) {
446 pa_sink_state_t state;
447
448 pa_source_assert_ref(s);
449 pa_assert(PA_SOURCE_IS_LINKED(s->state));
450 pa_assert(s->monitor_of);
451
452 state = pa_sink_get_state(s->monitor_of);
453
454 if (state == PA_SINK_SUSPENDED)
455 return source_set_state(s, PA_SOURCE_SUSPENDED);
456
457 pa_assert(PA_SINK_IS_OPENED(state));
458
459 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
460 }
461
462 /* Called from main context */
463 pa_queue *pa_source_move_all_start(pa_source *s) {
464 pa_queue *q;
465 pa_source_output *o, *n;
466 uint32_t idx;
467
468 pa_source_assert_ref(s);
469 pa_assert(PA_SOURCE_IS_LINKED(s->state));
470
471 q = pa_queue_new();
472
473 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
474 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
475
476 pa_source_output_ref(o);
477
478 if (pa_source_output_start_move(o) >= 0)
479 pa_queue_push(q, o);
480 else
481 pa_source_output_unref(o);
482 }
483
484 return q;
485 }
486
487 /* Called from main context */
488 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
489 pa_source_output *o;
490
491 pa_source_assert_ref(s);
492 pa_assert(PA_SOURCE_IS_LINKED(s->state));
493 pa_assert(q);
494
495 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
496 if (pa_source_output_finish_move(o, s, save) < 0)
497 pa_source_output_kill(o);
498
499 pa_source_output_unref(o);
500 }
501
502 pa_queue_free(q, NULL, NULL);
503 }
504
505 /* Called from main context */
506 void pa_source_move_all_fail(pa_queue *q) {
507 pa_source_output *o;
508 pa_assert(q);
509
510 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
511 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
512 pa_source_output_kill(o);
513 pa_source_output_unref(o);
514 }
515 }
516
517 pa_queue_free(q, NULL, NULL);
518 }
519
520 /* Called from IO thread context */
521 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
522 pa_source_output *o;
523 void *state = NULL;
524
525 pa_source_assert_ref(s);
526 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
527
528 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
529 return;
530
531 if (nbytes <= 0)
532 return;
533
534 pa_log_debug("Processing rewind...");
535
536 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
537 pa_source_output_assert_ref(o);
538 pa_source_output_process_rewind(o, nbytes);
539 }
540 }
541
542 /* Called from IO thread context */
543 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
544 pa_source_output *o;
545 void *state = NULL;
546
547 pa_source_assert_ref(s);
548 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
549 pa_assert(chunk);
550
551 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
552 return;
553
554 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
555 pa_memchunk vchunk = *chunk;
556
557 pa_memblock_ref(vchunk.memblock);
558 pa_memchunk_make_writable(&vchunk, 0);
559
560 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
561 pa_silence_memchunk(&vchunk, &s->sample_spec);
562 else
563 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
564
565 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
566 pa_source_output_assert_ref(o);
567
568 if (!o->thread_info.direct_on_input)
569 pa_source_output_push(o, &vchunk);
570 }
571
572 pa_memblock_unref(vchunk.memblock);
573 } else {
574
575 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
576 pa_source_output_assert_ref(o);
577
578 if (!o->thread_info.direct_on_input)
579 pa_source_output_push(o, chunk);
580 }
581 }
582 }
583
584 /* Called from IO thread context */
585 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
586 pa_source_assert_ref(s);
587 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
588 pa_source_output_assert_ref(o);
589 pa_assert(o->thread_info.direct_on_input);
590 pa_assert(chunk);
591
592 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
593 return;
594
595 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
596 pa_memchunk vchunk = *chunk;
597
598 pa_memblock_ref(vchunk.memblock);
599 pa_memchunk_make_writable(&vchunk, 0);
600
601 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
602 pa_silence_memchunk(&vchunk, &s->sample_spec);
603 else
604 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
605
606 pa_source_output_push(o, &vchunk);
607
608 pa_memblock_unref(vchunk.memblock);
609 } else
610 pa_source_output_push(o, chunk);
611 }
612
613 /* Called from main thread */
614 pa_usec_t pa_source_get_latency(pa_source *s) {
615 pa_usec_t usec;
616
617 pa_source_assert_ref(s);
618 pa_assert(PA_SOURCE_IS_LINKED(s->state));
619
620 if (s->state == PA_SOURCE_SUSPENDED)
621 return 0;
622
623 if (!(s->flags & PA_SOURCE_LATENCY))
624 return 0;
625
626 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
627
628 return usec;
629 }
630
631 /* Called from IO thread */
632 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
633 pa_usec_t usec = 0;
634 pa_msgobject *o;
635
636 pa_source_assert_ref(s);
637 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
638
639 /* The returned value is supposed to be in the time domain of the sound card! */
640
641 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
642 return 0;
643
644 if (!(s->flags & PA_SOURCE_LATENCY))
645 return 0;
646
647 o = PA_MSGOBJECT(s);
648
649 /* We probably should make this a proper vtable callback instead of going through process_msg() */
650
651 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
652 return -1;
653
654 return usec;
655 }
656
657 /* Called from main thread */
658 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
659 pa_cvolume old_virtual_volume;
660 pa_bool_t virtual_volume_changed;
661
662 pa_source_assert_ref(s);
663 pa_assert(PA_SOURCE_IS_LINKED(s->state));
664 pa_assert(volume);
665 pa_assert(pa_cvolume_valid(volume));
666 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
667
668 old_virtual_volume = s->virtual_volume;
669 s->virtual_volume = *volume;
670 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
671
672 if (s->set_volume) {
673 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
674 s->set_volume(s);
675 } else
676 s->soft_volume = s->virtual_volume;
677
678 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
679
680 if (virtual_volume_changed)
681 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
682 }
683
684 /* Called from main thread. Only to be called by source implementor */
685 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
686 pa_source_assert_ref(s);
687 pa_assert(volume);
688
689 if (PA_SOURCE_IS_LINKED(s->state))
690 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
691 else
692 s->thread_info.soft_volume = *volume;
693 }
694
695 /* Called from main thread */
696 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
697 pa_source_assert_ref(s);
698 pa_assert(PA_SOURCE_IS_LINKED(s->state));
699
700 if (s->refresh_volume || force_refresh) {
701 pa_cvolume old_virtual_volume = s->virtual_volume;
702
703 if (s->get_volume)
704 s->get_volume(s);
705
706 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
707
708 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
709 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
710 }
711
712 return &s->virtual_volume;
713 }
714
715 /* Called from main thread */
716 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
717 pa_source_assert_ref(s);
718
719 /* The source implementor may call this if the volume changed to make sure everyone is notified */
720
721 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
722 return;
723
724 s->virtual_volume = *new_volume;
725 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
726 }
727
728 /* Called from main thread */
729 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
730 pa_bool_t old_muted;
731
732 pa_source_assert_ref(s);
733 pa_assert(PA_SOURCE_IS_LINKED(s->state));
734
735 old_muted = s->muted;
736 s->muted = mute;
737
738 if (s->set_mute)
739 s->set_mute(s);
740
741 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
742
743 if (old_muted != s->muted)
744 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
745 }
746
747 /* Called from main thread */
748 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
749 pa_source_assert_ref(s);
750 pa_assert(PA_SOURCE_IS_LINKED(s->state));
751
752 if (s->refresh_muted || force_refresh) {
753 pa_bool_t old_muted = s->muted;
754
755 if (s->get_mute)
756 s->get_mute(s);
757
758 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
759
760 if (old_muted != s->muted)
761 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
762 }
763
764 return s->muted;
765 }
766
767 /* Called from main thread */
768 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
769 pa_source_assert_ref(s);
770
771 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
772
773 if (s->muted == new_muted)
774 return;
775
776 s->muted = new_muted;
777 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
778 }
779
780 /* Called from main thread */
781 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
782 pa_source_assert_ref(s);
783
784 if (p)
785 pa_proplist_update(s->proplist, mode, p);
786
787 if (PA_SOURCE_IS_LINKED(s->state)) {
788 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
789 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
790 }
791
792 return TRUE;
793 }
794
795 /* Called from main thread */
796 void pa_source_set_description(pa_source *s, const char *description) {
797 const char *old;
798 pa_source_assert_ref(s);
799
800 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
801 return;
802
803 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
804
805 if (old && description && !strcmp(old, description))
806 return;
807
808 if (description)
809 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
810 else
811 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
812
813 if (PA_SOURCE_IS_LINKED(s->state)) {
814 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
815 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
816 }
817 }
818
819 /* Called from main thread */
820 unsigned pa_source_linked_by(pa_source *s) {
821 pa_source_assert_ref(s);
822 pa_assert(PA_SOURCE_IS_LINKED(s->state));
823
824 return pa_idxset_size(s->outputs);
825 }
826
827 /* Called from main thread */
828 unsigned pa_source_used_by(pa_source *s) {
829 unsigned ret;
830
831 pa_source_assert_ref(s);
832 pa_assert(PA_SOURCE_IS_LINKED(s->state));
833
834 ret = pa_idxset_size(s->outputs);
835 pa_assert(ret >= s->n_corked);
836
837 return ret - s->n_corked;
838 }
839
840 /* Called from main thread */
841 unsigned pa_source_check_suspend(pa_source *s) {
842 unsigned ret;
843 pa_source_output *o;
844 uint32_t idx;
845
846 pa_source_assert_ref(s);
847
848 if (!PA_SOURCE_IS_LINKED(s->state))
849 return 0;
850
851 ret = 0;
852
853 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
854 pa_source_output_state_t st;
855
856 st = pa_source_output_get_state(o);
857 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
858
859 if (st == PA_SOURCE_OUTPUT_CORKED)
860 continue;
861
862 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
863 continue;
864
865 ret ++;
866 }
867
868 return ret;
869 }
870
871 /* Called from IO thread, except when it is not */
872 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
873 pa_source *s = PA_SOURCE(object);
874 pa_source_assert_ref(s);
875
876 switch ((pa_source_message_t) code) {
877
878 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
879 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
880
881 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
882
883 if (o->direct_on_input) {
884 o->thread_info.direct_on_input = o->direct_on_input;
885 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
886 }
887
888 pa_assert(!o->thread_info.attached);
889 o->thread_info.attached = TRUE;
890
891 if (o->attach)
892 o->attach(o);
893
894 pa_source_output_set_state_within_thread(o, o->state);
895
896 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
897 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
898
899 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
900
901 /* We don't just invalidate the requested latency here,
902 * because if we are in a move we might need to fix up the
903 * requested latency. */
904 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
905
906 return 0;
907 }
908
909 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
910 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
911
912 pa_source_output_set_state_within_thread(o, o->state);
913
914 if (o->detach)
915 o->detach(o);
916
917 pa_assert(o->thread_info.attached);
918 o->thread_info.attached = FALSE;
919
920 if (o->thread_info.direct_on_input) {
921 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
922 o->thread_info.direct_on_input = NULL;
923 }
924
925 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
926 pa_source_output_unref(o);
927
928 pa_source_invalidate_requested_latency(s);
929
930 return 0;
931 }
932
933 case PA_SOURCE_MESSAGE_SET_VOLUME:
934 s->thread_info.soft_volume = s->soft_volume;
935 return 0;
936
937 case PA_SOURCE_MESSAGE_GET_VOLUME:
938 return 0;
939
940 case PA_SOURCE_MESSAGE_SET_MUTE:
941 s->thread_info.soft_muted = s->muted;
942 return 0;
943
944 case PA_SOURCE_MESSAGE_GET_MUTE:
945 return 0;
946
947 case PA_SOURCE_MESSAGE_SET_STATE: {
948
949 pa_bool_t suspend_change =
950 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
951 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
952
953 s->thread_info.state = PA_PTR_TO_UINT(userdata);
954
955 if (suspend_change) {
956 pa_source_output *o;
957 void *state = NULL;
958
959 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
960 if (o->suspend_within_thread)
961 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
962 }
963
964
965 return 0;
966 }
967
968 case PA_SOURCE_MESSAGE_DETACH:
969
970 /* Detach all streams */
971 pa_source_detach_within_thread(s);
972 return 0;
973
974 case PA_SOURCE_MESSAGE_ATTACH:
975
976 /* Reattach all streams */
977 pa_source_attach_within_thread(s);
978 return 0;
979
980 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
981
982 pa_usec_t *usec = userdata;
983 *usec = pa_source_get_requested_latency_within_thread(s);
984
985 if (*usec == (pa_usec_t) -1)
986 *usec = s->thread_info.max_latency;
987
988 return 0;
989 }
990
991 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
992 pa_usec_t *r = userdata;
993
994 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
995
996 return 0;
997 }
998
999 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
1000 pa_usec_t *r = userdata;
1001
1002 r[0] = s->thread_info.min_latency;
1003 r[1] = s->thread_info.max_latency;
1004
1005 return 0;
1006 }
1007
1008 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1009
1010 *((size_t*) userdata) = s->thread_info.max_rewind;
1011 return 0;
1012
1013 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1014
1015 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1016 return 0;
1017
1018 case PA_SOURCE_MESSAGE_GET_LATENCY:
1019
1020 if (s->monitor_of) {
1021 *((pa_usec_t*) userdata) = 0;
1022 return 0;
1023 }
1024
1025 /* Implementors need to overwrite this implementation! */
1026 return -1;
1027
1028 case PA_SOURCE_MESSAGE_MAX:
1029 ;
1030 }
1031
1032 return -1;
1033 }
1034
1035 /* Called from main thread */
1036 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
1037 uint32_t idx;
1038 pa_source *source;
1039 int ret = 0;
1040
1041 pa_core_assert_ref(c);
1042
1043 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1044 int r;
1045
1046 if (source->monitor_of)
1047 continue;
1048
1049 if ((r = pa_source_suspend(source, suspend)) < 0)
1050 ret = r;
1051 }
1052
1053 return ret;
1054 }
1055
1056 /* Called from main thread */
1057 void pa_source_detach(pa_source *s) {
1058 pa_source_assert_ref(s);
1059 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1060
1061 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1062 }
1063
1064 /* Called from main thread */
1065 void pa_source_attach(pa_source *s) {
1066 pa_source_assert_ref(s);
1067 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1068
1069 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1070 }
1071
1072 /* Called from IO thread */
1073 void pa_source_detach_within_thread(pa_source *s) {
1074 pa_source_output *o;
1075 void *state = NULL;
1076
1077 pa_source_assert_ref(s);
1078 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1079
1080 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1081 if (o->detach)
1082 o->detach(o);
1083 }
1084
1085 /* Called from IO thread */
1086 void pa_source_attach_within_thread(pa_source *s) {
1087 pa_source_output *o;
1088 void *state = NULL;
1089
1090 pa_source_assert_ref(s);
1091 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1092
1093 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1094 if (o->attach)
1095 o->attach(o);
1096 }
1097
1098 /* Called from IO thread */
1099 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1100 pa_usec_t result = (pa_usec_t) -1;
1101 pa_source_output *o;
1102 void *state = NULL;
1103
1104 pa_source_assert_ref(s);
1105
1106 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1107 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1108
1109 if (s->thread_info.requested_latency_valid)
1110 return s->thread_info.requested_latency;
1111
1112 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1113
1114 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1115 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1116 result = o->thread_info.requested_source_latency;
1117
1118 if (result != (pa_usec_t) -1)
1119 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1120
1121 s->thread_info.requested_latency = result;
1122 s->thread_info.requested_latency_valid = TRUE;
1123
1124 return result;
1125 }
1126
1127 /* Called from main thread */
1128 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1129 pa_usec_t usec = 0;
1130
1131 pa_source_assert_ref(s);
1132 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1133
1134 if (s->state == PA_SOURCE_SUSPENDED)
1135 return 0;
1136
1137 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1138
1139 return usec;
1140 }
1141
1142 /* Called from IO thread */
1143 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1144 pa_source_output *o;
1145 void *state = NULL;
1146
1147 pa_source_assert_ref(s);
1148
1149 if (max_rewind == s->thread_info.max_rewind)
1150 return;
1151
1152 s->thread_info.max_rewind = max_rewind;
1153
1154 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1155 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1156 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1157 }
1158 }
1159
1160 /* Called from main thread */
1161 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1162 pa_source_assert_ref(s);
1163
1164 if (PA_SOURCE_IS_LINKED(s->state))
1165 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1166 else
1167 pa_source_set_max_rewind_within_thread(s, max_rewind);
1168 }
1169
1170 /* Called from IO thread */
1171 void pa_source_invalidate_requested_latency(pa_source *s) {
1172 pa_source_output *o;
1173 void *state = NULL;
1174
1175 pa_source_assert_ref(s);
1176
1177 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1178 return;
1179
1180 s->thread_info.requested_latency_valid = FALSE;
1181
1182 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1183
1184 if (s->update_requested_latency)
1185 s->update_requested_latency(s);
1186
1187 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1188 if (o->update_source_requested_latency)
1189 o->update_source_requested_latency(o);
1190 }
1191
1192 if (s->monitor_of)
1193 pa_sink_invalidate_requested_latency(s->monitor_of);
1194 }
1195
1196 /* Called from main thread */
1197 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1198 pa_source_assert_ref(s);
1199
1200 /* min_latency == 0: no limit
1201 * min_latency anything else: specified limit
1202 *
1203 * Similar for max_latency */
1204
1205 if (min_latency < ABSOLUTE_MIN_LATENCY)
1206 min_latency = ABSOLUTE_MIN_LATENCY;
1207
1208 if (max_latency <= 0 ||
1209 max_latency > ABSOLUTE_MAX_LATENCY)
1210 max_latency = ABSOLUTE_MAX_LATENCY;
1211
1212 pa_assert(min_latency <= max_latency);
1213
1214 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1215 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1216 max_latency == ABSOLUTE_MAX_LATENCY) ||
1217 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1218
1219 if (PA_SOURCE_IS_LINKED(s->state)) {
1220 pa_usec_t r[2];
1221
1222 r[0] = min_latency;
1223 r[1] = max_latency;
1224
1225 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1226 } else
1227 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1228 }
1229
1230 /* Called from main thread */
1231 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1232 pa_source_assert_ref(s);
1233 pa_assert(min_latency);
1234 pa_assert(max_latency);
1235
1236 if (PA_SOURCE_IS_LINKED(s->state)) {
1237 pa_usec_t r[2] = { 0, 0 };
1238
1239 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1240
1241 *min_latency = r[0];
1242 *max_latency = r[1];
1243 } else {
1244 *min_latency = s->thread_info.min_latency;
1245 *max_latency = s->thread_info.max_latency;
1246 }
1247 }
1248
1249 /* Called from IO thread, and from main thread before pa_source_put() is called */
1250 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1251 void *state = NULL;
1252
1253 pa_source_assert_ref(s);
1254
1255 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1256 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1257 pa_assert(min_latency <= max_latency);
1258
1259 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1260 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1261 max_latency == ABSOLUTE_MAX_LATENCY) ||
1262 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1263 s->monitor_of);
1264
1265 s->thread_info.min_latency = min_latency;
1266 s->thread_info.max_latency = max_latency;
1267
1268 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1269 pa_source_output *o;
1270
1271 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1272 if (o->update_source_latency_range)
1273 o->update_source_latency_range(o);
1274 }
1275
1276 pa_source_invalidate_requested_latency(s);
1277 }
1278
1279 /* Called from main thread, before the source is put */
1280 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1281 pa_source_assert_ref(s);
1282
1283 pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1284
1285 if (latency < ABSOLUTE_MIN_LATENCY)
1286 latency = ABSOLUTE_MIN_LATENCY;
1287
1288 if (latency > ABSOLUTE_MAX_LATENCY)
1289 latency = ABSOLUTE_MAX_LATENCY;
1290
1291 s->fixed_latency = latency;
1292 }
1293
1294 /* Called from main thread */
1295 size_t pa_source_get_max_rewind(pa_source *s) {
1296 size_t r;
1297 pa_source_assert_ref(s);
1298
1299 if (!PA_SOURCE_IS_LINKED(s->state))
1300 return s->thread_info.max_rewind;
1301
1302 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1303
1304 return r;
1305 }