]> code.delx.au - pulseaudio/blob - src/pulsecore/source.c
Merge commit 'coling/lgpl21'
[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 (suspend)
428 return source_set_state(s, PA_SOURCE_SUSPENDED);
429 else
430 return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : PA_SOURCE_IDLE);
431 }
432
433 /* Called from main context */
434 pa_queue *pa_source_move_all_start(pa_source *s) {
435 pa_queue *q;
436 pa_source_output *o, *n;
437 uint32_t idx;
438
439 pa_source_assert_ref(s);
440 pa_assert(PA_SOURCE_IS_LINKED(s->state));
441
442 q = pa_queue_new();
443
444 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
445 n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
446
447 if (pa_source_output_start_move(o) >= 0)
448 pa_queue_push(q, pa_source_output_ref(o));
449 }
450
451 return q;
452 }
453
454 /* Called from main context */
455 void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
456 pa_source_output *o;
457
458 pa_source_assert_ref(s);
459 pa_assert(PA_SOURCE_IS_LINKED(s->state));
460 pa_assert(q);
461
462 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
463 if (pa_source_output_finish_move(o, s, save) < 0)
464 pa_source_output_kill(o);
465
466 pa_source_output_unref(o);
467 }
468
469 pa_queue_free(q, NULL, NULL);
470 }
471
472 /* Called from main context */
473 void pa_source_move_all_fail(pa_queue *q) {
474 pa_source_output *o;
475 pa_assert(q);
476
477 while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
478 if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FAIL], o) == PA_HOOK_OK) {
479 pa_source_output_kill(o);
480 pa_source_output_unref(o);
481 }
482 }
483
484 pa_queue_free(q, NULL, NULL);
485 }
486
487 /* Called from IO thread context */
488 void pa_source_process_rewind(pa_source *s, size_t nbytes) {
489 pa_source_output *o;
490 void *state = NULL;
491
492 pa_source_assert_ref(s);
493 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
494
495 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
496 return;
497
498 if (nbytes <= 0)
499 return;
500
501 pa_log_debug("Processing rewind...");
502
503 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
504 pa_source_output_assert_ref(o);
505 pa_source_output_process_rewind(o, nbytes);
506 }
507 }
508
509 /* Called from IO thread context */
510 void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
511 pa_source_output *o;
512 void *state = NULL;
513
514 pa_source_assert_ref(s);
515 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
516 pa_assert(chunk);
517
518 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
519 return;
520
521 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
522 pa_memchunk vchunk = *chunk;
523
524 pa_memblock_ref(vchunk.memblock);
525 pa_memchunk_make_writable(&vchunk, 0);
526
527 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
528 pa_silence_memchunk(&vchunk, &s->sample_spec);
529 else
530 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
531
532 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
533 pa_source_output_assert_ref(o);
534
535 if (!o->thread_info.direct_on_input)
536 pa_source_output_push(o, &vchunk);
537 }
538
539 pa_memblock_unref(vchunk.memblock);
540 } else {
541
542 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL))) {
543 pa_source_output_assert_ref(o);
544
545 if (!o->thread_info.direct_on_input)
546 pa_source_output_push(o, chunk);
547 }
548 }
549 }
550
551 /* Called from IO thread context */
552 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
553 pa_source_assert_ref(s);
554 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
555 pa_source_output_assert_ref(o);
556 pa_assert(o->thread_info.direct_on_input);
557 pa_assert(chunk);
558
559 if (s->thread_info.state == PA_SOURCE_SUSPENDED)
560 return;
561
562 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
563 pa_memchunk vchunk = *chunk;
564
565 pa_memblock_ref(vchunk.memblock);
566 pa_memchunk_make_writable(&vchunk, 0);
567
568 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&s->thread_info.soft_volume))
569 pa_silence_memchunk(&vchunk, &s->sample_spec);
570 else
571 pa_volume_memchunk(&vchunk, &s->sample_spec, &s->thread_info.soft_volume);
572
573 pa_source_output_push(o, &vchunk);
574
575 pa_memblock_unref(vchunk.memblock);
576 } else
577 pa_source_output_push(o, chunk);
578 }
579
580 /* Called from main thread */
581 pa_usec_t pa_source_get_latency(pa_source *s) {
582 pa_usec_t usec;
583
584 pa_source_assert_ref(s);
585 pa_assert(PA_SOURCE_IS_LINKED(s->state));
586
587 if (s->state == PA_SOURCE_SUSPENDED)
588 return 0;
589
590 if (!(s->flags & PA_SOURCE_LATENCY))
591 return 0;
592
593 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
594
595 return usec;
596 }
597
598 /* Called from main thread */
599 void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
600 pa_cvolume old_virtual_volume;
601 pa_bool_t virtual_volume_changed;
602
603 pa_source_assert_ref(s);
604 pa_assert(PA_SOURCE_IS_LINKED(s->state));
605 pa_assert(volume);
606 pa_assert(pa_cvolume_valid(volume));
607 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
608
609 old_virtual_volume = s->virtual_volume;
610 s->virtual_volume = *volume;
611 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
612
613 if (s->set_volume) {
614 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
615 s->set_volume(s);
616 } else
617 s->soft_volume = s->virtual_volume;
618
619 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
620
621 if (virtual_volume_changed)
622 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
623 }
624
625 /* Called from main thread. Only to be called by source implementor */
626 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
627 pa_source_assert_ref(s);
628 pa_assert(volume);
629
630 if (PA_SOURCE_IS_LINKED(s->state))
631 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
632 else
633 s->thread_info.soft_volume = *volume;
634 }
635
636 /* Called from main thread */
637 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
638 pa_source_assert_ref(s);
639 pa_assert(PA_SOURCE_IS_LINKED(s->state));
640
641 if (s->refresh_volume || force_refresh) {
642 pa_cvolume old_virtual_volume = s->virtual_volume;
643
644 if (s->get_volume)
645 s->get_volume(s);
646
647 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
648
649 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume))
650 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
651 }
652
653 return &s->virtual_volume;
654 }
655
656 /* Called from main thread */
657 void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
658 pa_bool_t old_muted;
659
660 pa_source_assert_ref(s);
661 pa_assert(PA_SOURCE_IS_LINKED(s->state));
662
663 old_muted = s->muted;
664 s->muted = mute;
665
666 if (s->set_mute)
667 s->set_mute(s);
668
669 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
670
671 if (old_muted != s->muted)
672 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
673 }
674
675 /* Called from main thread */
676 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
677
678 pa_source_assert_ref(s);
679 pa_assert(PA_SOURCE_IS_LINKED(s->state));
680
681 if (s->refresh_muted || force_refresh) {
682 pa_bool_t old_muted = s->muted;
683
684 if (s->get_mute)
685 s->get_mute(s);
686
687 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
688
689 if (old_muted != s->muted)
690 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
691 }
692
693 return s->muted;
694 }
695
696 /* Called from main thread */
697 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
698 pa_source_assert_ref(s);
699 pa_assert(p);
700
701 pa_proplist_update(s->proplist, mode, p);
702
703 if (PA_SOURCE_IS_LINKED(s->state)) {
704 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
705 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
706 }
707
708 return TRUE;
709 }
710
711 /* Called from main thread */
712 void pa_source_set_description(pa_source *s, const char *description) {
713 const char *old;
714 pa_source_assert_ref(s);
715
716 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
717 return;
718
719 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
720
721 if (old && description && !strcmp(old, description))
722 return;
723
724 if (description)
725 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
726 else
727 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
728
729 if (PA_SOURCE_IS_LINKED(s->state)) {
730 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
731 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], s);
732 }
733 }
734
735 /* Called from main thread */
736 unsigned pa_source_linked_by(pa_source *s) {
737 pa_source_assert_ref(s);
738 pa_assert(PA_SOURCE_IS_LINKED(s->state));
739
740 return pa_idxset_size(s->outputs);
741 }
742
743 /* Called from main thread */
744 unsigned pa_source_used_by(pa_source *s) {
745 unsigned ret;
746
747 pa_source_assert_ref(s);
748 pa_assert(PA_SOURCE_IS_LINKED(s->state));
749
750 ret = pa_idxset_size(s->outputs);
751 pa_assert(ret >= s->n_corked);
752
753 return ret - s->n_corked;
754 }
755
756 /* Called from main thread */
757 unsigned pa_source_check_suspend(pa_source *s) {
758 unsigned ret;
759 pa_source_output *o;
760 uint32_t idx;
761
762 pa_source_assert_ref(s);
763
764 if (!PA_SOURCE_IS_LINKED(s->state))
765 return 0;
766
767 ret = 0;
768
769 for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
770 pa_source_output_state_t st;
771
772 st = pa_source_output_get_state(o);
773 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st));
774
775 if (st == PA_SOURCE_OUTPUT_CORKED)
776 continue;
777
778 if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND)
779 continue;
780
781 ret ++;
782 }
783
784 return ret;
785 }
786
787 /* Called from IO thread, except when it is not */
788 int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
789 pa_source *s = PA_SOURCE(object);
790 pa_source_assert_ref(s);
791
792 switch ((pa_source_message_t) code) {
793
794 case PA_SOURCE_MESSAGE_ADD_OUTPUT: {
795 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
796
797 pa_hashmap_put(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index), pa_source_output_ref(o));
798
799 if (o->direct_on_input) {
800 o->thread_info.direct_on_input = o->direct_on_input;
801 pa_hashmap_put(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index), o);
802 }
803
804 pa_assert(!o->thread_info.attached);
805 o->thread_info.attached = TRUE;
806
807 if (o->attach)
808 o->attach(o);
809
810 pa_source_output_set_state_within_thread(o, o->state);
811
812 if (o->thread_info.requested_source_latency != (pa_usec_t) -1)
813 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
814
815 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
816
817 /* We don't just invalidate the requested latency here,
818 * because if we are in a move we might need to fix up the
819 * requested latency. */
820 pa_source_output_set_requested_latency_within_thread(o, o->thread_info.requested_source_latency);
821
822 return 0;
823 }
824
825 case PA_SOURCE_MESSAGE_REMOVE_OUTPUT: {
826 pa_source_output *o = PA_SOURCE_OUTPUT(userdata);
827
828 pa_source_output_set_state_within_thread(o, o->state);
829
830 if (o->detach)
831 o->detach(o);
832
833 pa_assert(o->thread_info.attached);
834 o->thread_info.attached = FALSE;
835
836 if (o->thread_info.direct_on_input) {
837 pa_hashmap_remove(o->thread_info.direct_on_input->thread_info.direct_outputs, PA_UINT32_TO_PTR(o->index));
838 o->thread_info.direct_on_input = NULL;
839 }
840
841 if (pa_hashmap_remove(s->thread_info.outputs, PA_UINT32_TO_PTR(o->index)))
842 pa_source_output_unref(o);
843
844 pa_source_invalidate_requested_latency(s);
845
846 return 0;
847 }
848
849 case PA_SOURCE_MESSAGE_SET_VOLUME:
850 s->thread_info.soft_volume = s->soft_volume;
851 return 0;
852
853 case PA_SOURCE_MESSAGE_GET_VOLUME:
854 return 0;
855
856 case PA_SOURCE_MESSAGE_SET_MUTE:
857 s->thread_info.soft_muted = s->muted;
858 return 0;
859
860 case PA_SOURCE_MESSAGE_GET_MUTE:
861 return 0;
862
863 case PA_SOURCE_MESSAGE_SET_STATE:
864 s->thread_info.state = PA_PTR_TO_UINT(userdata);
865 return 0;
866
867 case PA_SOURCE_MESSAGE_DETACH:
868
869 /* Detach all streams */
870 pa_source_detach_within_thread(s);
871 return 0;
872
873 case PA_SOURCE_MESSAGE_ATTACH:
874
875 /* Reattach all streams */
876 pa_source_attach_within_thread(s);
877 return 0;
878
879 case PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY: {
880
881 pa_usec_t *usec = userdata;
882 *usec = pa_source_get_requested_latency_within_thread(s);
883
884 if (*usec == (pa_usec_t) -1)
885 *usec = s->thread_info.max_latency;
886
887 return 0;
888 }
889
890 case PA_SOURCE_MESSAGE_SET_LATENCY_RANGE: {
891 pa_usec_t *r = userdata;
892
893 pa_source_update_latency_range(s, r[0], r[1]);
894
895 return 0;
896 }
897
898 case PA_SOURCE_MESSAGE_GET_LATENCY_RANGE: {
899 pa_usec_t *r = userdata;
900
901 r[0] = s->thread_info.min_latency;
902 r[1] = s->thread_info.max_latency;
903
904 return 0;
905 }
906
907 case PA_SOURCE_MESSAGE_GET_MAX_REWIND:
908
909 *((size_t*) userdata) = s->thread_info.max_rewind;
910 return 0;
911
912 case PA_SOURCE_MESSAGE_GET_LATENCY:
913
914 if (s->monitor_of) {
915 *((pa_usec_t*) userdata) = 0;
916 return 0;
917 }
918
919 /* Implementors need to overwrite this implementation! */
920 return -1;
921
922 case PA_SOURCE_MESSAGE_MAX:
923 ;
924 }
925
926 return -1;
927 }
928
929 /* Called from main thread */
930 int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
931 uint32_t idx;
932 pa_source *source;
933 int ret = 0;
934
935 pa_core_assert_ref(c);
936
937 for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx)))
938 ret -= pa_source_suspend(source, suspend) < 0;
939
940 return ret;
941 }
942
943 /* Called from main thread */
944 void pa_source_detach(pa_source *s) {
945 pa_source_assert_ref(s);
946 pa_assert(PA_SOURCE_IS_LINKED(s->state));
947
948 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
949 }
950
951 /* Called from main thread */
952 void pa_source_attach(pa_source *s) {
953 pa_source_assert_ref(s);
954 pa_assert(PA_SOURCE_IS_LINKED(s->state));
955
956 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
957 }
958
959 /* Called from IO thread */
960 void pa_source_detach_within_thread(pa_source *s) {
961 pa_source_output *o;
962 void *state = NULL;
963
964 pa_source_assert_ref(s);
965 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
966
967 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
968 if (o->detach)
969 o->detach(o);
970 }
971
972 /* Called from IO thread */
973 void pa_source_attach_within_thread(pa_source *s) {
974 pa_source_output *o;
975 void *state = NULL;
976
977 pa_source_assert_ref(s);
978 pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
979
980 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
981 if (o->attach)
982 o->attach(o);
983 }
984
985 /* Called from IO thread */
986 pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
987 pa_usec_t result = (pa_usec_t) -1;
988 pa_source_output *o;
989 void *state = NULL;
990
991 pa_source_assert_ref(s);
992
993 if (s->thread_info.requested_latency_valid)
994 return s->thread_info.requested_latency;
995
996 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
997
998 if (o->thread_info.requested_source_latency != (pa_usec_t) -1 &&
999 (result == (pa_usec_t) -1 || result > o->thread_info.requested_source_latency))
1000 result = o->thread_info.requested_source_latency;
1001
1002 if (result != (pa_usec_t) -1) {
1003 if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1004 result = s->thread_info.max_latency;
1005
1006 if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1007 result = s->thread_info.min_latency;
1008 }
1009
1010 s->thread_info.requested_latency = result;
1011 s->thread_info.requested_latency_valid = TRUE;
1012
1013 return result;
1014 }
1015
1016 /* Called from main thread */
1017 pa_usec_t pa_source_get_requested_latency(pa_source *s) {
1018 pa_usec_t usec;
1019
1020 pa_source_assert_ref(s);
1021 pa_assert(PA_SOURCE_IS_LINKED(s->state));
1022
1023 if (s->state == PA_SOURCE_SUSPENDED)
1024 return 0;
1025
1026 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1027
1028 return usec;
1029 }
1030
1031 /* Called from IO thread */
1032 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
1033 pa_source_output *o;
1034 void *state = NULL;
1035
1036 pa_source_assert_ref(s);
1037
1038 if (max_rewind == s->thread_info.max_rewind)
1039 return;
1040
1041 s->thread_info.max_rewind = max_rewind;
1042
1043 if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
1044 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1045 pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
1046 }
1047 }
1048
1049 void pa_source_invalidate_requested_latency(pa_source *s) {
1050 pa_source_output *o;
1051 void *state = NULL;
1052
1053 pa_source_assert_ref(s);
1054
1055 s->thread_info.requested_latency_valid = FALSE;
1056
1057 if (s->update_requested_latency)
1058 s->update_requested_latency(s);
1059
1060 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1061 if (o->update_source_requested_latency)
1062 o->update_source_requested_latency(o);
1063
1064 if (s->monitor_of)
1065 pa_sink_invalidate_requested_latency(s->monitor_of);
1066 }
1067
1068 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1069 pa_source_assert_ref(s);
1070
1071 /* min_latency == 0: no limit
1072 * min_latency == (size_t) -1: default limit
1073 * min_latency anything else: specified limit
1074 *
1075 * Similar for max_latency */
1076
1077 if (min_latency == (pa_usec_t) -1)
1078 min_latency = DEFAULT_MIN_LATENCY;
1079
1080 if (max_latency == (pa_usec_t) -1)
1081 max_latency = min_latency;
1082
1083 pa_assert(!min_latency || !max_latency ||
1084 min_latency <= max_latency);
1085
1086 if (PA_SOURCE_IS_LINKED(s->state)) {
1087 pa_usec_t r[2];
1088
1089 r[0] = min_latency;
1090 r[1] = max_latency;
1091
1092 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1093 } else {
1094 s->thread_info.min_latency = min_latency;
1095 s->thread_info.max_latency = max_latency;
1096
1097 s->thread_info.requested_latency_valid = FALSE;
1098 }
1099 }
1100
1101 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1102 pa_source_assert_ref(s);
1103 pa_assert(min_latency);
1104 pa_assert(max_latency);
1105
1106 if (PA_SOURCE_IS_LINKED(s->state)) {
1107 pa_usec_t r[2] = { 0, 0 };
1108
1109 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1110
1111 *min_latency = r[0];
1112 *max_latency = r[1];
1113 } else {
1114 *min_latency = s->thread_info.min_latency;
1115 *max_latency = s->thread_info.max_latency;
1116 }
1117 }
1118
1119 /* Called from IO thread */
1120 void pa_source_update_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1121 pa_source_output *o;
1122 void *state = NULL;
1123
1124 pa_source_assert_ref(s);
1125
1126 pa_assert(!min_latency || !max_latency ||
1127 min_latency <= max_latency);
1128
1129 s->thread_info.min_latency = min_latency;
1130 s->thread_info.max_latency = max_latency;
1131
1132 while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
1133 if (o->update_source_latency_range)
1134 o->update_source_latency_range(o);
1135
1136 pa_source_invalidate_requested_latency(s);
1137 }
1138
1139 size_t pa_source_get_max_rewind(pa_source *s) {
1140 size_t r;
1141 pa_source_assert_ref(s);
1142
1143 if (!PA_SOURCE_IS_LINKED(s->state))
1144 return s->thread_info.max_rewind;
1145
1146 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1147
1148 return r;
1149 }