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