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