]> code.delx.au - pulseaudio/blob - src/pulsecore/source.c
Merge commit 'origin/master-tx'
[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
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 }