Merge commit 'origin/master-tx'
[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             /* Make sure the soft mute status stays in sync */
775             pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
776         }
777     }
778
779     return s->muted;
780 }
781
782 /* Called from main thread */
783 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
784     pa_source_assert_ref(s);
785
786     /* The source implementor may call this if the mute state changed to make sure everyone is notified */
787
788     if (s->muted == new_muted)
789         return;
790
791     s->muted = new_muted;
792     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
793 }
794
795 /* Called from main thread */
796 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
797     pa_source_assert_ref(s);
798
799     if (p)
800         pa_proplist_update(s->proplist, mode, p);
801
802     if (PA_SOURCE_IS_LINKED(s->state)) {
803         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
804         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
805     }
806
807     return TRUE;
808 }
809
810 /* Called from main thread */
811 void pa_source_set_description(pa_source *s, const char *description) {
812     const char *old;
813     pa_source_assert_ref(s);
814
815     if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
816         return;
817
818     old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
819
820     if (old && description && !strcmp(old, description))
821         return;
822
823     if (description)
824         pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
825     else
826         pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
827
828     if (PA_SOURCE_IS_LINKED(s->state)) {
829         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
830         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
831     }
832 }
833
834 /* Called from main thread */
835 unsigned pa_source_linked_by(pa_source *s) {
836     pa_source_assert_ref(s);
837     pa_assert(PA_SOURCE_IS_LINKED(s->state));
838
839     return pa_idxset_size(s->outputs);
840 }
841
842 /* Called from main thread */
843 unsigned pa_source_used_by(pa_source *s) {
844     unsigned ret;
845
846     pa_source_assert_ref(s);
847     pa_assert(PA_SOURCE_IS_LINKED(s->state));
848
849     ret = pa_idxset_size(s->outputs);
850     pa_assert(ret >= s->n_corked);
851
852     return ret - s->n_corked;
853 }
854
855 /* Called from main thread */
856 unsigned pa_source_check_suspend(pa_source *s) {
857     unsigned ret;
858     pa_source_output *o;
859     uint32_t idx;
860
861     pa_source_assert_ref(s);
862
863     if (!PA_SOURCE_IS_LINKED(s->state))
864         return 0;
865
866     ret = 0;
867
868     for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
869         pa_source_output_state_t st;
870
871         st = pa_source_output_get_state(o);
872         pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
873
874         if (st == PA_SOURCE_OUTPUT_CORKED)
875             continue;
876
877         if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
878             continue;
879
880         ret ++;
881     }
882
883     return ret;
884 }
885
886 /* Called from IO thread, except when it is not */
887 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
888     pa_source *s = PA_SOURCE(object);
889     pa_source_assert_ref(s);
890
891     switch ((pa_source_message_t) code) {
892
893         case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
894             pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
895
896             pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
897
898             if (o->direct_on_input) {
899                 o->thread_info.direct_on_input = o->direct_on_input;
900                 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
901             }
902
903             pa_assert(!o->thread_info.attached);
904             o->thread_info.attached = TRUE;
905
906             if (o->attach)
907                 o->attach(o);
908
909             pa_source_output_set_state_within_thread(o, o->state);
910
911             if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
912                 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
913
914             pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
915
916             /* We don't just invalidate the requested latency here,
917              * because if we are in a move we might need to fix up the
918              * requested latency. */
919             pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
920
921             return 0;
922         }
923
924         case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
925             pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
926
927             pa_source_output_set_state_within_thread(o, o->state);
928
929             if (o->detach)
930                 o->detach(o);
931
932             pa_assert(o->thread_info.attached);
933             o->thread_info.attached = FALSE;
934
935             if (o->thread_info.direct_on_input) {
936                 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
937                 o->thread_info.direct_on_input = NULL;
938             }
939
940             if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
941                 pa_source_output_unref(o);
942
943             pa_source_invalidate_requested_latency(s);
944
945             return 0;
946         }
947
948         case PA_SOURCE_MESSAGE_SET_VOLUME:
949             s->thread_info.soft_volume = s->soft_volume;
950             return 0;
951
952         case PA_SOURCE_MESSAGE_GET_VOLUME:
953             return 0;
954
955         case PA_SOURCE_MESSAGE_SET_MUTE:
956             s->thread_info.soft_muted = s->muted;
957             return 0;
958
959         case PA_SOURCE_MESSAGE_GET_MUTE:
960             return 0;
961
962         case PA_SOURCE_MESSAGE_SET_STATE: {
963
964             pa_bool_t suspend_change =
965                 (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
966                 (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED);
967
968             s->thread_info.state = PA_PTR_TO_UINT(userdata);
969
970             if (suspend_change) {
971                 pa_source_output *o;
972                 void *state = NULL;
973
974                 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
975                     if (o->suspend_within_thread)
976                         o->suspend_within_thread(o, s->thread_info.state == PA_SOURCE_SUSPENDED);
977             }
978
979
980             return 0;
981         }
982
983         case PA_SOURCE_MESSAGE_DETACH:
984
985             /* Detach all streams */
986             pa_source_detach_within_thread(s);
987             return 0;
988
989         case PA_SOURCE_MESSAGE_ATTACH:
990
991             /* Reattach all streams */
992             pa_source_attach_within_thread(s);
993             return 0;
994
995         case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
996
997             pa_usec_t *usec = userdata;
998             *usec = pa_source_get_requested_latency_within_thread(s);
999
1000             if (*usec == (pa_usec_t) -1)
1001                 *usec = s->thread_info.max_latency;
1002
1003             return 0;
1004         }
1005
1006         case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
1007             pa_usec_t *r = userdata;
1008
1009             pa_source_set_latency_range_within_thread(s, r[0], r[1]);
1010
1011             return 0;
1012         }
1013
1014         case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
1015             pa_usec_t *r = userdata;
1016
1017             r[0] = s->thread_info.min_latency;
1018             r[1] = s->thread_info.max_latency;
1019
1020             return 0;
1021         }
1022
1023         case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
1024
1025             *((size_t*) userdata) = s->thread_info.max_rewind;
1026             return 0;
1027
1028         case PA_SOURCE_MESSAGE_SET_MAX_REWIND:
1029
1030             pa_source_set_max_rewind_within_thread(s, (size_t) offset);
1031             return 0;
1032
1033         case PA_SOURCE_MESSAGE_GET_LATENCY:
1034
1035             if (s->monitor_of) {
1036                 *((pa_usec_t*) userdata) = 0;
1037                 return 0;
1038             }
1039
1040             /* Implementors need to overwrite this implementation! */
1041             return -1;
1042
1043         case PA_SOURCE_MESSAGE_MAX:
1044             ;
1045     }
1046
1047     return -1;
1048 }
1049
1050 /* Called from main thread */
1051 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
1052     uint32_t idx;
1053     pa_source *source;
1054     int ret = 0;
1055
1056     pa_core_assert_ref(c);
1057     pa_assert(cause != 0);
1058
1059     for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
1060         int r;
1061
1062         if (source->monitor_of)
1063             continue;
1064
1065         if ((r = pa_source_suspend(source, suspend, cause)) < 0)
1066             ret = r;
1067     }
1068
1069     return ret;
1070 }
1071
1072 /* Called from main thread */
1073 void pa_source_detach(pa_source *s) {
1074     pa_source_assert_ref(s);
1075     pa_assert(PA_SOURCE_IS_LINKED(s->state));
1076
1077     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1078 }
1079
1080 /* Called from main thread */
1081 void pa_source_attach(pa_source *s) {
1082     pa_source_assert_ref(s);
1083     pa_assert(PA_SOURCE_IS_LINKED(s->state));
1084
1085     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1086 }
1087
1088 /* Called from IO thread */
1089 void pa_source_detach_within_thread(pa_source *s) {
1090     pa_source_output *o;
1091     void *state = NULL;
1092
1093     pa_source_assert_ref(s);
1094     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1095
1096     while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1097         if (o->detach)
1098             o->detach(o);
1099 }
1100
1101 /* Called from IO thread */
1102 void pa_source_attach_within_thread(pa_source *s) {
1103     pa_source_output *o;
1104     void *state = NULL;
1105
1106     pa_source_assert_ref(s);
1107     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
1108
1109     while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1110         if (o->attach)
1111             o->attach(o);
1112 }
1113
1114 /* Called from IO thread */
1115 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
1116     pa_usec_t result = (pa_usec_t) -1;
1117     pa_source_output *o;
1118     void *state = NULL;
1119
1120     pa_source_assert_ref(s);
1121
1122     if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1123         return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1124
1125     if (s->thread_info.requested_latency_valid)
1126         return s->thread_info.requested_latency;
1127
1128     while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1129
1130         if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1131             (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1132             result = o->thread_info.requested_source_latency;
1133
1134     if (result != (pa_usec_t) -1)
1135         result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1136
1137     if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1138         /* Only cache this if we are fully set up */
1139         s->thread_info.requested_latency = result;
1140         s->thread_info.requested_latency_valid = TRUE;
1141     }
1142
1143     return result;
1144 }
1145
1146 /* Called from main thread */
1147 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1148     pa_usec_t usec = 0;
1149
1150     pa_source_assert_ref(s);
1151     pa_assert(PA_SOURCE_IS_LINKED(s->state));
1152
1153     if (s->state == PA_SOURCE_SUSPENDED)
1154         return 0;
1155
1156     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1157
1158     return usec;
1159 }
1160
1161 /* Called from IO thread */
1162 void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
1163     pa_source_output *o;
1164     void *state = NULL;
1165
1166     pa_source_assert_ref(s);
1167
1168     if (max_rewind == s->thread_info.max_rewind)
1169         return;
1170
1171     s->thread_info.max_rewind = max_rewind;
1172
1173     if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1174         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1175             pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1176     }
1177 }
1178
1179 /* Called from main thread */
1180 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1181     pa_source_assert_ref(s);
1182
1183     if (PA_SOURCE_IS_LINKED(s->state))
1184         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1185     else
1186         pa_source_set_max_rewind_within_thread(s, max_rewind);
1187 }
1188
1189 /* Called from IO thread */
1190 void pa_source_invalidate_requested_latency(pa_source *s) {
1191     pa_source_output *o;
1192     void *state = NULL;
1193
1194     pa_source_assert_ref(s);
1195
1196     if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
1197         return;
1198
1199     s->thread_info.requested_latency_valid = FALSE;
1200
1201     if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1202
1203         if (s->update_requested_latency)
1204             s->update_requested_latency(s);
1205
1206         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1207             if (o->update_source_requested_latency)
1208                 o->update_source_requested_latency(o);
1209     }
1210
1211     if (s->monitor_of)
1212         pa_sink_invalidate_requested_latency(s->monitor_of);
1213 }
1214
1215 /* Called from main thread */
1216 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1217     pa_source_assert_ref(s);
1218
1219     /* min_latency == 0:           no limit
1220      * min_latency anything else:  specified limit
1221      *
1222      * Similar for max_latency */
1223
1224     if (min_latency < ABSOLUTE_MIN_LATENCY)
1225         min_latency = ABSOLUTE_MIN_LATENCY;
1226
1227     if (max_latency <= 0 ||
1228         max_latency > ABSOLUTE_MAX_LATENCY)
1229         max_latency = ABSOLUTE_MAX_LATENCY;
1230
1231     pa_assert(min_latency <= max_latency);
1232
1233     /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1234     pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1235                max_latency == ABSOLUTE_MAX_LATENCY) ||
1236               (s->flags & PA_SOURCE_DYNAMIC_LATENCY));
1237
1238     if (PA_SOURCE_IS_LINKED(s->state)) {
1239         pa_usec_t r[2];
1240
1241         r[0] = min_latency;
1242         r[1] = max_latency;
1243
1244         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1245     } else
1246         pa_source_set_latency_range_within_thread(s, min_latency, max_latency);
1247 }
1248
1249 /* Called from main thread */
1250 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1251    pa_source_assert_ref(s);
1252    pa_assert(min_latency);
1253    pa_assert(max_latency);
1254
1255    if (PA_SOURCE_IS_LINKED(s->state)) {
1256        pa_usec_t r[2] = { 0, 0 };
1257
1258        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1259
1260        *min_latency = r[0];
1261        *max_latency = r[1];
1262    } else {
1263        *min_latency = s->thread_info.min_latency;
1264        *max_latency = s->thread_info.max_latency;
1265    }
1266 }
1267
1268 /* Called from IO thread, and from main thread before pa_source_put() is called */
1269 void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1270     void *state = NULL;
1271
1272     pa_source_assert_ref(s);
1273
1274     pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1275     pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1276     pa_assert(min_latency <= max_latency);
1277
1278     /* Hmm, let's see if someone forgot to set PA_SOURCE_DYNAMIC_LATENCY here... */
1279     pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1280                max_latency == ABSOLUTE_MAX_LATENCY) ||
1281               (s->flags & PA_SOURCE_DYNAMIC_LATENCY) ||
1282               s->monitor_of);
1283
1284     s->thread_info.min_latency = min_latency;
1285     s->thread_info.max_latency = max_latency;
1286
1287     if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1288         pa_source_output *o;
1289
1290         while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1291             if (o->update_source_latency_range)
1292                 o->update_source_latency_range(o);
1293     }
1294
1295     pa_source_invalidate_requested_latency(s);
1296 }
1297
1298 /* Called from main thread, before the source is put */
1299 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
1300     pa_source_assert_ref(s);
1301
1302     pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
1303
1304     if (latency < ABSOLUTE_MIN_LATENCY)
1305         latency = ABSOLUTE_MIN_LATENCY;
1306
1307     if (latency > ABSOLUTE_MAX_LATENCY)
1308         latency = ABSOLUTE_MAX_LATENCY;
1309
1310     s->fixed_latency = latency;
1311 }
1312
1313 /* Called from main thread */
1314 size_t pa_source_get_max_rewind(pa_source *s) {
1315     size_t r;
1316     pa_source_assert_ref(s);
1317
1318     if (!PA_SOURCE_IS_LINKED(s->state))
1319         return s->thread_info.max_rewind;
1320
1321     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1322
1323     return r;
1324 }