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