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