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