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