]> code.delx.au - pulseaudio/blob - src/pulsecore/sink.c
don't include full path in driver name.
[pulseaudio] / src / pulsecore / sink.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 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 <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 #include <pulse/introspect.h>
32 #include <pulse/utf8.h>
33 #include <pulse/xmalloc.h>
34 #include <pulse/timeval.h>
35 #include <pulse/util.h>
36
37 #include <pulsecore/sink-input.h>
38 #include <pulsecore/namereg.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/sample-util.h>
41 #include <pulsecore/core-subscribe.h>
42 #include <pulsecore/log.h>
43 #include <pulsecore/macro.h>
44 #include <pulsecore/play-memblockq.h>
45
46 #include "sink.h"
47
48 #define MAX_MIX_CHANNELS 32
49 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
50 #define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
51
52 static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
53
54 static void sink_free(pa_object *s);
55
56 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
57 pa_assert(data);
58
59 memset(data, 0, sizeof(*data));
60 data->proplist = pa_proplist_new();
61
62 return data;
63 }
64
65 void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name) {
66 pa_assert(data);
67
68 pa_xfree(data->name);
69 data->name = pa_xstrdup(name);
70 }
71
72 void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec) {
73 pa_assert(data);
74
75 if ((data->sample_spec_is_set = !!spec))
76 data->sample_spec = *spec;
77 }
78
79 void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map) {
80 pa_assert(data);
81
82 if ((data->channel_map_is_set = !!map))
83 data->channel_map = *map;
84 }
85
86 void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
87 pa_assert(data);
88
89 if ((data->volume_is_set = !!volume))
90 data->volume = *volume;
91 }
92
93 void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute) {
94 pa_assert(data);
95
96 data->muted_is_set = TRUE;
97 data->muted = !!mute;
98 }
99
100 void pa_sink_new_data_done(pa_sink_new_data *data) {
101 pa_assert(data);
102
103 pa_xfree(data->name);
104 pa_proplist_free(data->proplist);
105 }
106
107 /* Called from main context */
108 static void reset_callbacks(pa_sink *s) {
109 pa_assert(s);
110
111 s->set_state = NULL;
112 s->get_volume = NULL;
113 s->set_volume = NULL;
114 s->get_mute = NULL;
115 s->set_mute = NULL;
116 s->request_rewind = NULL;
117 s->update_requested_latency = NULL;
118 }
119
120 /* Called from main context */
121 pa_sink* pa_sink_new(
122 pa_core *core,
123 pa_sink_new_data *data,
124 pa_sink_flags_t flags) {
125
126 pa_sink *s;
127 const char *name;
128 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
129 pa_source_new_data source_data;
130 const char *dn;
131
132 pa_assert(core);
133 pa_assert(data);
134 pa_assert(data->name);
135
136 s = pa_msgobject_new(pa_sink);
137
138 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
139 pa_xfree(s);
140 return NULL;
141 }
142
143 pa_sink_new_data_set_name(data, name);
144
145 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
146 pa_xfree(s);
147 pa_namereg_unregister(core, name);
148 return NULL;
149 }
150
151 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
152 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
153
154 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
155
156 if (!data->channel_map_is_set)
157 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
158
159 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
160 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
161
162 if (!data->volume_is_set)
163 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
164
165 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
166 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
167
168 if (!data->muted_is_set)
169 data->muted = FALSE;
170
171 if (data->card)
172 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
173
174 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
175 pa_xfree(s);
176 pa_namereg_unregister(core, name);
177 return NULL;
178 }
179
180 s->parent.parent.free = sink_free;
181 s->parent.process_msg = pa_sink_process_msg;
182
183 s->core = core;
184 s->state = PA_SINK_INIT;
185 s->flags = flags;
186 s->name = pa_xstrdup(name);
187 s->proplist = pa_proplist_copy(data->proplist);
188 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
189 s->module = data->module;
190 s->card = data->card;
191
192 s->sample_spec = data->sample_spec;
193 s->channel_map = data->channel_map;
194
195 s->inputs = pa_idxset_new(NULL, NULL);
196 s->n_corked = 0;
197
198 s->volume = data->volume;
199 s->base_volume = PA_VOLUME_NORM;
200 s->virtual_volume = s->volume;
201
202 s->muted = data->muted;
203 s->refresh_volume = s->refresh_muted = FALSE;
204
205 reset_callbacks(s);
206 s->userdata = NULL;
207
208 s->asyncmsgq = NULL;
209 s->rtpoll = NULL;
210
211 pa_silence_memchunk_get(
212 &core->silence_cache,
213 core->mempool,
214 &s->silence,
215 &s->sample_spec,
216 0);
217
218 s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
219 pa_cvolume_reset(&s->thread_info.soft_volume, s->sample_spec.channels);
220 s->thread_info.soft_muted = FALSE;
221 s->thread_info.state = s->state;
222 s->thread_info.rewind_nbytes = 0;
223 s->thread_info.rewind_requested = FALSE;
224 s->thread_info.max_rewind = 0;
225 s->thread_info.max_request = 0;
226 s->thread_info.requested_latency_valid = FALSE;
227 s->thread_info.requested_latency = 0;
228 s->thread_info.min_latency = DEFAULT_MIN_LATENCY;
229 s->thread_info.max_latency = 0;
230
231 pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
232
233 if (s->card)
234 pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
235
236 pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s",
237 s->index,
238 s->name,
239 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
240 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map));
241
242 pa_source_new_data_init(&source_data);
243 pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
244 pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
245 source_data.name = pa_sprintf_malloc("%s.monitor", name);
246 source_data.driver = data->driver;
247 source_data.module = data->module;
248 source_data.card = data->card;
249
250 dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
251 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
252 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "monitor");
253
254 s->monitor_source = pa_source_new(core, &source_data, PA_SOURCE_LATENCY);
255
256 pa_source_new_data_done(&source_data);
257
258 if (!s->monitor_source) {
259 pa_sink_unlink(s);
260 pa_sink_unref(s);
261 return NULL;
262 }
263
264 s->monitor_source->monitor_of = s;
265
266 pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
267 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
268
269 return s;
270 }
271
272 /* Called from main context */
273 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
274 int ret;
275 pa_bool_t suspend_change;
276 pa_sink_state_t original_state;
277
278 pa_assert(s);
279
280 if (s->state == state)
281 return 0;
282
283 original_state = s->state;
284
285 suspend_change =
286 (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
287 (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
288
289 if (s->set_state)
290 if ((ret = s->set_state(s, state)) < 0)
291 return ret;
292
293 if (s->asyncmsgq)
294 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
295
296 if (s->set_state)
297 s->set_state(s, original_state);
298
299 return ret;
300 }
301
302 s->state = state;
303
304 if (suspend_change) {
305 pa_sink_input *i;
306 uint32_t idx;
307
308 /* We're suspending or resuming, tell everyone about it */
309
310 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
311 if (i->suspend)
312 i->suspend(i, state == PA_SINK_SUSPENDED);
313 }
314
315 if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
316 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
317 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
318 }
319
320 return 0;
321 }
322
323 /* Called from main context */
324 void pa_sink_put(pa_sink* s) {
325 pa_sink_assert_ref(s);
326
327 pa_assert(s->state == PA_SINK_INIT);
328
329 /* The following fields must be initialized properly when calling _put() */
330 pa_assert(s->asyncmsgq);
331 pa_assert(s->rtpoll);
332 pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
333 s->thread_info.min_latency <= s->thread_info.max_latency);
334
335 if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
336 s->flags |= PA_SINK_DECIBEL_VOLUME;
337
338 s->thread_info.soft_volume = s->volume;
339 s->thread_info.soft_muted = s->muted;
340 }
341
342 pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
343
344 pa_source_put(s->monitor_source);
345
346 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
347 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
348 }
349
350 /* Called from main context */
351 void pa_sink_unlink(pa_sink* s) {
352 pa_bool_t linked;
353 pa_sink_input *i, *j = NULL;
354
355 pa_assert(s);
356
357 /* Please note that pa_sink_unlink() does more than simply
358 * reversing pa_sink_put(). It also undoes the registrations
359 * already done in pa_sink_new()! */
360
361 /* All operations here shall be idempotent, i.e. pa_sink_unlink()
362 * may be called multiple times on the same sink without bad
363 * effects. */
364
365 linked = PA_SINK_IS_LINKED(s->state);
366
367 if (linked)
368 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
369
370 if (s->state != PA_SINK_UNLINKED)
371 pa_namereg_unregister(s->core, s->name);
372 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
373
374 if (s->card)
375 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
376
377 while ((i = pa_idxset_first(s->inputs, NULL))) {
378 pa_assert(i != j);
379 pa_sink_input_kill(i);
380 j = i;
381 }
382
383 if (linked)
384 sink_set_state(s, PA_SINK_UNLINKED);
385 else
386 s->state = PA_SINK_UNLINKED;
387
388 reset_callbacks(s);
389
390 if (s->monitor_source)
391 pa_source_unlink(s->monitor_source);
392
393 if (linked) {
394 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
395 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
396 }
397 }
398
399 /* Called from main context */
400 static void sink_free(pa_object *o) {
401 pa_sink *s = PA_SINK(o);
402 pa_sink_input *i;
403
404 pa_assert(s);
405 pa_assert(pa_sink_refcnt(s) == 0);
406
407 if (PA_SINK_IS_LINKED(s->state))
408 pa_sink_unlink(s);
409
410 pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
411
412 if (s->monitor_source) {
413 pa_source_unref(s->monitor_source);
414 s->monitor_source = NULL;
415 }
416
417 pa_idxset_free(s->inputs, NULL, NULL);
418
419 while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
420 pa_sink_input_unref(i);
421
422 pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
423
424 if (s->silence.memblock)
425 pa_memblock_unref(s->silence.memblock);
426
427 pa_xfree(s->name);
428 pa_xfree(s->driver);
429
430 if (s->proplist)
431 pa_proplist_free(s->proplist);
432
433 pa_xfree(s);
434 }
435
436 /* Called from main context */
437 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
438 pa_sink_assert_ref(s);
439
440 s->asyncmsgq = q;
441
442 if (s->monitor_source)
443 pa_source_set_asyncmsgq(s->monitor_source, q);
444 }
445
446 /* Called from main context */
447 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
448 pa_sink_assert_ref(s);
449
450 s->rtpoll = p;
451 if (s->monitor_source)
452 pa_source_set_rtpoll(s->monitor_source, p);
453 }
454
455 /* Called from main context */
456 int pa_sink_update_status(pa_sink*s) {
457 pa_sink_assert_ref(s);
458 pa_assert(PA_SINK_IS_LINKED(s->state));
459
460 if (s->state == PA_SINK_SUSPENDED)
461 return 0;
462
463 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
464 }
465
466 /* Called from main context */
467 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
468 pa_sink_assert_ref(s);
469 pa_assert(PA_SINK_IS_LINKED(s->state));
470
471 if (suspend)
472 return sink_set_state(s, PA_SINK_SUSPENDED);
473 else
474 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
475 }
476
477 /* Called from IO thread context */
478 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
479 pa_sink_input *i;
480 void *state = NULL;
481 pa_sink_assert_ref(s);
482 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
483
484 s->thread_info.rewind_nbytes = 0;
485 s->thread_info.rewind_requested = FALSE;
486
487 if (nbytes > 0)
488 pa_log_debug("Processing rewind...");
489
490 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
491 pa_sink_input_assert_ref(i);
492 pa_sink_input_process_rewind(i, nbytes);
493 }
494
495 if (nbytes > 0)
496 if (s->monitor_source && PA_SOURCE_IS_OPENED(s->monitor_source->thread_info.state))
497 pa_source_process_rewind(s->monitor_source, nbytes);
498 }
499
500 /* Called from IO thread context */
501 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
502 pa_sink_input *i;
503 unsigned n = 0;
504 void *state = NULL;
505 size_t mixlength = *length;
506
507 pa_sink_assert_ref(s);
508 pa_assert(info);
509
510 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
511 pa_sink_input_assert_ref(i);
512
513 if (pa_sink_input_peek(i, *length, &info->chunk, &info->volume) < 0)
514 continue;
515
516 if (mixlength == 0 || info->chunk.length < mixlength)
517 mixlength = info->chunk.length;
518
519 if (pa_memblock_is_silence(info->chunk.memblock)) {
520 pa_memblock_unref(info->chunk.memblock);
521 continue;
522 }
523
524 info->userdata = pa_sink_input_ref(i);
525
526 pa_assert(info->chunk.memblock);
527 pa_assert(info->chunk.length > 0);
528
529 info++;
530 n++;
531 maxinfo--;
532 }
533
534 if (mixlength > 0)
535 *length = mixlength;
536
537 return n;
538 }
539
540 /* Called from IO thread context */
541 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
542 pa_sink_input *i;
543 void *state = NULL;
544 unsigned p = 0;
545 unsigned n_unreffed = 0;
546
547 pa_sink_assert_ref(s);
548 pa_assert(result);
549 pa_assert(result->memblock);
550 pa_assert(result->length > 0);
551
552 /* We optimize for the case where the order of the inputs has not changed */
553
554 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
555 unsigned j;
556 pa_mix_info* m = NULL;
557
558 pa_sink_input_assert_ref(i);
559
560 /* Let's try to find the matching entry info the pa_mix_info array */
561 for (j = 0; j < n; j ++) {
562
563 if (info[p].userdata == i) {
564 m = info + p;
565 break;
566 }
567
568 p++;
569 if (p >= n)
570 p = 0;
571 }
572
573 /* Drop read data */
574 pa_sink_input_drop(i, result->length);
575
576 if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) {
577
578 if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
579 void *ostate = NULL;
580 pa_source_output *o;
581 pa_memchunk c;
582
583 if (m && m->chunk.memblock) {
584 c = m->chunk;
585 pa_memblock_ref(c.memblock);
586 pa_assert(result->length <= c.length);
587 c.length = result->length;
588
589 pa_memchunk_make_writable(&c, 0);
590 pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
591 } else {
592 c = s->silence;
593 pa_memblock_ref(c.memblock);
594 pa_assert(result->length <= c.length);
595 c.length = result->length;
596 }
597
598 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
599 pa_source_output_assert_ref(o);
600 pa_assert(o->direct_on_input == i);
601 pa_source_post_direct(s->monitor_source, o, &c);
602 }
603
604 pa_memblock_unref(c.memblock);
605 }
606 }
607
608 if (m) {
609 if (m->chunk.memblock)
610 pa_memblock_unref(m->chunk.memblock);
611 pa_memchunk_reset(&m->chunk);
612
613 pa_sink_input_unref(m->userdata);
614 m->userdata = NULL;
615
616 n_unreffed += 1;
617 }
618 }
619
620 /* Now drop references to entries that are included in the
621 * pa_mix_info array but don't exist anymore */
622
623 if (n_unreffed < n) {
624 for (; n > 0; info++, n--) {
625 if (info->userdata)
626 pa_sink_input_unref(info->userdata);
627 if (info->chunk.memblock)
628 pa_memblock_unref(info->chunk.memblock);
629 }
630 }
631
632 if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
633 pa_source_post(s->monitor_source, result);
634 }
635
636 /* Called from IO thread context */
637 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
638 pa_mix_info info[MAX_MIX_CHANNELS];
639 unsigned n;
640 size_t block_size_max;
641
642 pa_sink_assert_ref(s);
643 pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
644 pa_assert(pa_frame_aligned(length, &s->sample_spec));
645 pa_assert(result);
646
647 pa_sink_ref(s);
648
649 pa_assert(!s->thread_info.rewind_requested);
650 pa_assert(s->thread_info.rewind_nbytes == 0);
651
652 if (length <= 0)
653 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
654
655 block_size_max = pa_mempool_block_size_max(s->core->mempool);
656 if (length > block_size_max)
657 length = pa_frame_align(block_size_max, &s->sample_spec);
658
659 pa_assert(length > 0);
660
661 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
662
663 if (n == 0) {
664
665 *result = s->silence;
666 pa_memblock_ref(result->memblock);
667
668 if (result->length > length)
669 result->length = length;
670
671 } else if (n == 1) {
672 pa_cvolume volume;
673
674 *result = info[0].chunk;
675 pa_memblock_ref(result->memblock);
676
677 if (result->length > length)
678 result->length = length;
679
680 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
681
682 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
683 pa_memchunk_make_writable(result, 0);
684 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
685 pa_silence_memchunk(result, &s->sample_spec);
686 else
687 pa_volume_memchunk(result, &s->sample_spec, &volume);
688 }
689 } else {
690 void *ptr;
691 result->memblock = pa_memblock_new(s->core->mempool, length);
692
693 ptr = pa_memblock_acquire(result->memblock);
694 result->length = pa_mix(info, n,
695 ptr, length,
696 &s->sample_spec,
697 &s->thread_info.soft_volume,
698 s->thread_info.soft_muted);
699 pa_memblock_release(result->memblock);
700
701 result->index = 0;
702 }
703
704 inputs_drop(s, info, n, result);
705
706 pa_sink_unref(s);
707 }
708
709 /* Called from IO thread context */
710 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
711 pa_mix_info info[MAX_MIX_CHANNELS];
712 unsigned n;
713 size_t length, block_size_max;
714
715 pa_sink_assert_ref(s);
716 pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
717 pa_assert(target);
718 pa_assert(target->memblock);
719 pa_assert(target->length > 0);
720 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
721
722 pa_sink_ref(s);
723
724 pa_assert(!s->thread_info.rewind_requested);
725 pa_assert(s->thread_info.rewind_nbytes == 0);
726
727 length = target->length;
728 block_size_max = pa_mempool_block_size_max(s->core->mempool);
729 if (length > block_size_max)
730 length = pa_frame_align(block_size_max, &s->sample_spec);
731
732 pa_assert(length > 0);
733
734 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
735
736 if (n == 0) {
737 if (target->length > length)
738 target->length = length;
739
740 pa_silence_memchunk(target, &s->sample_spec);
741 } else if (n == 1) {
742 pa_cvolume volume;
743
744 if (target->length > length)
745 target->length = length;
746
747 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
748
749 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
750 pa_silence_memchunk(target, &s->sample_spec);
751 else {
752 pa_memchunk vchunk;
753
754 vchunk = info[0].chunk;
755 pa_memblock_ref(vchunk.memblock);
756
757 if (vchunk.length > length)
758 vchunk.length = length;
759
760 if (!pa_cvolume_is_norm(&volume)) {
761 pa_memchunk_make_writable(&vchunk, 0);
762 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
763 }
764
765 pa_memchunk_memcpy(target, &vchunk);
766 pa_memblock_unref(vchunk.memblock);
767 }
768
769 } else {
770 void *ptr;
771
772 ptr = pa_memblock_acquire(target->memblock);
773
774 target->length = pa_mix(info, n,
775 (uint8_t*) ptr + target->index, length,
776 &s->sample_spec,
777 &s->thread_info.soft_volume,
778 s->thread_info.soft_muted);
779
780 pa_memblock_release(target->memblock);
781 }
782
783 inputs_drop(s, info, n, target);
784
785 pa_sink_unref(s);
786 }
787
788 /* Called from IO thread context */
789 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
790 pa_memchunk chunk;
791 size_t l, d;
792
793 pa_sink_assert_ref(s);
794 pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
795 pa_assert(target);
796 pa_assert(target->memblock);
797 pa_assert(target->length > 0);
798 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
799
800 pa_sink_ref(s);
801
802 pa_assert(!s->thread_info.rewind_requested);
803 pa_assert(s->thread_info.rewind_nbytes == 0);
804
805 l = target->length;
806 d = 0;
807 while (l > 0) {
808 chunk = *target;
809 chunk.index += d;
810 chunk.length -= d;
811
812 pa_sink_render_into(s, &chunk);
813
814 d += chunk.length;
815 l -= chunk.length;
816 }
817
818 pa_sink_unref(s);
819 }
820
821 /* Called from IO thread context */
822 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
823 pa_sink_assert_ref(s);
824 pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
825 pa_assert(length > 0);
826 pa_assert(pa_frame_aligned(length, &s->sample_spec));
827 pa_assert(result);
828
829 pa_assert(!s->thread_info.rewind_requested);
830 pa_assert(s->thread_info.rewind_nbytes == 0);
831
832 /*** This needs optimization ***/
833
834 result->index = 0;
835 result->length = length;
836 result->memblock = pa_memblock_new(s->core->mempool, length);
837
838 pa_sink_render_into_full(s, result);
839 }
840
841 /* Called from main thread */
842 pa_usec_t pa_sink_get_latency(pa_sink *s) {
843 pa_usec_t usec = 0;
844
845 pa_sink_assert_ref(s);
846 pa_assert(PA_SINK_IS_LINKED(s->state));
847
848 /* The returned value is supposed to be in the time domain of the sound card! */
849
850 if (!PA_SINK_IS_OPENED(s->state))
851 return 0;
852
853 if (!(s->flags & PA_SINK_LATENCY))
854 return 0;
855
856 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
857
858 return usec;
859 }
860
861 /* Called from main thread */
862 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume) {
863 pa_bool_t changed;
864 pa_sink_set_volume_data data;
865
866 pa_sink_assert_ref(s);
867 pa_assert(PA_SINK_IS_LINKED(s->state));
868 pa_assert(volume);
869 pa_assert(pa_cvolume_valid(volume));
870 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
871
872 data.sink = s;
873 data.virtual_volume = data.volume = *volume;
874
875 changed = !pa_cvolume_equal(&data.virtual_volume, &s->virtual_volume) ||
876 !pa_cvolume_equal(&data.volume, &s->volume);
877
878 if (changed) {
879 if (pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_SET_VOLUME], &data) < 0)
880 return;
881
882 changed = !pa_cvolume_equal(&data.virtual_volume, &s->virtual_volume); /* from client-side view */
883 }
884
885 s->volume = data.volume;
886 s->virtual_volume = data.virtual_volume;
887
888 if (s->set_volume && s->set_volume(s) < 0)
889 s->set_volume = NULL;
890
891 if (!s->set_volume)
892 pa_sink_set_soft_volume(s, &s->volume);
893
894 if (changed)
895 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
896 }
897
898 /* Called from main thread */
899 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
900 pa_sink_assert_ref(s);
901 pa_assert(volume);
902
903 if (PA_SINK_IS_LINKED(s->state))
904 pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, volume, 0, NULL);
905 else
906 s->thread_info.soft_volume = *volume;
907 }
908
909 /* Called from main thread */
910 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
911 pa_sink_assert_ref(s);
912 pa_assert(PA_SINK_IS_LINKED(s->state));
913
914 if (s->refresh_volume || force_refresh) {
915 struct pa_cvolume old_volume = s->virtual_volume;
916
917 if (s->get_volume && s->get_volume(s) < 0)
918 s->get_volume = NULL;
919
920 if (!s->get_volume) {
921 pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, &s->volume, 0, NULL);
922 s->virtual_volume = s->volume;
923 }
924
925 if (!pa_cvolume_equal(&old_volume, &s->virtual_volume))
926 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
927 }
928
929 return &s->virtual_volume;
930 }
931
932 /* Called from main thread */
933 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
934 pa_bool_t changed;
935
936 pa_sink_assert_ref(s);
937 pa_assert(PA_SINK_IS_LINKED(s->state));
938
939 changed = s->muted != mute;
940 s->muted = mute;
941
942 if (s->set_mute && s->set_mute(s) < 0)
943 s->set_mute = NULL;
944
945 if (!s->set_mute)
946 pa_asyncmsgq_post(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), 0, NULL, NULL);
947
948 if (changed)
949 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
950 }
951
952 /* Called from main thread */
953 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
954
955 pa_sink_assert_ref(s);
956 pa_assert(PA_SINK_IS_LINKED(s->state));
957
958 if (s->refresh_muted || force_refresh) {
959 pa_bool_t old_muted = s->muted;
960
961 if (s->get_mute && s->get_mute(s) < 0)
962 s->get_mute = NULL;
963
964 if (!s->get_mute)
965 pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &s->muted, 0, NULL);
966
967 if (old_muted != s->muted)
968 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
969 }
970
971 return s->muted;
972 }
973
974 /* Called from main thread */
975 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
976
977 pa_sink_assert_ref(s);
978
979 pa_proplist_update(s->proplist, mode, p);
980
981 if (PA_SINK_IS_LINKED(s->state)) {
982 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
983 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
984 }
985
986 return TRUE;
987 }
988
989 /* Called from main thread */
990 void pa_sink_set_description(pa_sink *s, const char *description) {
991 const char *old;
992 pa_sink_assert_ref(s);
993
994 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
995 return;
996
997 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
998
999 if (old && description && !strcmp(old, description))
1000 return;
1001
1002 if (description)
1003 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1004 else
1005 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1006
1007 if (s->monitor_source) {
1008 char *n;
1009
1010 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1011 pa_source_set_description(s->monitor_source, n);
1012 pa_xfree(n);
1013 }
1014
1015 if (PA_SINK_IS_LINKED(s->state)) {
1016 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1017 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1018 }
1019 }
1020
1021 /* Called from main thread */
1022 unsigned pa_sink_linked_by(pa_sink *s) {
1023 unsigned ret;
1024
1025 pa_sink_assert_ref(s);
1026 pa_assert(PA_SINK_IS_LINKED(s->state));
1027
1028 ret = pa_idxset_size(s->inputs);
1029
1030 /* We add in the number of streams connected to us here. Please
1031 * note the asymmmetry to pa_sink_used_by()! */
1032
1033 if (s->monitor_source)
1034 ret += pa_source_linked_by(s->monitor_source);
1035
1036 return ret;
1037 }
1038
1039 /* Called from main thread */
1040 unsigned pa_sink_used_by(pa_sink *s) {
1041 unsigned ret;
1042
1043 pa_sink_assert_ref(s);
1044 pa_assert(PA_SINK_IS_LINKED(s->state));
1045
1046 ret = pa_idxset_size(s->inputs);
1047 pa_assert(ret >= s->n_corked);
1048
1049 /* Streams connected to our monitor source do not matter for
1050 * pa_sink_used_by()!.*/
1051
1052 return ret - s->n_corked;
1053 }
1054
1055 /* Called from main thread */
1056 unsigned pa_sink_check_suspend(pa_sink *s) {
1057 unsigned ret;
1058 pa_sink_input *i;
1059 uint32_t idx;
1060
1061 pa_sink_assert_ref(s);
1062
1063 if (!PA_SINK_IS_LINKED(s->state))
1064 return 0;
1065
1066 ret = 0;
1067
1068 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1069 pa_sink_input_state_t st;
1070
1071 st = pa_sink_input_get_state(i);
1072 pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1073
1074 if (st == PA_SINK_INPUT_CORKED)
1075 continue;
1076
1077 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1078 continue;
1079
1080 ret ++;
1081 }
1082
1083 if (s->monitor_source)
1084 ret += pa_source_check_suspend(s->monitor_source);
1085
1086 return ret;
1087 }
1088
1089 /* Called from IO thread, except when it is not */
1090 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1091 pa_sink *s = PA_SINK(o);
1092 pa_sink_assert_ref(s);
1093
1094 switch ((pa_sink_message_t) code) {
1095
1096 case PA_SINK_MESSAGE_ADD_INPUT: {
1097 pa_sink_input *i = PA_SINK_INPUT(userdata);
1098
1099 /* If you change anything here, make sure to change the
1100 * sink input handling a few lines down at
1101 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1102
1103 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1104
1105 /* Since the caller sleeps in pa_sink_input_put(), we can
1106 * safely access data outside of thread_info even though
1107 * it is mutable */
1108
1109 if ((i->thread_info.sync_prev = i->sync_prev)) {
1110 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1111 pa_assert(i->sync_prev->sync_next == i);
1112 i->thread_info.sync_prev->thread_info.sync_next = i;
1113 }
1114
1115 if ((i->thread_info.sync_next = i->sync_next)) {
1116 pa_assert(i->sink == i->thread_info.sync_next->sink);
1117 pa_assert(i->sync_next->sync_prev == i);
1118 i->thread_info.sync_next->thread_info.sync_prev = i;
1119 }
1120
1121 pa_assert(!i->thread_info.attached);
1122 i->thread_info.attached = TRUE;
1123
1124 if (i->attach)
1125 i->attach(i);
1126
1127 pa_sink_input_set_state_within_thread(i, i->state);
1128
1129 /* The requested latency of the sink input needs to be
1130 * fixed up and then configured on the sink */
1131
1132 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1133 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1134
1135 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1136 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1137
1138 /* We don't rewind here automatically. This is left to the
1139 * sink input implementor because some sink inputs need a
1140 * slow start, i.e. need some time to buffer client
1141 * samples before beginning streaming. */
1142
1143 return 0;
1144 }
1145
1146 case PA_SINK_MESSAGE_REMOVE_INPUT: {
1147 pa_sink_input *i = PA_SINK_INPUT(userdata);
1148
1149 /* If you change anything here, make sure to change the
1150 * sink input handling a few lines down at
1151 * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1152
1153 if (i->detach)
1154 i->detach(i);
1155
1156 pa_sink_input_set_state_within_thread(i, i->state);
1157
1158 pa_assert(i->thread_info.attached);
1159 i->thread_info.attached = FALSE;
1160
1161 /* Since the caller sleeps in pa_sink_input_unlink(),
1162 * we can safely access data outside of thread_info even
1163 * though it is mutable */
1164
1165 pa_assert(!i->sync_prev);
1166 pa_assert(!i->sync_next);
1167
1168 if (i->thread_info.sync_prev) {
1169 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1170 i->thread_info.sync_prev = NULL;
1171 }
1172
1173 if (i->thread_info.sync_next) {
1174 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1175 i->thread_info.sync_next = NULL;
1176 }
1177
1178 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1179 pa_sink_input_unref(i);
1180
1181 pa_sink_invalidate_requested_latency(s);
1182 pa_sink_request_rewind(s, (size_t) -1);
1183
1184 return 0;
1185 }
1186
1187 case PA_SINK_MESSAGE_START_MOVE: {
1188 pa_sink_input *i = PA_SINK_INPUT(userdata);
1189
1190 /* We don't support moving synchronized streams. */
1191 pa_assert(!i->sync_prev);
1192 pa_assert(!i->sync_next);
1193 pa_assert(!i->thread_info.sync_next);
1194 pa_assert(!i->thread_info.sync_prev);
1195
1196 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1197 pa_usec_t usec = 0;
1198 size_t sink_nbytes, total_nbytes;
1199
1200 /* Get the latency of the sink */
1201 if (!(s->flags & PA_SINK_LATENCY) ||
1202 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1203 usec = 0;
1204
1205 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1206 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1207
1208 if (total_nbytes > 0) {
1209 i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1210 i->thread_info.rewrite_flush = TRUE;
1211 pa_sink_input_process_rewind(i, sink_nbytes);
1212 }
1213 }
1214
1215 if (i->detach)
1216 i->detach(i);
1217
1218 pa_assert(i->thread_info.attached);
1219 i->thread_info.attached = FALSE;
1220
1221 /* Let's remove the sink input ...*/
1222 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1223 pa_sink_input_unref(i);
1224
1225 pa_sink_invalidate_requested_latency(s);
1226
1227 pa_log_debug("Requesting rewind due to started move");
1228 pa_sink_request_rewind(s, (size_t) -1);
1229
1230 return 0;
1231 }
1232
1233 case PA_SINK_MESSAGE_FINISH_MOVE: {
1234 pa_sink_input *i = PA_SINK_INPUT(userdata);
1235
1236 /* We don't support moving synchronized streams. */
1237 pa_assert(!i->sync_prev);
1238 pa_assert(!i->sync_next);
1239 pa_assert(!i->thread_info.sync_next);
1240 pa_assert(!i->thread_info.sync_prev);
1241
1242 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1243
1244 pa_assert(!i->thread_info.attached);
1245 i->thread_info.attached = TRUE;
1246
1247 if (i->attach)
1248 i->attach(i);
1249
1250 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1251 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1252
1253 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1254 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1255
1256 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1257 pa_usec_t usec = 0;
1258 size_t nbytes;
1259
1260 /* Get the latency of the sink */
1261 if (!(s->flags & PA_SINK_LATENCY) ||
1262 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1263 usec = 0;
1264
1265 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1266
1267 if (nbytes > 0)
1268 pa_sink_input_drop(i, nbytes);
1269
1270 pa_log_debug("Requesting rewind due to finished move");
1271 pa_sink_request_rewind(s, nbytes);
1272 }
1273
1274 return 0;
1275 }
1276
1277 case PA_SINK_MESSAGE_SET_VOLUME:
1278 s->thread_info.soft_volume = *((pa_cvolume*) userdata);
1279
1280 pa_sink_request_rewind(s, (size_t) -1);
1281 return 0;
1282
1283 case PA_SINK_MESSAGE_SET_MUTE:
1284 s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
1285
1286 pa_sink_request_rewind(s, (size_t) -1);
1287 return 0;
1288
1289 case PA_SINK_MESSAGE_GET_VOLUME:
1290 *((pa_cvolume*) userdata) = s->thread_info.soft_volume;
1291 return 0;
1292
1293 case PA_SINK_MESSAGE_GET_MUTE:
1294 *((pa_bool_t*) userdata) = s->thread_info.soft_muted;
1295 return 0;
1296
1297 case PA_SINK_MESSAGE_SET_STATE:
1298
1299 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1300 return 0;
1301
1302 case PA_SINK_MESSAGE_DETACH:
1303
1304 /* Detach all streams */
1305 pa_sink_detach_within_thread(s);
1306 return 0;
1307
1308 case PA_SINK_MESSAGE_ATTACH:
1309
1310 /* Reattach all streams */
1311 pa_sink_attach_within_thread(s);
1312 return 0;
1313
1314 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1315
1316 pa_usec_t *usec = userdata;
1317 *usec = pa_sink_get_requested_latency_within_thread(s);
1318
1319 if (*usec == (pa_usec_t) -1)
1320 *usec = s->thread_info.max_latency;
1321
1322 return 0;
1323 }
1324
1325 case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1326 pa_usec_t *r = userdata;
1327
1328 pa_sink_update_latency_range(s, r[0], r[1]);
1329
1330 return 0;
1331 }
1332
1333 case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1334 pa_usec_t *r = userdata;
1335
1336 r[0] = s->thread_info.min_latency;
1337 r[1] = s->thread_info.max_latency;
1338
1339 return 0;
1340 }
1341
1342 case PA_SINK_MESSAGE_GET_MAX_REWIND:
1343
1344 *((size_t*) userdata) = s->thread_info.max_rewind;
1345 return 0;
1346
1347 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1348
1349 *((size_t*) userdata) = s->thread_info.max_request;
1350 return 0;
1351
1352 case PA_SINK_MESSAGE_GET_LATENCY:
1353 case PA_SINK_MESSAGE_MAX:
1354 ;
1355 }
1356
1357 return -1;
1358 }
1359
1360 /* Called from main thread */
1361 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1362 pa_sink *sink;
1363 uint32_t idx;
1364 int ret = 0;
1365
1366 pa_core_assert_ref(c);
1367
1368 for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx)))
1369 ret -= pa_sink_suspend(sink, suspend) < 0;
1370
1371 return ret;
1372 }
1373
1374 /* Called from main thread */
1375 void pa_sink_detach(pa_sink *s) {
1376 pa_sink_assert_ref(s);
1377 pa_assert(PA_SINK_IS_LINKED(s->state));
1378
1379 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1380 }
1381
1382 /* Called from main thread */
1383 void pa_sink_attach(pa_sink *s) {
1384 pa_sink_assert_ref(s);
1385 pa_assert(PA_SINK_IS_LINKED(s->state));
1386
1387 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1388 }
1389
1390 /* Called from IO thread */
1391 void pa_sink_detach_within_thread(pa_sink *s) {
1392 pa_sink_input *i;
1393 void *state = NULL;
1394
1395 pa_sink_assert_ref(s);
1396 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1397
1398 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1399 if (i->detach)
1400 i->detach(i);
1401
1402 if (s->monitor_source)
1403 pa_source_detach_within_thread(s->monitor_source);
1404 }
1405
1406 /* Called from IO thread */
1407 void pa_sink_attach_within_thread(pa_sink *s) {
1408 pa_sink_input *i;
1409 void *state = NULL;
1410
1411 pa_sink_assert_ref(s);
1412 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1413
1414 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1415 if (i->attach)
1416 i->attach(i);
1417
1418 if (s->monitor_source)
1419 pa_source_attach_within_thread(s->monitor_source);
1420 }
1421
1422 /* Called from IO thread */
1423 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1424 pa_sink_assert_ref(s);
1425 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1426
1427 if (nbytes == (size_t) -1)
1428 nbytes = s->thread_info.max_rewind;
1429
1430 nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1431
1432 if (s->thread_info.rewind_requested &&
1433 nbytes <= s->thread_info.rewind_nbytes)
1434 return;
1435
1436 s->thread_info.rewind_nbytes = nbytes;
1437 s->thread_info.rewind_requested = TRUE;
1438
1439 if (s->request_rewind)
1440 s->request_rewind(s);
1441 }
1442
1443 /* Called from IO thread */
1444 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1445 pa_usec_t result = (pa_usec_t) -1;
1446 pa_sink_input *i;
1447 void *state = NULL;
1448 pa_usec_t monitor_latency;
1449
1450 pa_sink_assert_ref(s);
1451
1452 if (s->thread_info.requested_latency_valid)
1453 return s->thread_info.requested_latency;
1454
1455 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1456
1457 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1458 (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1459 result = i->thread_info.requested_sink_latency;
1460
1461 monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1462
1463 if (monitor_latency != (pa_usec_t) -1 &&
1464 (result == (pa_usec_t) -1 || result > monitor_latency))
1465 result = monitor_latency;
1466
1467 if (result != (pa_usec_t) -1) {
1468 if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1469 result = s->thread_info.max_latency;
1470
1471 if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1472 result = s->thread_info.min_latency;
1473 }
1474
1475 s->thread_info.requested_latency = result;
1476 s->thread_info.requested_latency_valid = TRUE;
1477
1478 return result;
1479 }
1480
1481 /* Called from main thread */
1482 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1483 pa_usec_t usec = 0;
1484
1485 pa_sink_assert_ref(s);
1486 pa_assert(PA_SINK_IS_LINKED(s->state));
1487
1488 if (!PA_SINK_IS_OPENED(s->state))
1489 return 0;
1490
1491 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1492 return usec;
1493 }
1494
1495 /* Called from IO thread */
1496 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1497 pa_sink_input *i;
1498 void *state = NULL;
1499
1500 pa_sink_assert_ref(s);
1501
1502 if (max_rewind == s->thread_info.max_rewind)
1503 return;
1504
1505 s->thread_info.max_rewind = max_rewind;
1506
1507 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1508 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1509 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1510 }
1511
1512 if (s->monitor_source)
1513 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
1514 }
1515
1516 /* Called from IO thread */
1517 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
1518 void *state = NULL;
1519
1520 pa_sink_assert_ref(s);
1521
1522 if (max_request == s->thread_info.max_request)
1523 return;
1524
1525 s->thread_info.max_request = max_request;
1526
1527 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1528 pa_sink_input *i;
1529
1530 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1531 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1532 }
1533 }
1534
1535 /* Called from IO thread */
1536 void pa_sink_invalidate_requested_latency(pa_sink *s) {
1537 pa_sink_input *i;
1538 void *state = NULL;
1539
1540 pa_sink_assert_ref(s);
1541
1542 s->thread_info.requested_latency_valid = FALSE;
1543
1544 if (s->update_requested_latency)
1545 s->update_requested_latency(s);
1546
1547 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1548 if (i->update_sink_requested_latency)
1549 i->update_sink_requested_latency(i);
1550 }
1551
1552 /* Called from main thread */
1553 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1554 pa_sink_assert_ref(s);
1555
1556 /* min_latency == 0: no limit
1557 * min_latency == (size_t) -1: default limit
1558 * min_latency anything else: specified limit
1559 *
1560 * Similar for max_latency */
1561
1562 if (min_latency == (pa_usec_t) -1)
1563 min_latency = DEFAULT_MIN_LATENCY;
1564
1565 if (max_latency == (pa_usec_t) -1)
1566 max_latency = min_latency;
1567
1568 pa_assert(!min_latency || !max_latency ||
1569 min_latency <= max_latency);
1570
1571 if (PA_SINK_IS_LINKED(s->state)) {
1572 pa_usec_t r[2];
1573
1574 r[0] = min_latency;
1575 r[1] = max_latency;
1576
1577 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1578 } else {
1579 s->thread_info.min_latency = min_latency;
1580 s->thread_info.max_latency = max_latency;
1581
1582 s->monitor_source->thread_info.min_latency = min_latency;
1583 s->monitor_source->thread_info.max_latency = max_latency;
1584
1585 s->thread_info.requested_latency_valid = s->monitor_source->thread_info.requested_latency_valid = FALSE;
1586 }
1587 }
1588
1589 /* Called from main thread */
1590 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1591 pa_sink_assert_ref(s);
1592 pa_assert(min_latency);
1593 pa_assert(max_latency);
1594
1595 if (PA_SINK_IS_LINKED(s->state)) {
1596 pa_usec_t r[2] = { 0, 0 };
1597
1598 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1599
1600 *min_latency = r[0];
1601 *max_latency = r[1];
1602 } else {
1603 *min_latency = s->thread_info.min_latency;
1604 *max_latency = s->thread_info.max_latency;
1605 }
1606 }
1607
1608 /* Called from IO thread */
1609 void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1610 pa_sink_input *i;
1611 void *state = NULL;
1612
1613 pa_sink_assert_ref(s);
1614
1615 s->thread_info.min_latency = min_latency;
1616 s->thread_info.max_latency = max_latency;
1617
1618 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1619 if (i->update_sink_latency_range)
1620 i->update_sink_latency_range(i);
1621
1622 pa_sink_invalidate_requested_latency(s);
1623
1624 pa_source_update_latency_range(s->monitor_source, min_latency, max_latency);
1625 }
1626
1627 size_t pa_sink_get_max_rewind(pa_sink *s) {
1628 size_t r;
1629 pa_sink_assert_ref(s);
1630
1631 if (!PA_SINK_IS_LINKED(s->state))
1632 return s->thread_info.max_rewind;
1633
1634 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1635
1636 return r;
1637 }
1638
1639 size_t pa_sink_get_max_request(pa_sink *s) {
1640 size_t r;
1641 pa_sink_assert_ref(s);
1642
1643 if (!PA_SINK_IS_LINKED(s->state))
1644 return s->thread_info.max_request;
1645
1646 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
1647
1648 return r;
1649 }