]> code.delx.au - pulseaudio/blob - src/pulsecore/source.c
f946366d6c32b09358b204514d40d35346efa060
[pulseaudio] / src / pulsecore / source.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34 #include <pulse/util.h>
35
36 #include <pulsecore/source-output.h>
37 #include <pulsecore/namereg.h>
38 #include <pulsecore/core-subscribe.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/sample-util.h>
41
42 #include "source.h"
43
44 #define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
45
46 static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
47
48 static void source_free(pa_object *o);
49
50 pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
51 pa_assert(data);
52
53 memset(data, 0, sizeof(*data));
54 data->proplist = pa_proplist_new();
55
56 return data;
57 }
58
59 void pa_source_new_data_set_name(pa_source_new_data *data, const char *name) {
60 pa_assert(data);
61
62 pa_xfree(data->name);
63 data->name = pa_xstrdup(name);
64 }
65
66 void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sample_spec *spec) {
67 pa_assert(data);
68
69 if ((data->sample_spec_is_set = !!spec))
70 data->sample_spec = *spec;
71 }
72
73 void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_channel_map *map) {
74 pa_assert(data);
75
76 if ((data->channel_map_is_set = !!map))
77 data->channel_map = *map;
78 }
79
80 void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume) {
81 pa_assert(data);
82
83 if ((data->volume_is_set = !!volume))
84 data->volume = *volume;
85 }
86
87 void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute) {
88 pa_assert(data);
89
90 data->muted_is_set = TRUE;
91 data->muted = !!mute;
92 }
93
94 void pa_source_new_data_done(pa_source_new_data *data) {
95 pa_assert(data);
96
97 pa_xfree(data->name);
98 pa_proplist_free(data->proplist);
99 }
100
101 /* Called from main context */
102 static void reset_callbacks(pa_source *s) {
103 pa_assert(s);
104
105 s->set_state = NULL;
106 s->get_volume = NULL;
107 s->set_volume = NULL;
108 s->get_mute = NULL;
109 s->set_mute = NULL;
110 s->update_requested_latency = NULL;
111 }
112
113 /* Called from main context */
114 pa_source* pa_source_new(
115 pa_core *core,
116 pa_source_new_data *data,
117 pa_source_flags_t flags) {
118
119 pa_source *s;
120 const char *name;
121 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
122 char *pt;
123
124 pa_assert(core);
125 pa_assert(data);
126 pa_assert(data->name);
127
128 s = pa_msgobject_new(pa_source);
129
130 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
131 pa_xfree(s);
132 return NULL;
133 }
134
135 pa_source_new_data_set_name(data, name);
136
137 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
138 pa_xfree(s);
139 pa_namereg_unregister(core, name);
140 return NULL;
141 }
142
143 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
144 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
145
146 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
147
148 if (!data->channel_map_is_set)
149 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
150
151 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
152 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
153
154 if (!data->volume_is_set)
155 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
156
157 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
158 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
159
160 if (!data->muted_is_set)
161 data->muted = FALSE;
162
163 if (data->card)
164 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
165
166 pa_device_init_description(data->proplist);
167 pa_device_init_icon(data->proplist, FALSE);
168
169 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
170 pa_xfree(s);
171 pa_namereg_unregister(core, name);
172 return NULL;
173 }
174
175 s->parent.parent.free = source_free;
176 s->parent.process_msg = pa_source_process_msg;
177
178 s->core = core;
179 s->state = PA_SOURCE_INIT;
180 s->flags = flags;
181 s->name = pa_xstrdup(name);
182 s->proplist = pa_proplist_copy(data->proplist);
183 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
184 s->module = data->module;
185 s->card = data->card;
186
187 s->sample_spec = data->sample_spec;
188 s->channel_map = data->channel_map;
189
190 s->outputs = pa_idxset_new(NULL, NULL);
191 s->n_corked = 0;
192 s->monitor_of = NULL;
193
194 s->virtual_volume = data->volume;
195 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
196 s->base_volume = PA_VOLUME_NORM;
197 s->n_volume_steps = PA_VOLUME_NORM+1;
198 s->muted = data->muted;
199 s->refresh_volume = s->refresh_muted = FALSE;
200
201 reset_callbacks(s);
202 s->userdata = NULL;
203
204 s->asyncmsgq = NULL;
205 s->rtpoll = NULL;
206
207 pa_silence_memchunk_get(
208 &core->silence_cache,
209 core->mempool,
210 &s->silence,
211 &s->sample_spec,
212 0);
213
214 s->thread_info.outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
215 s->thread_info.soft_volume = s->soft_volume;
216 s->thread_info.soft_muted = s->muted;
217 s->thread_info.state = s->state;
218 s->thread_info.max_rewind = 0;
219 s->thread_info.requested_latency_valid = FALSE;
220 s->thread_info.requested_latency = 0;
221 s->thread_info.min_latency = DEFAULT_MIN_LATENCY;
222 s->thread_info.max_latency = 0;
223
224 pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
225
226 if (s->card)
227 pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
228
229 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
230 pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s\n %s",
231 s->index,
232 s->name,
233 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
234 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
235 pt);
236 pa_xfree(pt);
237
238 return s;
239 }
240
241 /* Called from main context */
242 static int source_set_state(pa_source *s, pa_source_state_t state) {
243 int ret;
244 pa_bool_t suspend_change;
245 pa_source_state_t original_state;
246
247 pa_assert(s);
248
249 if (s->state == state)
250 return 0;
251
252 original_state = s->state;
253
254 suspend_change =
255 (original_state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(state)) ||
256 (PA_SOURCE_IS_OPENED(original_state) && state == PA_SOURCE_SUSPENDED);
257
258 if (s->set_state)
259 if ((ret = s->set_state(s, state)) < 0)
260 return ret;
261
262 if (s->asyncmsgq)
263 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
264
265 if (s->set_state)
266 s->set_state(s, original_state);
267
268 return ret;
269 }
270
271 s->state = state;
272
273 if (state != PA_SOURCE_UNLINKED) { /* if we enter UNLINKED state pa_source_unlink() will fire the apropriate events */
274 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], s);
275 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
276 }
277
278 if (suspend_change) {
279 pa_source_output *o;
280 uint32_t idx;
281
282 /* We're suspending or resuming, tell everyone about it */
283
284 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx)))
285 if (s->state == PA_SOURCE_SUSPENDED &&
286 (o->flags & PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND))
287 pa_source_output_kill(o);
288 else if (o->suspend)
289 o->suspend(o, state == PA_SOURCE_SUSPENDED);
290 }
291
292
293 return 0;
294 }
295
296 /* Called from main context */
297 void pa_source_put(pa_source *s) {
298 pa_source_assert_ref(s);
299
300 pa_assert(s->state == PA_SOURCE_INIT);
301
302 /* The following fields must be initialized properly when calling _put() */
303 pa_assert(s->asyncmsgq);
304 pa_assert(s->rtpoll);
305 pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
306 s->thread_info.min_latency <= s->thread_info.max_latency);
307
308 if (!(s->flags & PA_SOURCE_HW_VOLUME_CTRL)) {
309 s->flags |= PA_SOURCE_DECIBEL_VOLUME;
310
311 s->thread_info.soft_volume = s->soft_volume;
312 s->thread_info.soft_muted = s->muted;
313 }
314
315 if (s->flags & PA_SOURCE_DECIBEL_VOLUME)
316 s->n_volume_steps = PA_VOLUME_NORM+1;
317
318 pa_assert_se(source_set_state(s, PA_SOURCE_IDLE) == 0);
319
320 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_NEW, s->index);
321 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PUT], s);
322 }
323
324 /* Called from main context */
325 void pa_source_unlink(pa_source *s) {
326 pa_bool_t linked;
327 pa_source_output *o, *j = NULL;
328
329 pa_assert(s);
330
331 /* See pa_sink_unlink() for a couple of comments how this function
332 * works. */
333
334 linked = PA_SOURCE_IS_LINKED(s->state);
335
336 if (linked)
337 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], s);
338
339 if (s->state != PA_SOURCE_UNLINKED)
340 pa_namereg_unregister(s->core, s->name);
341 pa_idxset_remove_by_data(s->core->sources, s, NULL);
342
343 if (s->card)
344 pa_idxset_remove_by_data(s->card->sources, s, NULL);
345
346 while ((o = pa_idxset_first(s->outputs, NULL))) {
347 pa_assert(o != j);
348 pa_source_output_kill(o);
349 j = o;
350 }
351
352 if (linked)
353 source_set_state(s, PA_SOURCE_UNLINKED);
354 else
355 s->state = PA_SOURCE_UNLINKED;
356
357 reset_callbacks(s);
358
359 if (linked) {
360 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
361 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK_POST], s);
362 }
363 }
364
365 /* Called from main context */
366 static void source_free(pa_object *o) {
367 pa_source_output *so;
368 pa_source *s = PA_SOURCE(o);
369
370 pa_assert(s);
371 pa_assert(pa_source_refcnt(s) == 0);
372
373 if (PA_SOURCE_IS_LINKED(s->state))
374 pa_source_unlink(s);
375
376 pa_log_info("Freeing source %u \"%s\"", s->index, s->name);
377
378 pa_idxset_free(s->outputs, NULL, NULL);
379
380 while ((so = pa_hashmap_steal_first(s->thread_info.outputs)))
381 pa_source_output_unref(so);
382
383 pa_hashmap_free(s->thread_info.outputs, NULL, NULL);
384
385 if (s->silence.memblock)
386 pa_memblock_unref(s->silence.memblock);
387
388 pa_xfree(s->name);
389 pa_xfree(s->driver);
390
391 if (s->proplist)
392 pa_proplist_free(s->proplist);
393
394 pa_xfree(s);
395 }
396
397 /* Called from main context */
398 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
399 pa_source_assert_ref(s);
400
401 s->asyncmsgq = q;
402 }
403
404 /* Called from main context */
405 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
406 pa_source_assert_ref(s);
407
408 s->rtpoll = p;
409 }
410
411 /* Called from main context */
412 int pa_source_update_status(pa_source*s) {
413 pa_source_assert_ref(s);
414 pa_assert(PA_SOURCE_IS_LINKED(s->state));
415
416 if (s->state == PA_SOURCE_SUSPENDED)
417 return 0;
418
419 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
420 }
421
422 /* Called from main context */
423 int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
424 pa_source_assert_ref(s);
425 pa_assert(PA_SOURCE_IS_LINKED(s->state));
426
427 if (s->monitor_of)
428 return -PA_ERR_NOTSUPPORTED;
429
430 if (suspend)
431 return source_set_state(s, PA_SOURCE_SUSPENDED);
432 else
433 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
434 }
435
436 /* Called from main context */
437 pa_queue *pa_source_move_all_start(pa_source *s) {
438 pa_queue *q;
439 pa_source_output *o, *n;
440 uint32_t idx;
441
442 pa_source_assert_ref(s);
443 pa_assert(PA_SOURCE_IS_LINKED(s->state));
444
445 q = pa_queue_new();
446
447 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
448 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
449
450 if (pa_source_output_start_move(o) >= 0)
451 pa_queue_push(q, pa_source_output_ref(o));
452 }
453
454 return q;
455 }
456
457 /* Called from main context */
458 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
459 pa_source_output *o;
460
461 pa_source_assert_ref(s);
462 pa_assert(PA_SOURCE_IS_LINKED(s->state));
463 pa_assert(q);
464
465 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
466 if (pa_source_output_finish_move(o, s, save) < 0)
467 pa_source_output_kill(o);
468
469 pa_source_output_unref(o);
470 }
471
472 pa_queue_free(q, NULL, NULL);
473 }
474
475 /* Called from main context */
476 void pa_source_move_all_fail(pa_queue *q) {
477 pa_source_output *o;
478 pa_assert(q);
479
480 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
481 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
482 pa_source_output_kill(o);
483 pa_source_output_unref(o);
484 }
485 }
486
487 pa_queue_free(q, NULL, NULL);
488 }
489
490 /* Called from IO thread context */
491 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
492 pa_source_output *o;
493 void *state = NULL;
494
495 pa_source_assert_ref(s);
496 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
497
498 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
499 return;
500
501 if (nbytes <= 0)
502 return;
503
504 pa_log_debug("Processing rewind...");
505
506 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
507 pa_source_output_assert_ref(o);
508 pa_source_output_process_rewind(o, nbytes);
509 }
510 }
511
512 /* Called from IO thread context */
513 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
514 pa_source_output *o;
515 void *state = NULL;
516
517 pa_source_assert_ref(s);
518 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
519 pa_assert(chunk);
520
521 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
522 return;
523
524 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
525 pa_memchunk vchunk = *chunk;
526
527 pa_memblock_ref(vchunk.memblock);
528 pa_memchunk_make_writable(&vchunk, 0);
529
530 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
531 pa_silence_memchunk(&vchunk, &s->sample_spec);
532 else
533 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
534
535 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
536 pa_source_output_assert_ref(o);
537
538 if (!o->thread_info.direct_on_input)
539 pa_source_output_push(o, &vchunk);
540 }
541
542 pa_memblock_unref(vchunk.memblock);
543 } else {
544
545 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
546 pa_source_output_assert_ref(o);
547
548 if (!o->thread_info.direct_on_input)
549 pa_source_output_push(o, chunk);
550 }
551 }
552 }
553
554 /* Called from IO thread context */
555 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
556 pa_source_assert_ref(s);
557 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
558 pa_source_output_assert_ref(o);
559 pa_assert(o->thread_info.direct_on_input);
560 pa_assert(chunk);
561
562 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
563 return;
564
565 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
566 pa_memchunk vchunk = *chunk;
567
568 pa_memblock_ref(vchunk.memblock);
569 pa_memchunk_make_writable(&vchunk, 0);
570
571 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
572 pa_silence_memchunk(&vchunk, &s->sample_spec);
573 else
574 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
575
576 pa_source_output_push(o, &vchunk);
577
578 pa_memblock_unref(vchunk.memblock);
579 } else
580 pa_source_output_push(o, chunk);
581 }
582
583 /* Called from main thread */
584 pa_usec_t pa_source_get_latency(pa_source *s) {
585 pa_usec_t usec;
586
587 pa_source_assert_ref(s);
588 pa_assert(PA_SOURCE_IS_LINKED(s->state));
589
590 if (s->state == PA_SOURCE_SUSPENDED)
591 return 0;
592
593 if (!(s->flags & PA_SOURCE_LATENCY))
594 return 0;
595
596 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
597
598 return usec;
599 }
600
601 /* Called from main thread */
602 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
603 pa_cvolume old_virtual_volume;
604 pa_bool_t virtual_volume_changed;
605
606 pa_source_assert_ref(s);
607 pa_assert(PA_SOURCE_IS_LINKED(s->state));
608 pa_assert(volume);
609 pa_assert(pa_cvolume_valid(volume));
610 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
611
612 old_virtual_volume = s->virtual_volume;
613 s->virtual_volume = *volume;
614 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
615
616 if (s->set_volume) {
617 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
618 s->set_volume(s);
619 } else
620 s->soft_volume = s->virtual_volume;
621
622 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
623
624 if (virtual_volume_changed)
625 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
626 }
627
628 /* Called from main thread. Only to be called by source implementor */
629 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
630 pa_source_assert_ref(s);
631 pa_assert(volume);
632
633 if (PA_SOURCE_IS_LINKED(s->state))
634 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
635 else
636 s->thread_info.soft_volume = *volume;
637 }
638
639 /* Called from main thread */
640 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
641 pa_source_assert_ref(s);
642 pa_assert(PA_SOURCE_IS_LINKED(s->state));
643
644 if (s->refresh_volume || force_refresh) {
645 pa_cvolume old_virtual_volume = s->virtual_volume;
646
647 if (s->get_volume)
648 s->get_volume(s);
649
650 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
651
652 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
653 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
654 }
655
656 return &s->virtual_volume;
657 }
658
659 /* Called from main thread */
660 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
661 pa_bool_t old_muted;
662
663 pa_source_assert_ref(s);
664 pa_assert(PA_SOURCE_IS_LINKED(s->state));
665
666 old_muted = s->muted;
667 s->muted = mute;
668
669 if (s->set_mute)
670 s->set_mute(s);
671
672 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
673
674 if (old_muted != s->muted)
675 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
676 }
677
678 /* Called from main thread */
679 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
680
681 pa_source_assert_ref(s);
682 pa_assert(PA_SOURCE_IS_LINKED(s->state));
683
684 if (s->refresh_muted || force_refresh) {
685 pa_bool_t old_muted = s->muted;
686
687 if (s->get_mute)
688 s->get_mute(s);
689
690 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
691
692 if (old_muted != s->muted)
693 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
694 }
695
696 return s->muted;
697 }
698
699 /* Called from main thread */
700 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
701 pa_source_assert_ref(s);
702 pa_assert(p);
703
704 pa_proplist_update(s->proplist, mode, p);
705
706 if (PA_SOURCE_IS_LINKED(s->state)) {
707 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
708 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
709 }
710
711 return TRUE;
712 }
713
714 /* Called from main thread */
715 void pa_source_set_description(pa_source *s, const char *description) {
716 const char *old;
717 pa_source_assert_ref(s);
718
719 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
720 return;
721
722 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
723
724 if (old && description && !strcmp(old, description))
725 return;
726
727 if (description)
728 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
729 else
730 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
731
732 if (PA_SOURCE_IS_LINKED(s->state)) {
733 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
734 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
735 }
736 }
737
738 /* Called from main thread */
739 unsigned pa_source_linked_by(pa_source *s) {
740 pa_source_assert_ref(s);
741 pa_assert(PA_SOURCE_IS_LINKED(s->state));
742
743 return pa_idxset_size(s->outputs);
744 }
745
746 /* Called from main thread */
747 unsigned pa_source_used_by(pa_source *s) {
748 unsigned ret;
749
750 pa_source_assert_ref(s);
751 pa_assert(PA_SOURCE_IS_LINKED(s->state));
752
753 ret = pa_idxset_size(s->outputs);
754 pa_assert(ret >= s->n_corked);
755
756 return ret - s->n_corked;
757 }
758
759 /* Called from main thread */
760 unsigned pa_source_check_suspend(pa_source *s) {
761 unsigned ret;
762 pa_source_output *o;
763 uint32_t idx;
764
765 pa_source_assert_ref(s);
766
767 if (!PA_SOURCE_IS_LINKED(s->state))
768 return 0;
769
770 ret = 0;
771
772 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
773 pa_source_output_state_t st;
774
775 st = pa_source_output_get_state(o);
776 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
777
778 if (st == PA_SOURCE_OUTPUT_CORKED)
779 continue;
780
781 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
782 continue;
783
784 ret ++;
785 }
786
787 return ret;
788 }
789
790 /* Called from IO thread, except when it is not */
791 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
792 pa_source *s = PA_SOURCE(object);
793 pa_source_assert_ref(s);
794
795 switch ((pa_source_message_t) code) {
796
797 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
798 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
799
800 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
801
802 if (o->direct_on_input) {
803 o->thread_info.direct_on_input = o->direct_on_input;
804 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
805 }
806
807 pa_assert(!o->thread_info.attached);
808 o->thread_info.attached = TRUE;
809
810 if (o->attach)
811 o->attach(o);
812
813 pa_source_output_set_state_within_thread(o, o->state);
814
815 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
816 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
817
818 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
819
820 /* We don't just invalidate the requested latency here,
821 * because if we are in a move we might need to fix up the
822 * requested latency. */
823 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
824
825 return 0;
826 }
827
828 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
829 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
830
831 pa_source_output_set_state_within_thread(o, o->state);
832
833 if (o->detach)
834 o->detach(o);
835
836 pa_assert(o->thread_info.attached);
837 o->thread_info.attached = FALSE;
838
839 if (o->thread_info.direct_on_input) {
840 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
841 o->thread_info.direct_on_input = NULL;
842 }
843
844 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
845 pa_source_output_unref(o);
846
847 pa_source_invalidate_requested_latency(s);
848
849 return 0;
850 }
851
852 case PA_SOURCE_MESSAGE_SET_VOLUME:
853 s->thread_info.soft_volume = s->soft_volume;
854 return 0;
855
856 case PA_SOURCE_MESSAGE_GET_VOLUME:
857 return 0;
858
859 case PA_SOURCE_MESSAGE_SET_MUTE:
860 s->thread_info.soft_muted = s->muted;
861 return 0;
862
863 case PA_SOURCE_MESSAGE_GET_MUTE:
864 return 0;
865
866 case PA_SOURCE_MESSAGE_SET_STATE:
867 s->thread_info.state = PA_PTR_TO_UINT(userdata);
868 return 0;
869
870 case PA_SOURCE_MESSAGE_DETACH:
871
872 /* Detach all streams */
873 pa_source_detach_within_thread(s);
874 return 0;
875
876 case PA_SOURCE_MESSAGE_ATTACH:
877
878 /* Reattach all streams */
879 pa_source_attach_within_thread(s);
880 return 0;
881
882 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
883
884 pa_usec_t *usec = userdata;
885 *usec = pa_source_get_requested_latency_within_thread(s);
886
887 if (*usec == (pa_usec_t) -1)
888 *usec = s->thread_info.max_latency;
889
890 return 0;
891 }
892
893 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
894 pa_usec_t *r = userdata;
895
896 pa_source_update_latency_range(s, r[0], r[1]);
897
898 return 0;
899 }
900
901 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
902 pa_usec_t *r = userdata;
903
904 r[0] = s->thread_info.min_latency;
905 r[1] = s->thread_info.max_latency;
906
907 return 0;
908 }
909
910 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
911
912 *((size_t*) userdata) = s->thread_info.max_rewind;
913 return 0;
914
915 case PA_SOURCE_MESSAGE_GET_LATENCY:
916
917 if (s->monitor_of) {
918 *((pa_usec_t*) userdata) = 0;
919 return 0;
920 }
921
922 /* Implementors need to overwrite this implementation! */
923 return -1;
924
925 case PA_SOURCE_MESSAGE_MAX:
926 ;
927 }
928
929 return -1;
930 }
931
932 /* Called from main thread */
933 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
934 uint32_t idx;
935 pa_source *source;
936 int ret = 0;
937
938 pa_core_assert_ref(c);
939
940 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx)))
941 ret -= pa_source_suspend(source, suspend) < 0;
942
943 return ret;
944 }
945
946 /* Called from main thread */
947 void pa_source_detach(pa_source *s) {
948 pa_source_assert_ref(s);
949 pa_assert(PA_SOURCE_IS_LINKED(s->state));
950
951 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
952 }
953
954 /* Called from main thread */
955 void pa_source_attach(pa_source *s) {
956 pa_source_assert_ref(s);
957 pa_assert(PA_SOURCE_IS_LINKED(s->state));
958
959 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
960 }
961
962 /* Called from IO thread */
963 void pa_source_detach_within_thread(pa_source *s) {
964 pa_source_output *o;
965 void *state = NULL;
966
967 pa_source_assert_ref(s);
968 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
969
970 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
971 if (o->detach)
972 o->detach(o);
973 }
974
975 /* Called from IO thread */
976 void pa_source_attach_within_thread(pa_source *s) {
977 pa_source_output *o;
978 void *state = NULL;
979
980 pa_source_assert_ref(s);
981 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
982
983 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
984 if (o->attach)
985 o->attach(o);
986 }
987
988 /* Called from IO thread */
989 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
990 pa_usec_t result = (pa_usec_t) -1;
991 pa_source_output *o;
992 void *state = NULL;
993
994 pa_source_assert_ref(s);
995
996 if (s->thread_info.requested_latency_valid)
997 return s->thread_info.requested_latency;
998
999 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1000
1001 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
1002 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1003 result = o->thread_info.requested_source_latency;
1004
1005 if (result != (pa_usec_t) -1) {
1006 if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1007 result = s->thread_info.max_latency;
1008
1009 if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1010 result = s->thread_info.min_latency;
1011 }
1012
1013 s->thread_info.requested_latency = result;
1014 s->thread_info.requested_latency_valid = TRUE;
1015
1016 return result;
1017 }
1018
1019 /* Called from main thread */
1020 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1021 pa_usec_t usec;
1022
1023 pa_source_assert_ref(s);
1024 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1025
1026 if (s->state == PA_SOURCE_SUSPENDED)
1027 return 0;
1028
1029 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1030
1031 return usec;
1032 }
1033
1034 /* Called from IO thread */
1035 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1036 pa_source_output *o;
1037 void *state = NULL;
1038
1039 pa_source_assert_ref(s);
1040
1041 if (max_rewind == s->thread_info.max_rewind)
1042 return;
1043
1044 s->thread_info.max_rewind = max_rewind;
1045
1046 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1047 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1048 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1049 }
1050 }
1051
1052 void pa_source_invalidate_requested_latency(pa_source *s) {
1053 pa_source_output *o;
1054 void *state = NULL;
1055
1056 pa_source_assert_ref(s);
1057
1058 s->thread_info.requested_latency_valid = FALSE;
1059
1060 if (s->update_requested_latency)
1061 s->update_requested_latency(s);
1062
1063 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1064 if (o->update_source_requested_latency)
1065 o->update_source_requested_latency(o);
1066
1067 if (s->monitor_of)
1068 pa_sink_invalidate_requested_latency(s->monitor_of);
1069 }
1070
1071 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1072 pa_source_assert_ref(s);
1073
1074 /* min_latency == 0: no limit
1075 * min_latency == (size_t) -1: default limit
1076 * min_latency anything else: specified limit
1077 *
1078 * Similar for max_latency */
1079
1080 if (min_latency == (pa_usec_t) -1)
1081 min_latency = DEFAULT_MIN_LATENCY;
1082
1083 if (max_latency == (pa_usec_t) -1)
1084 max_latency = min_latency;
1085
1086 pa_assert(!min_latency || !max_latency ||
1087 min_latency <= max_latency);
1088
1089 if (PA_SOURCE_IS_LINKED(s->state)) {
1090 pa_usec_t r[2];
1091
1092 r[0] = min_latency;
1093 r[1] = max_latency;
1094
1095 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1096 } else {
1097 s->thread_info.min_latency = min_latency;
1098 s->thread_info.max_latency = max_latency;
1099
1100 s->thread_info.requested_latency_valid = FALSE;
1101 }
1102 }
1103
1104 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1105 pa_source_assert_ref(s);
1106 pa_assert(min_latency);
1107 pa_assert(max_latency);
1108
1109 if (PA_SOURCE_IS_LINKED(s->state)) {
1110 pa_usec_t r[2] = { 0, 0 };
1111
1112 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1113
1114 *min_latency = r[0];
1115 *max_latency = r[1];
1116 } else {
1117 *min_latency = s->thread_info.min_latency;
1118 *max_latency = s->thread_info.max_latency;
1119 }
1120 }
1121
1122 /* Called from IO thread */
1123 void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1124 pa_source_output *o;
1125 void *state = NULL;
1126
1127 pa_source_assert_ref(s);
1128
1129 pa_assert(!min_latency || !max_latency ||
1130 min_latency <= max_latency);
1131
1132 s->thread_info.min_latency = min_latency;
1133 s->thread_info.max_latency = max_latency;
1134
1135 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1136 if (o->update_source_latency_range)
1137 o->update_source_latency_range(o);
1138
1139 pa_source_invalidate_requested_latency(s);
1140 }
1141
1142 size_t pa_source_get_max_rewind(pa_source *s) {
1143 size_t r;
1144 pa_source_assert_ref(s);
1145
1146 if (!PA_SOURCE_IS_LINKED(s->state))
1147 return s->thread_info.max_rewind;
1148
1149 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1150
1151 return r;
1152 }