]> code.delx.au - pulseaudio/blob - src/pulsecore/source.c
core: liberalize 99a6a4 a bit
[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 /* Generally, flags should be initialized via pa_source_new(). As
312 * a special exception we allow volume related flags to be set
313 * between _new() and _put(). */
314
315 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL))
316 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
317
318 s->thread_info.soft_volume = s->soft_volume;
319 s->thread_info.soft_muted = s->muted;
320
321 pa_assert((s->flags & PA_SOURCE_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SOURCE_DECIBEL_VOLUME));
322 pa_assert(!(s->flags & PA_SOURCE_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
323 pa_assert(!(s->flags & PA_SOURCE_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
324
325 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
326
327 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
328 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
329 }
330
331 /* Called from main context */
332 void pa_source_unlink(pa_source *s) {
333 pa_bool_t linked;
334 pa_source_output *o, *j = NULL;
335
336 pa_assert(s);
337
338 /* See pa_sink_unlink() for a couple of comments how this function
339 * works. */
340
341 linked = PA_SOURCE_IS_LINKED(s->state);
342
343 if (linked)
344 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
345
346 if (s->state != PA_SOURCE_UNLINKED)
347 pa_namereg_unregister(s->core, s->name);
348 pa_idxset_remove_by_data(s->core->sources, s, NULL);
349
350 if (s->card)
351 pa_idxset_remove_by_data(s->card->sources, s, NULL);
352
353 while ((o = pa_idxset_first(s->outputs, NULL))) {
354 pa_assert(o != j);
355 pa_source_output_kill(o);
356 j = o;
357 }
358
359 if (linked)
360 source_set_state(s, PA_SOURCE_UNLINKED);
361 else
362 s->state = PA_SOURCE_UNLINKED;
363
364 reset_callbacks(s);
365
366 if (linked) {
367 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
368 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
369 }
370 }
371
372 /* Called from main context */
373 static void source_free(pa_object *o) {
374 pa_source_output *so;
375 pa_source *s = PA_SOURCE(o);
376
377 pa_assert(s);
378 pa_assert(pa_source_refcnt(s) == 0);
379
380 if (PA_SOURCE_IS_LINKED(s->state))
381 pa_source_unlink(s);
382
383 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
384
385 pa_idxset_free(s->outputs, NULL, NULL);
386
387 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
388 pa_source_output_unref(so);
389
390 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
391
392 if (s->silence.memblock)
393 pa_memblock_unref(s->silence.memblock);
394
395 pa_xfree(s->name);
396 pa_xfree(s->driver);
397
398 if (s->proplist)
399 pa_proplist_free(s->proplist);
400
401 pa_xfree(s);
402 }
403
404 /* Called from main context */
405 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
406 pa_source_assert_ref(s);
407
408 s->asyncmsgq = q;
409 }
410
411 /* Called from main context */
412 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
413 pa_source_assert_ref(s);
414
415 s->rtpoll = p;
416 }
417
418 /* Called from main context */
419 int pa_source_update_status(pa_source*s) {
420 pa_source_assert_ref(s);
421 pa_assert(PA_SOURCE_IS_LINKED(s->state));
422
423 if (s->state == PA_SOURCE_SUSPENDED)
424 return 0;
425
426 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
427 }
428
429 /* Called from main context */
430 int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
431 pa_source_assert_ref(s);
432 pa_assert(PA_SOURCE_IS_LINKED(s->state));
433
434 if (s->monitor_of)
435 return -PA_ERR_NOTSUPPORTED;
436
437 if (suspend)
438 return source_set_state(s, PA_SOURCE_SUSPENDED);
439 else
440 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
441 }
442
443 /* Called from main context */
444 int pa_source_sync_suspend(pa_source *s) {
445 pa_sink_state_t state;
446
447 pa_source_assert_ref(s);
448 pa_assert(PA_SOURCE_IS_LINKED(s->state));
449 pa_assert(s->monitor_of);
450
451 state = pa_sink_get_state(s->monitor_of);
452
453 if (state == PA_SINK_SUSPENDED)
454 return source_set_state(s, PA_SOURCE_SUSPENDED);
455
456 pa_assert(PA_SINK_IS_OPENED(state));
457
458 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
459 }
460
461 /* Called from main context */
462 pa_queue *pa_source_move_all_start(pa_source *s) {
463 pa_queue *q;
464 pa_source_output *o, *n;
465 uint32_t idx;
466
467 pa_source_assert_ref(s);
468 pa_assert(PA_SOURCE_IS_LINKED(s->state));
469
470 q = pa_queue_new();
471
472 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
473 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
474
475 pa_source_output_ref(o);
476
477 if (pa_source_output_start_move(o) >= 0)
478 pa_queue_push(q, o);
479 else
480 pa_source_output_unref(o);
481 }
482
483 return q;
484 }
485
486 /* Called from main context */
487 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
488 pa_source_output *o;
489
490 pa_source_assert_ref(s);
491 pa_assert(PA_SOURCE_IS_LINKED(s->state));
492 pa_assert(q);
493
494 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
495 if (pa_source_output_finish_move(o, s, save) < 0)
496 pa_source_output_kill(o);
497
498 pa_source_output_unref(o);
499 }
500
501 pa_queue_free(q, NULL, NULL);
502 }
503
504 /* Called from main context */
505 void pa_source_move_all_fail(pa_queue *q) {
506 pa_source_output *o;
507 pa_assert(q);
508
509 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
510 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
511 pa_source_output_kill(o);
512 pa_source_output_unref(o);
513 }
514 }
515
516 pa_queue_free(q, NULL, NULL);
517 }
518
519 /* Called from IO thread context */
520 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
521 pa_source_output *o;
522 void *state = NULL;
523
524 pa_source_assert_ref(s);
525 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
526
527 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
528 return;
529
530 if (nbytes <= 0)
531 return;
532
533 pa_log_debug("Processing rewind...");
534
535 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
536 pa_source_output_assert_ref(o);
537 pa_source_output_process_rewind(o, nbytes);
538 }
539 }
540
541 /* Called from IO thread context */
542 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
543 pa_source_output *o;
544 void *state = NULL;
545
546 pa_source_assert_ref(s);
547 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
548 pa_assert(chunk);
549
550 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
551 return;
552
553 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
554 pa_memchunk vchunk = *chunk;
555
556 pa_memblock_ref(vchunk.memblock);
557 pa_memchunk_make_writable(&vchunk, 0);
558
559 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
560 pa_silence_memchunk(&vchunk, &s->sample_spec);
561 else
562 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
563
564 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
565 pa_source_output_assert_ref(o);
566
567 if (!o->thread_info.direct_on_input)
568 pa_source_output_push(o, &vchunk);
569 }
570
571 pa_memblock_unref(vchunk.memblock);
572 } else {
573
574 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
575 pa_source_output_assert_ref(o);
576
577 if (!o->thread_info.direct_on_input)
578 pa_source_output_push(o, chunk);
579 }
580 }
581 }
582
583 /* Called from IO thread context */
584 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
585 pa_source_assert_ref(s);
586 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
587 pa_source_output_assert_ref(o);
588 pa_assert(o->thread_info.direct_on_input);
589 pa_assert(chunk);
590
591 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
592 return;
593
594 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
595 pa_memchunk vchunk = *chunk;
596
597 pa_memblock_ref(vchunk.memblock);
598 pa_memchunk_make_writable(&vchunk, 0);
599
600 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
601 pa_silence_memchunk(&vchunk, &s->sample_spec);
602 else
603 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
604
605 pa_source_output_push(o, &vchunk);
606
607 pa_memblock_unref(vchunk.memblock);
608 } else
609 pa_source_output_push(o, chunk);
610 }
611
612 /* Called from main thread */
613 pa_usec_t pa_source_get_latency(pa_source *s) {
614 pa_usec_t usec;
615
616 pa_source_assert_ref(s);
617 pa_assert(PA_SOURCE_IS_LINKED(s->state));
618
619 if (s->state == PA_SOURCE_SUSPENDED)
620 return 0;
621
622 if (!(s->flags & PA_SOURCE_LATENCY))
623 return 0;
624
625 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
626
627 return usec;
628 }
629
630 /* Called from IO thread */
631 pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
632 pa_usec_t usec = 0;
633 pa_msgobject *o;
634
635 pa_source_assert_ref(s);
636 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
637
638 /* The returned value is supposed to be in the time domain of the sound card! */
639
640 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
641 return 0;
642
643 if (!(s->flags & PA_SOURCE_LATENCY))
644 return 0;
645
646 o = PA_MSGOBJECT(s);
647
648 /* We probably should make this a proper vtable callback instead of going through process_msg() */
649
650 if (o->process_msg(o, PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
651 return -1;
652
653 return usec;
654 }
655
656 /* Called from main thread */
657 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
658 pa_cvolume old_virtual_volume;
659 pa_bool_t virtual_volume_changed;
660
661 pa_source_assert_ref(s);
662 pa_assert(PA_SOURCE_IS_LINKED(s->state));
663 pa_assert(volume);
664 pa_assert(pa_cvolume_valid(volume));
665 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
666
667 old_virtual_volume = s->virtual_volume;
668 s->virtual_volume = *volume;
669 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
670
671 if (s->set_volume) {
672 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
673 s->set_volume(s);
674 } else
675 s->soft_volume = s->virtual_volume;
676
677 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
678
679 if (virtual_volume_changed)
680 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
681 }
682
683 /* Called from main thread. Only to be called by source implementor */
684 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
685 pa_source_assert_ref(s);
686 pa_assert(volume);
687
688 if (PA_SOURCE_IS_LINKED(s->state))
689 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
690 else
691 s->thread_info.soft_volume = *volume;
692 }
693
694 /* Called from main thread */
695 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
696 pa_source_assert_ref(s);
697 pa_assert(PA_SOURCE_IS_LINKED(s->state));
698
699 if (s->refresh_volume || force_refresh) {
700 pa_cvolume old_virtual_volume = s->virtual_volume;
701
702 if (s->get_volume)
703 s->get_volume(s);
704
705 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
706
707 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
708 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
709 }
710
711 return &s->virtual_volume;
712 }
713
714 /* Called from main thread */
715 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
716 pa_source_assert_ref(s);
717
718 /* The source implementor may call this if the volume changed to make sure everyone is notified */
719
720 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
721 return;
722
723 s->virtual_volume = *new_volume;
724 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
725 }
726
727 /* Called from main thread */
728 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
729 pa_bool_t old_muted;
730
731 pa_source_assert_ref(s);
732 pa_assert(PA_SOURCE_IS_LINKED(s->state));
733
734 old_muted = s->muted;
735 s->muted = mute;
736
737 if (s->set_mute)
738 s->set_mute(s);
739
740 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
741
742 if (old_muted != s->muted)
743 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
744 }
745
746 /* Called from main thread */
747 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
748 pa_source_assert_ref(s);
749 pa_assert(PA_SOURCE_IS_LINKED(s->state));
750
751 if (s->refresh_muted || force_refresh) {
752 pa_bool_t old_muted = s->muted;
753
754 if (s->get_mute)
755 s->get_mute(s);
756
757 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
758
759 if (old_muted != s->muted)
760 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
761 }
762
763 return s->muted;
764 }
765
766 /* Called from main thread */
767 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
768 pa_source_assert_ref(s);
769
770 /* The source implementor may call this if the mute state changed to make sure everyone is notified */
771
772 if (s->muted == new_muted)
773 return;
774
775 s->muted = new_muted;
776 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
777 }
778
779 /* Called from main thread */
780 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
781 pa_source_assert_ref(s);
782
783 if (p)
784 pa_proplist_update(s->proplist, mode, p);
785
786 if (PA_SOURCE_IS_LINKED(s->state)) {
787 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
788 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
789 }
790
791 return TRUE;
792 }
793
794 /* Called from main thread */
795 void pa_source_set_description(pa_source *s, const char *description) {
796 const char *old;
797 pa_source_assert_ref(s);
798
799 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
800 return;
801
802 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
803
804 if (old && description && !strcmp(old, description))
805 return;
806
807 if (description)
808 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
809 else
810 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
811
812 if (PA_SOURCE_IS_LINKED(s->state)) {
813 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
814 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
815 }
816 }
817
818 /* Called from main thread */
819 unsigned pa_source_linked_by(pa_source *s) {
820 pa_source_assert_ref(s);
821 pa_assert(PA_SOURCE_IS_LINKED(s->state));
822
823 return pa_idxset_size(s->outputs);
824 }
825
826 /* Called from main thread */
827 unsigned pa_source_used_by(pa_source *s) {
828 unsigned ret;
829
830 pa_source_assert_ref(s);
831 pa_assert(PA_SOURCE_IS_LINKED(s->state));
832
833 ret = pa_idxset_size(s->outputs);
834 pa_assert(ret >= s->n_corked);
835
836 return ret - s->n_corked;
837 }
838
839 /* Called from main thread */
840 unsigned pa_source_check_suspend(pa_source *s) {
841 unsigned ret;
842 pa_source_output *o;
843 uint32_t idx;
844
845 pa_source_assert_ref(s);
846
847 if (!PA_SOURCE_IS_LINKED(s->state))
848 return 0;
849
850 ret = 0;
851
852 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
853 pa_source_output_state_t st;
854
855 st = pa_source_output_get_state(o);
856 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
857
858 if (st == PA_SOURCE_OUTPUT_CORKED)
859 continue;
860
861 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
862 continue;
863
864 ret ++;
865 }
866
867 return ret;
868 }
869
870 /* Called from IO thread, except when it is not */
871 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
872 pa_source *s = PA_SOURCE(object);
873 pa_source_assert_ref(s);
874
875 switch ((pa_source_message_t) code) {
876
877 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
878 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
879
880 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
881
882 if (o->direct_on_input) {
883 o->thread_info.direct_on_input = o->direct_on_input;
884 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
885 }
886
887 pa_assert(!o->thread_info.attached);
888 o->thread_info.attached = TRUE;
889
890 if (o->attach)
891 o->attach(o);
892
893 pa_source_output_set_state_within_thread(o, o->state);
894
895 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
896 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
897
898 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
899
900 /* We don't just invalidate the requested latency here,
901 * because if we are in a move we might need to fix up the
902 * requested latency. */
903 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
904
905 return 0;
906 }
907
908 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
909 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
910
911 pa_source_output_set_state_within_thread(o, o->state);
912
913 if (o->detach)
914 o->detach(o);
915
916 pa_assert(o->thread_info.attached);
917 o->thread_info.attached = FALSE;
918
919 if (o->thread_info.direct_on_input) {
920 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
921 o->thread_info.direct_on_input = NULL;
922 }
923
924 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
925 pa_source_output_unref(o);
926
927 pa_source_invalidate_requested_latency(s);
928
929 return 0;
930 }
931
932 case PA_SOURCE_MESSAGE_SET_VOLUME:
933 s->thread_info.soft_volume = s->soft_volume;
934 return 0;
935
936 case PA_SOURCE_MESSAGE_GET_VOLUME:
937 return 0;
938
939 case PA_SOURCE_MESSAGE_SET_MUTE:
940 s->thread_info.soft_muted = s->muted;
941 return 0;
942
943 case PA_SOURCE_MESSAGE_GET_MUTE:
944 return 0;
945
946 case PA_SOURCE_MESSAGE_SET_STATE: {
947
948 pa_bool_t suspend_change =
949 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
950 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
951
952 s->thread_info.state = PA_PTR_TO_UINT(userdata);
953
954 if (suspend_change) {
955 pa_source_output *o;
956 void *state = NULL;
957
958 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
959 if (o->suspend_within_thread)
960 o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
961 }
962
963
964 return 0;
965 }
966
967 case PA_SOURCE_MESSAGE_DETACH:
968
969 /* Detach all streams */
970 pa_source_detach_within_thread(s);
971 return 0;
972
973 case PA_SOURCE_MESSAGE_ATTACH:
974
975 /* Reattach all streams */
976 pa_source_attach_within_thread(s);
977 return 0;
978
979 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
980
981 pa_usec_t *usec = userdata;
982 *usec = pa_source_get_requested_latency_within_thread(s);
983
984 if (*usec == (pa_usec_t) -1)
985 *usec = s->thread_info.max_latency;
986
987 return 0;
988 }
989
990 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
991 pa_usec_t *r = userdata;
992
993 pa_source_set_latency_range_within_thread(s, r[0], r[1]);
994
995 return 0;
996 }
997
998 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
999 pa_usec_t *r = userdata;
1000
1001 r[0] = s->thread_info.min_latency;
1002 r[1] = s->thread_info.max_latency;
1003
1004 return 0;
1005 }
1006
1007 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1008
1009 *((size_t*) userdata) = s->thread_info.max_rewind;
1010 return 0;
1011
1012 case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1013
1014 pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1015 return 0;
1016
1017 case PA_SOURCE_MESSAGE_GET_LATENCY:
1018
1019 if (s->monitor_of) {
1020 *((pa_usec_t*) userdata) = 0;
1021 return 0;
1022 }
1023
1024 /* Implementors need to overwrite this implementation! */
1025 return -1;
1026
1027 case PA_SOURCE_MESSAGE_MAX:
1028 ;
1029 }
1030
1031 return -1;
1032 }
1033
1034 /* Called from main thread */
1035 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
1036 uint32_t idx;
1037 pa_source *source;
1038 int ret = 0;
1039
1040 pa_core_assert_ref(c);
1041
1042 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1043 int r;
1044
1045 if (source->monitor_of)
1046 continue;
1047
1048 if ((r = pa_source_suspend(source, suspend)) < 0)
1049 ret = r;
1050 }
1051
1052 return ret;
1053 }
1054
1055 /* Called from main thread */
1056 void pa_source_detach(pa_source *s) {
1057 pa_source_assert_ref(s);
1058 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1059
1060 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1061 }
1062
1063 /* Called from main thread */
1064 void pa_source_attach(pa_source *s) {
1065 pa_source_assert_ref(s);
1066 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1067
1068 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1069 }
1070
1071 /* Called from IO thread */
1072 void pa_source_detach_within_thread(pa_source *s) {
1073 pa_source_output *o;
1074 void *state = NULL;
1075
1076 pa_source_assert_ref(s);
1077 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1078
1079 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1080 if (o->detach)
1081 o->detach(o);
1082 }
1083
1084 /* Called from IO thread */
1085 void pa_source_attach_within_thread(pa_source *s) {
1086 pa_source_output *o;
1087 void *state = NULL;
1088
1089 pa_source_assert_ref(s);
1090 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1091
1092 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1093 if (o->attach)
1094 o->attach(o);
1095 }
1096
1097 /* Called from IO thread */
1098 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1099 pa_usec_t result = (pa_usec_t) -1;
1100 pa_source_output *o;
1101 void *state = NULL;
1102
1103 pa_source_assert_ref(s);
1104
1105 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1106 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1107
1108 if (s->thread_info.requested_latency_valid)
1109 return s->thread_info.requested_latency;
1110
1111 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1112
1113 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1114 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1115 result = o->thread_info.requested_source_latency;
1116
1117 if (result != (pa_usec_t) -1)
1118 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1119
1120 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1121 /* Only cache this if we are fully set up */
1122 s->thread_info.requested_latency = result;
1123 s->thread_info.requested_latency_valid = TRUE;
1124 }
1125
1126 return result;
1127 }
1128
1129 /* Called from main thread */
1130 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1131 pa_usec_t usec = 0;
1132
1133 pa_source_assert_ref(s);
1134 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1135
1136 if (s->state == PA_SOURCE_SUSPENDED)
1137 return 0;
1138
1139 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1140
1141 return usec;
1142 }
1143
1144 /* Called from IO thread */
1145 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1146 pa_source_output *o;
1147 void *state = NULL;
1148
1149 pa_source_assert_ref(s);
1150
1151 if (max_rewind == s->thread_info.max_rewind)
1152 return;
1153
1154 s->thread_info.max_rewind = max_rewind;
1155
1156 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1157 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1158 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1159 }
1160 }
1161
1162 /* Called from main thread */
1163 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1164 pa_source_assert_ref(s);
1165
1166 if (PA_SOURCE_IS_LINKED(s->state))
1167 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1168 else
1169 pa_source_set_max_rewind_within_thread(s, max_rewind);
1170 }
1171
1172 /* Called from IO thread */
1173 void pa_source_invalidate_requested_latency(pa_source *s) {
1174 pa_source_output *o;
1175 void *state = NULL;
1176
1177 pa_source_assert_ref(s);
1178
1179 if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1180 return;
1181
1182 s->thread_info.requested_latency_valid = FALSE;
1183
1184 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1185
1186 if (s->update_requested_latency)
1187 s->update_requested_latency(s);
1188
1189 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1190 if (o->update_source_requested_latency)
1191 o->update_source_requested_latency(o);
1192 }
1193
1194 if (s->monitor_of)
1195 pa_sink_invalidate_requested_latency(s->monitor_of);
1196 }
1197
1198 /* Called from main thread */
1199 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1200 pa_source_assert_ref(s);
1201
1202 /* min_latency == 0: no limit
1203 * min_latency anything else: specified limit
1204 *
1205 * Similar for max_latency */
1206
1207 if (min_latency < ABSOLUTE_MIN_LATENCY)
1208 min_latency = ABSOLUTE_MIN_LATENCY;
1209
1210 if (max_latency <= 0 ||
1211 max_latency > ABSOLUTE_MAX_LATENCY)
1212 max_latency = ABSOLUTE_MAX_LATENCY;
1213
1214 pa_assert(min_latency <= max_latency);
1215
1216 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1217 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1218 max_latency == ABSOLUTE_MAX_LATENCY) ||
1219 (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1220
1221 if (PA_SOURCE_IS_LINKED(s->state)) {
1222 pa_usec_t r[2];
1223
1224 r[0] = min_latency;
1225 r[1] = max_latency;
1226
1227 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1228 } else
1229 pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1230 }
1231
1232 /* Called from main thread */
1233 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1234 pa_source_assert_ref(s);
1235 pa_assert(min_latency);
1236 pa_assert(max_latency);
1237
1238 if (PA_SOURCE_IS_LINKED(s->state)) {
1239 pa_usec_t r[2] = { 0, 0 };
1240
1241 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1242
1243 *min_latency = r[0];
1244 *max_latency = r[1];
1245 } else {
1246 *min_latency = s->thread_info.min_latency;
1247 *max_latency = s->thread_info.max_latency;
1248 }
1249 }
1250
1251 /* Called from IO thread, and from main thread before pa_source_put() is called */
1252 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1253 void *state = NULL;
1254
1255 pa_source_assert_ref(s);
1256
1257 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1258 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1259 pa_assert(min_latency <= max_latency);
1260
1261 /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1262 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1263 max_latency == ABSOLUTE_MAX_LATENCY) ||
1264 (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1265 s->monitor_of);
1266
1267 s->thread_info.min_latency = min_latency;
1268 s->thread_info.max_latency = max_latency;
1269
1270 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1271 pa_source_output *o;
1272
1273 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1274 if (o->update_source_latency_range)
1275 o->update_source_latency_range(o);
1276 }
1277
1278 pa_source_invalidate_requested_latency(s);
1279 }
1280
1281 /* Called from main thread, before the source is put */
1282 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1283 pa_source_assert_ref(s);
1284
1285 pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1286
1287 if (latency < ABSOLUTE_MIN_LATENCY)
1288 latency = ABSOLUTE_MIN_LATENCY;
1289
1290 if (latency > ABSOLUTE_MAX_LATENCY)
1291 latency = ABSOLUTE_MAX_LATENCY;
1292
1293 s->fixed_latency = latency;
1294 }
1295
1296 /* Called from main thread */
1297 size_t pa_source_get_max_rewind(pa_source *s) {
1298 size_t r;
1299 pa_source_assert_ref(s);
1300
1301 if (!PA_SOURCE_IS_LINKED(s->state))
1302 return s->thread_info.max_rewind;
1303
1304 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1305
1306 return r;
1307 }