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