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