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