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