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