]> code.delx.au - pulseaudio/blob - src/pulsecore/sink.c
core: add a seperate fixed_latency field for sinks/sources with fixed latency
[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.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 <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 #include <pulse/i18n.h>
37
38 #include <pulsecore/sink-input.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/sample-util.h>
42 #include <pulsecore/core-subscribe.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/play-memblockq.h>
46
47 #include "sink.h"
48
49 #define MAX_MIX_CHANNELS 32
50 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
51 #define ABSOLUTE_MIN_LATENCY (500)
52 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
53 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
54
55 static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
56
57 static void sink_free(pa_object *s);
58
59 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
60 pa_assert(data);
61
62 memset(data, 0, sizeof(*data));
63 data->proplist = pa_proplist_new();
64
65 return data;
66 }
67
68 void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name) {
69 pa_assert(data);
70
71 pa_xfree(data->name);
72 data->name = pa_xstrdup(name);
73 }
74
75 void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec) {
76 pa_assert(data);
77
78 if ((data->sample_spec_is_set = !!spec))
79 data->sample_spec = *spec;
80 }
81
82 void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map) {
83 pa_assert(data);
84
85 if ((data->channel_map_is_set = !!map))
86 data->channel_map = *map;
87 }
88
89 void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
90 pa_assert(data);
91
92 if ((data->volume_is_set = !!volume))
93 data->volume = *volume;
94 }
95
96 void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute) {
97 pa_assert(data);
98
99 data->muted_is_set = TRUE;
100 data->muted = !!mute;
101 }
102
103 void pa_sink_new_data_done(pa_sink_new_data *data) {
104 pa_assert(data);
105
106 pa_xfree(data->name);
107 pa_proplist_free(data->proplist);
108 }
109
110 /* Called from main context */
111 static void reset_callbacks(pa_sink *s) {
112 pa_assert(s);
113
114 s->set_state = NULL;
115 s->get_volume = NULL;
116 s->set_volume = NULL;
117 s->get_mute = NULL;
118 s->set_mute = NULL;
119 s->request_rewind = NULL;
120 s->update_requested_latency = NULL;
121 }
122
123 /* Called from main context */
124 pa_sink* pa_sink_new(
125 pa_core *core,
126 pa_sink_new_data *data,
127 pa_sink_flags_t flags) {
128
129 pa_sink *s;
130 const char *name;
131 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
132 pa_source_new_data source_data;
133 const char *dn;
134 char *pt;
135
136 pa_assert(core);
137 pa_assert(data);
138 pa_assert(data->name);
139
140 s = pa_msgobject_new(pa_sink);
141
142 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
143 pa_xfree(s);
144 return NULL;
145 }
146
147 pa_sink_new_data_set_name(data, name);
148
149 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
150 pa_xfree(s);
151 pa_namereg_unregister(core, name);
152 return NULL;
153 }
154
155 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
156 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
157
158 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
159
160 if (!data->channel_map_is_set)
161 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
162
163 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
164 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
165
166 if (!data->volume_is_set)
167 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
168
169 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
170 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
171
172 if (!data->muted_is_set)
173 data->muted = FALSE;
174
175 if (data->card)
176 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
177
178 pa_device_init_description(data->proplist);
179 pa_device_init_icon(data->proplist, TRUE);
180
181 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
182 pa_xfree(s);
183 pa_namereg_unregister(core, name);
184 return NULL;
185 }
186
187 s->parent.parent.free = sink_free;
188 s->parent.process_msg = pa_sink_process_msg;
189
190 s->core = core;
191 s->state = PA_SINK_INIT;
192 s->flags = flags;
193 s->name = pa_xstrdup(name);
194 s->proplist = pa_proplist_copy(data->proplist);
195 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
196 s->module = data->module;
197 s->card = data->card;
198
199 s->sample_spec = data->sample_spec;
200 s->channel_map = data->channel_map;
201
202 s->inputs = pa_idxset_new(NULL, NULL);
203 s->n_corked = 0;
204
205 s->virtual_volume = data->volume;
206 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
207 s->base_volume = PA_VOLUME_NORM;
208 s->n_volume_steps = PA_VOLUME_NORM+1;
209 s->muted = data->muted;
210 s->refresh_volume = s->refresh_muted = FALSE;
211
212 s->fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
213
214 reset_callbacks(s);
215 s->userdata = NULL;
216
217 s->asyncmsgq = NULL;
218 s->rtpoll = NULL;
219
220 pa_silence_memchunk_get(
221 &core->silence_cache,
222 core->mempool,
223 &s->silence,
224 &s->sample_spec,
225 0);
226
227 s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
228 s->thread_info.soft_volume = s->soft_volume;
229 s->thread_info.soft_muted = s->muted;
230 s->thread_info.state = s->state;
231 s->thread_info.rewind_nbytes = 0;
232 s->thread_info.rewind_requested = FALSE;
233 s->thread_info.max_rewind = 0;
234 s->thread_info.max_request = 0;
235 s->thread_info.requested_latency_valid = FALSE;
236 s->thread_info.requested_latency = 0;
237 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
238 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
239
240 pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
241
242 if (s->card)
243 pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
244
245 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
246 pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
247 s->index,
248 s->name,
249 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
250 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
251 pt);
252 pa_xfree(pt);
253
254 pa_source_new_data_init(&source_data);
255 pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
256 pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
257 source_data.name = pa_sprintf_malloc("%s.monitor", name);
258 source_data.driver = data->driver;
259 source_data.module = data->module;
260 source_data.card = data->card;
261
262 dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
263 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
264 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "monitor");
265
266 s->monitor_source = pa_source_new(core, &source_data, 0);
267
268 pa_source_new_data_done(&source_data);
269
270 if (!s->monitor_source) {
271 pa_sink_unlink(s);
272 pa_sink_unref(s);
273 return NULL;
274 }
275
276 s->monitor_source->monitor_of = s;
277
278 pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
279 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
280
281 return s;
282 }
283
284 /* Called from main context */
285 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
286 int ret;
287 pa_bool_t suspend_change;
288 pa_sink_state_t original_state;
289
290 pa_assert(s);
291
292 if (s->state == state)
293 return 0;
294
295 original_state = s->state;
296
297 suspend_change =
298 (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
299 (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
300
301 if (s->set_state)
302 if ((ret = s->set_state(s, state)) < 0)
303 return ret;
304
305 if (s->asyncmsgq)
306 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
307
308 if (s->set_state)
309 s->set_state(s, original_state);
310
311 return ret;
312 }
313
314 s->state = state;
315
316 if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
317 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
318 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
319 }
320
321 if (suspend_change) {
322 pa_sink_input *i;
323 uint32_t idx;
324
325 /* We're suspending or resuming, tell everyone about it */
326
327 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
328 if (s->state == PA_SINK_SUSPENDED &&
329 (i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND))
330 pa_sink_input_kill(i);
331 else if (i->suspend)
332 i->suspend(i, state == PA_SINK_SUSPENDED);
333
334 if (s->monitor_source)
335 pa_source_sync_suspend(s->monitor_source);
336 }
337
338 return 0;
339 }
340
341 /* Called from main context */
342 void pa_sink_put(pa_sink* s) {
343 pa_sink_assert_ref(s);
344
345 pa_assert(s->state == PA_SINK_INIT);
346
347 /* The following fields must be initialized properly when calling _put() */
348 pa_assert(s->asyncmsgq);
349 pa_assert(s->rtpoll);
350 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
351
352 if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
353 s->flags |= PA_SINK_DECIBEL_VOLUME;
354
355 s->thread_info.soft_volume = s->soft_volume;
356 s->thread_info.soft_muted = s->muted;
357 }
358
359 if (s->flags & PA_SINK_DECIBEL_VOLUME)
360 s->n_volume_steps = PA_VOLUME_NORM+1;
361
362 if (s->core->flat_volumes)
363 if (s->flags & PA_SINK_DECIBEL_VOLUME)
364 s->flags |= PA_SINK_FLAT_VOLUME;
365
366 if (s->flags & PA_SINK_LATENCY)
367 s->monitor_source->flags |= PA_SOURCE_LATENCY;
368
369 if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
370 s->monitor_source->flags |= PA_SOURCE_DYNAMIC_LATENCY;
371 s->fixed_latency = 0;
372 } else if (s->fixed_latency <= 0)
373 s->fixed_latency = DEFAULT_FIXED_LATENCY;
374
375 s->monitor_source->fixed_latency = s->fixed_latency;
376
377 pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
378
379 pa_source_put(s->monitor_source);
380
381 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
382 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
383 }
384
385 /* Called from main context */
386 void pa_sink_unlink(pa_sink* s) {
387 pa_bool_t linked;
388 pa_sink_input *i, *j = NULL;
389
390 pa_assert(s);
391
392 /* Please note that pa_sink_unlink() does more than simply
393 * reversing pa_sink_put(). It also undoes the registrations
394 * already done in pa_sink_new()! */
395
396 /* All operations here shall be idempotent, i.e. pa_sink_unlink()
397 * may be called multiple times on the same sink without bad
398 * effects. */
399
400 linked = PA_SINK_IS_LINKED(s->state);
401
402 if (linked)
403 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
404
405 if (s->state != PA_SINK_UNLINKED)
406 pa_namereg_unregister(s->core, s->name);
407 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
408
409 if (s->card)
410 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
411
412 while ((i = pa_idxset_first(s->inputs, NULL))) {
413 pa_assert(i != j);
414 pa_sink_input_kill(i);
415 j = i;
416 }
417
418 if (linked)
419 sink_set_state(s, PA_SINK_UNLINKED);
420 else
421 s->state = PA_SINK_UNLINKED;
422
423 reset_callbacks(s);
424
425 if (s->monitor_source)
426 pa_source_unlink(s->monitor_source);
427
428 if (linked) {
429 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
430 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
431 }
432 }
433
434 /* Called from main context */
435 static void sink_free(pa_object *o) {
436 pa_sink *s = PA_SINK(o);
437 pa_sink_input *i;
438
439 pa_assert(s);
440 pa_assert(pa_sink_refcnt(s) == 0);
441
442 if (PA_SINK_IS_LINKED(s->state))
443 pa_sink_unlink(s);
444
445 pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
446
447 if (s->monitor_source) {
448 pa_source_unref(s->monitor_source);
449 s->monitor_source = NULL;
450 }
451
452 pa_idxset_free(s->inputs, NULL, NULL);
453
454 while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
455 pa_sink_input_unref(i);
456
457 pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
458
459 if (s->silence.memblock)
460 pa_memblock_unref(s->silence.memblock);
461
462 pa_xfree(s->name);
463 pa_xfree(s->driver);
464
465 if (s->proplist)
466 pa_proplist_free(s->proplist);
467
468 pa_xfree(s);
469 }
470
471 /* Called from main context */
472 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
473 pa_sink_assert_ref(s);
474
475 s->asyncmsgq = q;
476
477 if (s->monitor_source)
478 pa_source_set_asyncmsgq(s->monitor_source, q);
479 }
480
481 /* Called from main context */
482 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
483 pa_sink_assert_ref(s);
484
485 s->rtpoll = p;
486 if (s->monitor_source)
487 pa_source_set_rtpoll(s->monitor_source, p);
488 }
489
490 /* Called from main context */
491 int pa_sink_update_status(pa_sink*s) {
492 pa_sink_assert_ref(s);
493 pa_assert(PA_SINK_IS_LINKED(s->state));
494
495 if (s->state == PA_SINK_SUSPENDED)
496 return 0;
497
498 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
499 }
500
501 /* Called from main context */
502 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
503 pa_sink_assert_ref(s);
504 pa_assert(PA_SINK_IS_LINKED(s->state));
505
506 if (suspend)
507 return sink_set_state(s, PA_SINK_SUSPENDED);
508 else
509 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
510 }
511
512 /* Called from main context */
513 pa_queue *pa_sink_move_all_start(pa_sink *s) {
514 pa_queue *q;
515 pa_sink_input *i, *n;
516 uint32_t idx;
517
518 pa_sink_assert_ref(s);
519 pa_assert(PA_SINK_IS_LINKED(s->state));
520
521 q = pa_queue_new();
522
523 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
524 n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
525
526 pa_sink_input_ref(i);
527
528 if (pa_sink_input_start_move(i) >= 0)
529 pa_queue_push(q, i);
530 else
531 pa_sink_input_unref(i);
532 }
533
534 return q;
535 }
536
537 /* Called from main context */
538 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
539 pa_sink_input *i;
540
541 pa_sink_assert_ref(s);
542 pa_assert(PA_SINK_IS_LINKED(s->state));
543 pa_assert(q);
544
545 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
546 if (pa_sink_input_finish_move(i, s, save) < 0)
547 pa_sink_input_kill(i);
548
549 pa_sink_input_unref(i);
550 }
551
552 pa_queue_free(q, NULL, NULL);
553 }
554
555 /* Called from main context */
556 void pa_sink_move_all_fail(pa_queue *q) {
557 pa_sink_input *i;
558 pa_assert(q);
559
560 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
561 if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) {
562 pa_sink_input_kill(i);
563 pa_sink_input_unref(i);
564 }
565 }
566
567 pa_queue_free(q, NULL, NULL);
568 }
569
570 /* Called from IO thread context */
571 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
572 pa_sink_input *i;
573 void *state = NULL;
574 pa_sink_assert_ref(s);
575 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
576
577 /* If nobody requested this and this is actually no real rewind
578 * then we can short cut this */
579 if (!s->thread_info.rewind_requested && nbytes <= 0)
580 return;
581
582 s->thread_info.rewind_nbytes = 0;
583 s->thread_info.rewind_requested = FALSE;
584
585 if (s->thread_info.state == PA_SINK_SUSPENDED)
586 return;
587
588 if (nbytes > 0)
589 pa_log_debug("Processing rewind...");
590
591 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
592 pa_sink_input_assert_ref(i);
593 pa_sink_input_process_rewind(i, nbytes);
594 }
595
596 if (nbytes > 0)
597 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
598 pa_source_process_rewind(s->monitor_source, nbytes);
599 }
600
601 /* Called from IO thread context */
602 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
603 pa_sink_input *i;
604 unsigned n = 0;
605 void *state = NULL;
606 size_t mixlength = *length;
607
608 pa_sink_assert_ref(s);
609 pa_assert(info);
610
611 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
612 pa_sink_input_assert_ref(i);
613
614 pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
615
616 if (mixlength == 0 || info->chunk.length < mixlength)
617 mixlength = info->chunk.length;
618
619 if (pa_memblock_is_silence(info->chunk.memblock)) {
620 pa_memblock_unref(info->chunk.memblock);
621 continue;
622 }
623
624 info->userdata = pa_sink_input_ref(i);
625
626 pa_assert(info->chunk.memblock);
627 pa_assert(info->chunk.length > 0);
628
629 info++;
630 n++;
631 maxinfo--;
632 }
633
634 if (mixlength > 0)
635 *length = mixlength;
636
637 return n;
638 }
639
640 /* Called from IO thread context */
641 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
642 pa_sink_input *i;
643 void *state = NULL;
644 unsigned p = 0;
645 unsigned n_unreffed = 0;
646
647 pa_sink_assert_ref(s);
648 pa_assert(result);
649 pa_assert(result->memblock);
650 pa_assert(result->length > 0);
651
652 /* We optimize for the case where the order of the inputs has not changed */
653
654 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
655 unsigned j;
656 pa_mix_info* m = NULL;
657
658 pa_sink_input_assert_ref(i);
659
660 /* Let's try to find the matching entry info the pa_mix_info array */
661 for (j = 0; j < n; j ++) {
662
663 if (info[p].userdata == i) {
664 m = info + p;
665 break;
666 }
667
668 p++;
669 if (p >= n)
670 p = 0;
671 }
672
673 /* Drop read data */
674 pa_sink_input_drop(i, result->length);
675
676 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
677
678 if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
679 void *ostate = NULL;
680 pa_source_output *o;
681 pa_memchunk c;
682
683 if (m && m->chunk.memblock) {
684 c = m->chunk;
685 pa_memblock_ref(c.memblock);
686 pa_assert(result->length <= c.length);
687 c.length = result->length;
688
689 pa_memchunk_make_writable(&c, 0);
690 pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
691 } else {
692 c = s->silence;
693 pa_memblock_ref(c.memblock);
694 pa_assert(result->length <= c.length);
695 c.length = result->length;
696 }
697
698 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
699 pa_source_output_assert_ref(o);
700 pa_assert(o->direct_on_input == i);
701 pa_source_post_direct(s->monitor_source, o, &c);
702 }
703
704 pa_memblock_unref(c.memblock);
705 }
706 }
707
708 if (m) {
709 if (m->chunk.memblock)
710 pa_memblock_unref(m->chunk.memblock);
711 pa_memchunk_reset(&m->chunk);
712
713 pa_sink_input_unref(m->userdata);
714 m->userdata = NULL;
715
716 n_unreffed += 1;
717 }
718 }
719
720 /* Now drop references to entries that are included in the
721 * pa_mix_info array but don't exist anymore */
722
723 if (n_unreffed < n) {
724 for (; n > 0; info++, n--) {
725 if (info->userdata)
726 pa_sink_input_unref(info->userdata);
727 if (info->chunk.memblock)
728 pa_memblock_unref(info->chunk.memblock);
729 }
730 }
731
732 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
733 pa_source_post(s->monitor_source, result);
734 }
735
736 /* Called from IO thread context */
737 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
738 pa_mix_info info[MAX_MIX_CHANNELS];
739 unsigned n;
740 size_t block_size_max;
741
742 pa_sink_assert_ref(s);
743 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
744 pa_assert(pa_frame_aligned(length, &s->sample_spec));
745 pa_assert(result);
746
747 pa_sink_ref(s);
748
749 pa_assert(!s->thread_info.rewind_requested);
750 pa_assert(s->thread_info.rewind_nbytes == 0);
751
752 if (s->thread_info.state == PA_SINK_SUSPENDED) {
753 result->memblock = pa_memblock_ref(s->silence.memblock);
754 result->index = s->silence.index;
755 result->length = PA_MIN(s->silence.length, length);
756 return;
757 }
758
759 if (length <= 0)
760 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
761
762 block_size_max = pa_mempool_block_size_max(s->core->mempool);
763 if (length > block_size_max)
764 length = pa_frame_align(block_size_max, &s->sample_spec);
765
766 pa_assert(length > 0);
767
768 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
769
770 if (n == 0) {
771
772 *result = s->silence;
773 pa_memblock_ref(result->memblock);
774
775 if (result->length > length)
776 result->length = length;
777
778 } else if (n == 1) {
779 pa_cvolume volume;
780
781 *result = info[0].chunk;
782 pa_memblock_ref(result->memblock);
783
784 if (result->length > length)
785 result->length = length;
786
787 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
788
789 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
790 pa_memchunk_make_writable(result, 0);
791 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
792 pa_silence_memchunk(result, &s->sample_spec);
793 else
794 pa_volume_memchunk(result, &s->sample_spec, &volume);
795 }
796 } else {
797 void *ptr;
798 result->memblock = pa_memblock_new(s->core->mempool, length);
799
800 ptr = pa_memblock_acquire(result->memblock);
801 result->length = pa_mix(info, n,
802 ptr, length,
803 &s->sample_spec,
804 &s->thread_info.soft_volume,
805 s->thread_info.soft_muted);
806 pa_memblock_release(result->memblock);
807
808 result->index = 0;
809 }
810
811 inputs_drop(s, info, n, result);
812
813 pa_sink_unref(s);
814 }
815
816 /* Called from IO thread context */
817 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
818 pa_mix_info info[MAX_MIX_CHANNELS];
819 unsigned n;
820 size_t length, block_size_max;
821
822 pa_sink_assert_ref(s);
823 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
824 pa_assert(target);
825 pa_assert(target->memblock);
826 pa_assert(target->length > 0);
827 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
828
829 pa_sink_ref(s);
830
831 pa_assert(!s->thread_info.rewind_requested);
832 pa_assert(s->thread_info.rewind_nbytes == 0);
833
834 if (s->thread_info.state == PA_SINK_SUSPENDED) {
835 pa_silence_memchunk(target, &s->sample_spec);
836 return;
837 }
838
839 length = target->length;
840 block_size_max = pa_mempool_block_size_max(s->core->mempool);
841 if (length > block_size_max)
842 length = pa_frame_align(block_size_max, &s->sample_spec);
843
844 pa_assert(length > 0);
845
846 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
847
848 if (n == 0) {
849 if (target->length > length)
850 target->length = length;
851
852 pa_silence_memchunk(target, &s->sample_spec);
853 } else if (n == 1) {
854 pa_cvolume volume;
855
856 if (target->length > length)
857 target->length = length;
858
859 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
860
861 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
862 pa_silence_memchunk(target, &s->sample_spec);
863 else {
864 pa_memchunk vchunk;
865
866 vchunk = info[0].chunk;
867 pa_memblock_ref(vchunk.memblock);
868
869 if (vchunk.length > length)
870 vchunk.length = length;
871
872 if (!pa_cvolume_is_norm(&volume)) {
873 pa_memchunk_make_writable(&vchunk, 0);
874 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
875 }
876
877 pa_memchunk_memcpy(target, &vchunk);
878 pa_memblock_unref(vchunk.memblock);
879 }
880
881 } else {
882 void *ptr;
883
884 ptr = pa_memblock_acquire(target->memblock);
885
886 target->length = pa_mix(info, n,
887 (uint8_t*) ptr + target->index, length,
888 &s->sample_spec,
889 &s->thread_info.soft_volume,
890 s->thread_info.soft_muted);
891
892 pa_memblock_release(target->memblock);
893 }
894
895 inputs_drop(s, info, n, target);
896
897 pa_sink_unref(s);
898 }
899
900 /* Called from IO thread context */
901 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
902 pa_memchunk chunk;
903 size_t l, d;
904
905 pa_sink_assert_ref(s);
906 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
907 pa_assert(target);
908 pa_assert(target->memblock);
909 pa_assert(target->length > 0);
910 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
911
912 pa_sink_ref(s);
913
914 pa_assert(!s->thread_info.rewind_requested);
915 pa_assert(s->thread_info.rewind_nbytes == 0);
916
917 l = target->length;
918 d = 0;
919 while (l > 0) {
920 chunk = *target;
921 chunk.index += d;
922 chunk.length -= d;
923
924 pa_sink_render_into(s, &chunk);
925
926 d += chunk.length;
927 l -= chunk.length;
928 }
929
930 pa_sink_unref(s);
931 }
932
933 /* Called from IO thread context */
934 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
935 pa_sink_assert_ref(s);
936 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
937 pa_assert(length > 0);
938 pa_assert(pa_frame_aligned(length, &s->sample_spec));
939 pa_assert(result);
940
941 pa_assert(!s->thread_info.rewind_requested);
942 pa_assert(s->thread_info.rewind_nbytes == 0);
943
944 /*** This needs optimization ***/
945
946 result->index = 0;
947 result->length = length;
948 result->memblock = pa_memblock_new(s->core->mempool, length);
949
950 pa_sink_render_into_full(s, result);
951 }
952
953 /* Called from main thread */
954 pa_usec_t pa_sink_get_latency(pa_sink *s) {
955 pa_usec_t usec = 0;
956
957 pa_sink_assert_ref(s);
958 pa_assert(PA_SINK_IS_LINKED(s->state));
959
960 /* The returned value is supposed to be in the time domain of the sound card! */
961
962 if (s->state == PA_SINK_SUSPENDED)
963 return 0;
964
965 if (!(s->flags & PA_SINK_LATENCY))
966 return 0;
967
968 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
969
970 return usec;
971 }
972
973 /* Called from IO thread */
974 pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
975 pa_usec_t usec = 0;
976 pa_msgobject *o;
977
978 pa_sink_assert_ref(s);
979 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
980
981 /* The returned value is supposed to be in the time domain of the sound card! */
982
983 if (s->thread_info.state == PA_SINK_SUSPENDED)
984 return 0;
985
986 if (!(s->flags & PA_SINK_LATENCY))
987 return 0;
988
989 o = PA_MSGOBJECT(s);
990
991 /* We probably should make this a proper vtable callback instead of going through process_msg() */
992
993 if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
994 return -1;
995
996 return usec;
997 }
998
999 static void compute_new_soft_volume(pa_sink_input *i, const pa_cvolume *new_volume) {
1000 unsigned c;
1001
1002 pa_sink_input_assert_ref(i);
1003 pa_assert(new_volume->channels == i->sample_spec.channels);
1004
1005 /*
1006 * This basically calculates:
1007 *
1008 * i->relative_volume := i->virtual_volume / new_volume
1009 * i->soft_volume := i->relative_volume * i->volume_factor
1010 */
1011
1012 /* The new sink volume passed in here must already be remapped to
1013 * the sink input's channel map! */
1014
1015 i->soft_volume.channels = i->sample_spec.channels;
1016
1017 for (c = 0; c < i->sample_spec.channels; c++)
1018
1019 if (new_volume->values[c] <= PA_VOLUME_MUTED)
1020 /* We leave i->relative_volume untouched */
1021 i->soft_volume.values[c] = PA_VOLUME_MUTED;
1022 else {
1023 i->relative_volume[c] =
1024 pa_sw_volume_to_linear(i->virtual_volume.values[c]) /
1025 pa_sw_volume_to_linear(new_volume->values[c]);
1026
1027 i->soft_volume.values[c] = pa_sw_volume_from_linear(
1028 i->relative_volume[c] *
1029 pa_sw_volume_to_linear(i->volume_factor.values[c]));
1030 }
1031
1032 /* Hooks have the ability to play games with i->soft_volume */
1033 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1034
1035 /* We don't copy the soft_volume to the thread_info data
1036 * here. That must be done by the caller */
1037 }
1038
1039 /* Called from main thread */
1040 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
1041 pa_sink_input *i;
1042 uint32_t idx;
1043
1044 pa_sink_assert_ref(s);
1045 pa_assert(new_volume);
1046 pa_assert(PA_SINK_IS_LINKED(s->state));
1047 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1048
1049 /* This is called whenever a sink input volume changes and we
1050 * might need to fix up the sink volume accordingly. Please note
1051 * that we don't actually update the sinks volume here, we only
1052 * return how it needs to be updated. The caller should then call
1053 * pa_sink_set_volume().*/
1054
1055 if (pa_idxset_isempty(s->inputs)) {
1056 /* In the special case that we have no sink input we leave the
1057 * volume unmodified. */
1058 *new_volume = s->virtual_volume;
1059 return;
1060 }
1061
1062 pa_cvolume_mute(new_volume, s->channel_map.channels);
1063
1064 /* First let's determine the new maximum volume of all inputs
1065 * connected to this sink */
1066 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1067 unsigned c;
1068 pa_cvolume remapped_volume;
1069
1070 remapped_volume = i->virtual_volume;
1071 pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
1072
1073 for (c = 0; c < new_volume->channels; c++)
1074 if (remapped_volume.values[c] > new_volume->values[c])
1075 new_volume->values[c] = remapped_volume.values[c];
1076 }
1077
1078 /* Then, let's update the soft volumes of all inputs connected
1079 * to this sink */
1080 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1081 pa_cvolume remapped_new_volume;
1082
1083 remapped_new_volume = *new_volume;
1084 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1085 compute_new_soft_volume(i, &remapped_new_volume);
1086
1087 /* We don't copy soft_volume to the thread_info data here
1088 * (i.e. issue PA_SINK_INPUT_MESSAGE_SET_VOLUME) because we
1089 * want the update to be atomically with the sink volume
1090 * update, hence we do it within the pa_sink_set_volume() call
1091 * below */
1092 }
1093 }
1094
1095 /* Called from main thread */
1096 void pa_sink_propagate_flat_volume(pa_sink *s) {
1097 pa_sink_input *i;
1098 uint32_t idx;
1099
1100 pa_sink_assert_ref(s);
1101 pa_assert(PA_SINK_IS_LINKED(s->state));
1102 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1103
1104 /* This is called whenever the sink volume changes that is not
1105 * caused by a sink input volume change. We need to fix up the
1106 * sink input volumes accordingly */
1107
1108 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1109 pa_cvolume sink_volume, new_virtual_volume;
1110 unsigned c;
1111
1112 /* This basically calculates i->virtual_volume := i->relative_volume * s->virtual_volume */
1113
1114 sink_volume = s->virtual_volume;
1115 pa_cvolume_remap(&sink_volume, &s->channel_map, &i->channel_map);
1116
1117 for (c = 0; c < i->sample_spec.channels; c++)
1118 new_virtual_volume.values[c] = pa_sw_volume_from_linear(
1119 i->relative_volume[c] *
1120 pa_sw_volume_to_linear(sink_volume.values[c]));
1121
1122 new_virtual_volume.channels = i->sample_spec.channels;
1123
1124 if (!pa_cvolume_equal(&new_virtual_volume, &i->virtual_volume)) {
1125 i->virtual_volume = new_virtual_volume;
1126
1127 /* Hmm, the soft volume might no longer actually match
1128 * what has been chosen as new virtual volume here,
1129 * especially when the old volume was
1130 * PA_VOLUME_MUTED. Hence let's recalculate the soft
1131 * volumes here. */
1132 compute_new_soft_volume(i, &sink_volume);
1133
1134 /* The virtual volume changed, let's tell people so */
1135 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1136 }
1137 }
1138
1139 /* If the soft_volume of any of the sink inputs got changed, let's
1140 * make sure the thread copies are synced up. */
1141 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SYNC_VOLUMES, NULL, 0, NULL) == 0);
1142 }
1143
1144 /* Called from main thread */
1145 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
1146 pa_bool_t virtual_volume_changed;
1147
1148 pa_sink_assert_ref(s);
1149 pa_assert(PA_SINK_IS_LINKED(s->state));
1150 pa_assert(volume);
1151 pa_assert(pa_cvolume_valid(volume));
1152 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
1153
1154 virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume);
1155 s->virtual_volume = *volume;
1156
1157 /* Propagate this volume change back to the inputs */
1158 if (virtual_volume_changed)
1159 if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
1160 pa_sink_propagate_flat_volume(s);
1161
1162 if (s->set_volume) {
1163 /* If we have a function set_volume(), then we do not apply a
1164 * soft volume by default. However, set_volume() is apply one
1165 * to s->soft_volume */
1166
1167 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
1168 s->set_volume(s);
1169
1170 } else
1171 /* If we have no function set_volume(), then the soft volume
1172 * becomes the virtual volume */
1173 s->soft_volume = s->virtual_volume;
1174
1175 /* This tells the sink that soft and/or virtual volume changed */
1176 if (sendmsg)
1177 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1178
1179 if (virtual_volume_changed)
1180 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1181 }
1182
1183 /* Called from main thread. Only to be called by sink implementor */
1184 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
1185 pa_sink_assert_ref(s);
1186 pa_assert(volume);
1187
1188 s->soft_volume = *volume;
1189
1190 if (PA_SINK_IS_LINKED(s->state))
1191 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1192 else
1193 s->thread_info.soft_volume = *volume;
1194 }
1195
1196 /* Called from main thread */
1197 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
1198 pa_sink_assert_ref(s);
1199
1200 if (s->refresh_volume || force_refresh) {
1201 struct pa_cvolume old_virtual_volume = s->virtual_volume;
1202
1203 if (s->get_volume)
1204 s->get_volume(s);
1205
1206 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
1207
1208 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
1209
1210 if (s->flags & PA_SINK_FLAT_VOLUME)
1211 pa_sink_propagate_flat_volume(s);
1212
1213 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1214 }
1215 }
1216
1217 return &s->virtual_volume;
1218 }
1219
1220 /* Called from main thread */
1221 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
1222 pa_sink_assert_ref(s);
1223
1224 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1225
1226 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
1227 return;
1228
1229 s->virtual_volume = *new_volume;
1230 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1231 }
1232
1233 /* Called from main thread */
1234 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
1235 pa_bool_t old_muted;
1236
1237 pa_sink_assert_ref(s);
1238 pa_assert(PA_SINK_IS_LINKED(s->state));
1239
1240 old_muted = s->muted;
1241 s->muted = mute;
1242
1243 if (s->set_mute)
1244 s->set_mute(s);
1245
1246 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
1247
1248 if (old_muted != s->muted)
1249 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1250 }
1251
1252 /* Called from main thread */
1253 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
1254
1255 pa_sink_assert_ref(s);
1256
1257 if (s->refresh_muted || force_refresh) {
1258 pa_bool_t old_muted = s->muted;
1259
1260 if (s->get_mute)
1261 s->get_mute(s);
1262
1263 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
1264
1265 if (old_muted != s->muted)
1266 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1267 }
1268
1269 return s->muted;
1270 }
1271
1272 /* Called from main thread */
1273 void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
1274 pa_sink_assert_ref(s);
1275
1276 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1277
1278 if (s->muted == new_muted)
1279 return;
1280
1281 s->muted = new_muted;
1282 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1283 }
1284
1285 /* Called from main thread */
1286 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
1287 pa_sink_assert_ref(s);
1288
1289 if (p)
1290 pa_proplist_update(s->proplist, mode, p);
1291
1292 if (PA_SINK_IS_LINKED(s->state)) {
1293 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1294 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1295 }
1296
1297 return TRUE;
1298 }
1299
1300 /* Called from main thread */
1301 void pa_sink_set_description(pa_sink *s, const char *description) {
1302 const char *old;
1303 pa_sink_assert_ref(s);
1304
1305 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1306 return;
1307
1308 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1309
1310 if (old && description && !strcmp(old, description))
1311 return;
1312
1313 if (description)
1314 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1315 else
1316 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1317
1318 if (s->monitor_source) {
1319 char *n;
1320
1321 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1322 pa_source_set_description(s->monitor_source, n);
1323 pa_xfree(n);
1324 }
1325
1326 if (PA_SINK_IS_LINKED(s->state)) {
1327 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1328 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1329 }
1330 }
1331
1332 /* Called from main thread */
1333 unsigned pa_sink_linked_by(pa_sink *s) {
1334 unsigned ret;
1335
1336 pa_sink_assert_ref(s);
1337 pa_assert(PA_SINK_IS_LINKED(s->state));
1338
1339 ret = pa_idxset_size(s->inputs);
1340
1341 /* We add in the number of streams connected to us here. Please
1342 * note the asymmmetry to pa_sink_used_by()! */
1343
1344 if (s->monitor_source)
1345 ret += pa_source_linked_by(s->monitor_source);
1346
1347 return ret;
1348 }
1349
1350 /* Called from main thread */
1351 unsigned pa_sink_used_by(pa_sink *s) {
1352 unsigned ret;
1353
1354 pa_sink_assert_ref(s);
1355 pa_assert(PA_SINK_IS_LINKED(s->state));
1356
1357 ret = pa_idxset_size(s->inputs);
1358 pa_assert(ret >= s->n_corked);
1359
1360 /* Streams connected to our monitor source do not matter for
1361 * pa_sink_used_by()!.*/
1362
1363 return ret - s->n_corked;
1364 }
1365
1366 /* Called from main thread */
1367 unsigned pa_sink_check_suspend(pa_sink *s) {
1368 unsigned ret;
1369 pa_sink_input *i;
1370 uint32_t idx;
1371
1372 pa_sink_assert_ref(s);
1373
1374 if (!PA_SINK_IS_LINKED(s->state))
1375 return 0;
1376
1377 ret = 0;
1378
1379 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1380 pa_sink_input_state_t st;
1381
1382 st = pa_sink_input_get_state(i);
1383 pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1384
1385 if (st == PA_SINK_INPUT_CORKED)
1386 continue;
1387
1388 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1389 continue;
1390
1391 ret ++;
1392 }
1393
1394 if (s->monitor_source)
1395 ret += pa_source_check_suspend(s->monitor_source);
1396
1397 return ret;
1398 }
1399
1400 /* Called from the IO thread */
1401 static void sync_input_volumes_within_thread(pa_sink *s) {
1402 pa_sink_input *i;
1403 void *state = NULL;
1404
1405 pa_sink_assert_ref(s);
1406
1407 while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
1408 if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
1409 continue;
1410
1411 i->thread_info.soft_volume = i->soft_volume;
1412 pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1413 }
1414 }
1415
1416 /* Called from IO thread, except when it is not */
1417 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1418 pa_sink *s = PA_SINK(o);
1419 pa_sink_assert_ref(s);
1420
1421 switch ((pa_sink_message_t) code) {
1422
1423 case PA_SINK_MESSAGE_ADD_INPUT: {
1424 pa_sink_input *i = PA_SINK_INPUT(userdata);
1425
1426 /* If you change anything here, make sure to change the
1427 * sink input handling a few lines down at
1428 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1429
1430 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1431
1432 /* Since the caller sleeps in pa_sink_input_put(), we can
1433 * safely access data outside of thread_info even though
1434 * it is mutable */
1435
1436 if ((i->thread_info.sync_prev = i->sync_prev)) {
1437 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1438 pa_assert(i->sync_prev->sync_next == i);
1439 i->thread_info.sync_prev->thread_info.sync_next = i;
1440 }
1441
1442 if ((i->thread_info.sync_next = i->sync_next)) {
1443 pa_assert(i->sink == i->thread_info.sync_next->sink);
1444 pa_assert(i->sync_next->sync_prev == i);
1445 i->thread_info.sync_next->thread_info.sync_prev = i;
1446 }
1447
1448 pa_assert(!i->thread_info.attached);
1449 i->thread_info.attached = TRUE;
1450
1451 if (i->attach)
1452 i->attach(i);
1453
1454 pa_sink_input_set_state_within_thread(i, i->state);
1455
1456 /* The requested latency of the sink input needs to be
1457 * fixed up and then configured on the sink */
1458
1459 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1460 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1461
1462 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1463 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1464
1465 /* We don't rewind here automatically. This is left to the
1466 * sink input implementor because some sink inputs need a
1467 * slow start, i.e. need some time to buffer client
1468 * samples before beginning streaming. */
1469
1470 /* In flat volume mode we need to update the volume as
1471 * well */
1472 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1473 }
1474
1475 case PA_SINK_MESSAGE_REMOVE_INPUT: {
1476 pa_sink_input *i = PA_SINK_INPUT(userdata);
1477
1478 /* If you change anything here, make sure to change the
1479 * sink input handling a few lines down at
1480 * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1481
1482 if (i->detach)
1483 i->detach(i);
1484
1485 pa_sink_input_set_state_within_thread(i, i->state);
1486
1487 pa_assert(i->thread_info.attached);
1488 i->thread_info.attached = FALSE;
1489
1490 /* Since the caller sleeps in pa_sink_input_unlink(),
1491 * we can safely access data outside of thread_info even
1492 * though it is mutable */
1493
1494 pa_assert(!i->sync_prev);
1495 pa_assert(!i->sync_next);
1496
1497 if (i->thread_info.sync_prev) {
1498 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1499 i->thread_info.sync_prev = NULL;
1500 }
1501
1502 if (i->thread_info.sync_next) {
1503 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1504 i->thread_info.sync_next = NULL;
1505 }
1506
1507 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1508 pa_sink_input_unref(i);
1509
1510 pa_sink_invalidate_requested_latency(s);
1511 pa_sink_request_rewind(s, (size_t) -1);
1512
1513 /* In flat volume mode we need to update the volume as
1514 * well */
1515 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1516 }
1517
1518 case PA_SINK_MESSAGE_START_MOVE: {
1519 pa_sink_input *i = PA_SINK_INPUT(userdata);
1520
1521 /* We don't support moving synchronized streams. */
1522 pa_assert(!i->sync_prev);
1523 pa_assert(!i->sync_next);
1524 pa_assert(!i->thread_info.sync_next);
1525 pa_assert(!i->thread_info.sync_prev);
1526
1527 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1528 pa_usec_t usec = 0;
1529 size_t sink_nbytes, total_nbytes;
1530
1531 /* Get the latency of the sink */
1532 if (!(s->flags & PA_SINK_LATENCY) ||
1533 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1534 usec = 0;
1535
1536 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1537 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1538
1539 if (total_nbytes > 0) {
1540 i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1541 i->thread_info.rewrite_flush = TRUE;
1542 pa_sink_input_process_rewind(i, sink_nbytes);
1543 }
1544 }
1545
1546 if (i->detach)
1547 i->detach(i);
1548
1549 pa_assert(i->thread_info.attached);
1550 i->thread_info.attached = FALSE;
1551
1552 /* Let's remove the sink input ...*/
1553 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1554 pa_sink_input_unref(i);
1555
1556 pa_sink_invalidate_requested_latency(s);
1557
1558 pa_log_debug("Requesting rewind due to started move");
1559 pa_sink_request_rewind(s, (size_t) -1);
1560
1561 /* In flat volume mode we need to update the volume as
1562 * well */
1563 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1564 }
1565
1566 case PA_SINK_MESSAGE_FINISH_MOVE: {
1567 pa_sink_input *i = PA_SINK_INPUT(userdata);
1568
1569 /* We don't support moving synchronized streams. */
1570 pa_assert(!i->sync_prev);
1571 pa_assert(!i->sync_next);
1572 pa_assert(!i->thread_info.sync_next);
1573 pa_assert(!i->thread_info.sync_prev);
1574
1575 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1576
1577 pa_assert(!i->thread_info.attached);
1578 i->thread_info.attached = TRUE;
1579
1580 if (i->attach)
1581 i->attach(i);
1582
1583 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1584 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1585
1586 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1587 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1588
1589 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1590 pa_usec_t usec = 0;
1591 size_t nbytes;
1592
1593 /* Get the latency of the sink */
1594 if (!(s->flags & PA_SINK_LATENCY) ||
1595 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1596 usec = 0;
1597
1598 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1599
1600 if (nbytes > 0)
1601 pa_sink_input_drop(i, nbytes);
1602
1603 pa_log_debug("Requesting rewind due to finished move");
1604 pa_sink_request_rewind(s, nbytes);
1605 }
1606
1607 /* In flat volume mode we need to update the volume as
1608 * well */
1609 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1610 }
1611
1612 case PA_SINK_MESSAGE_SET_VOLUME:
1613
1614 if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
1615 s->thread_info.soft_volume = s->soft_volume;
1616 pa_sink_request_rewind(s, (size_t) -1);
1617 }
1618
1619 if (!(s->flags & PA_SINK_FLAT_VOLUME))
1620 return 0;
1621
1622 /* Fall through ... */
1623
1624 case PA_SINK_MESSAGE_SYNC_VOLUMES:
1625 sync_input_volumes_within_thread(s);
1626 return 0;
1627
1628 case PA_SINK_MESSAGE_GET_VOLUME:
1629 return 0;
1630
1631 case PA_SINK_MESSAGE_SET_MUTE:
1632
1633 if (s->thread_info.soft_muted != s->muted) {
1634 s->thread_info.soft_muted = s->muted;
1635 pa_sink_request_rewind(s, (size_t) -1);
1636 }
1637
1638 return 0;
1639
1640 case PA_SINK_MESSAGE_GET_MUTE:
1641 return 0;
1642
1643 case PA_SINK_MESSAGE_SET_STATE: {
1644
1645 pa_bool_t suspend_change =
1646 (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
1647 (PA_SINK_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SINK_SUSPENDED);
1648
1649 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1650
1651 if (s->thread_info.state == PA_SINK_SUSPENDED) {
1652 s->thread_info.rewind_nbytes = 0;
1653 s->thread_info.rewind_requested = FALSE;
1654 }
1655
1656 if (suspend_change) {
1657 pa_sink_input *i;
1658 void *state = NULL;
1659
1660 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1661 if (i->suspend_within_thread)
1662 i->suspend_within_thread(i, s->thread_info.state == PA_SINK_SUSPENDED);
1663 }
1664
1665 return 0;
1666 }
1667
1668 case PA_SINK_MESSAGE_DETACH:
1669
1670 /* Detach all streams */
1671 pa_sink_detach_within_thread(s);
1672 return 0;
1673
1674 case PA_SINK_MESSAGE_ATTACH:
1675
1676 /* Reattach all streams */
1677 pa_sink_attach_within_thread(s);
1678 return 0;
1679
1680 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1681
1682 pa_usec_t *usec = userdata;
1683 *usec = pa_sink_get_requested_latency_within_thread(s);
1684
1685 if (*usec == (pa_usec_t) -1)
1686 *usec = s->thread_info.max_latency;
1687
1688 return 0;
1689 }
1690
1691 case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1692 pa_usec_t *r = userdata;
1693
1694 pa_sink_set_latency_range_within_thread(s, r[0], r[1]);
1695
1696 return 0;
1697 }
1698
1699 case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1700 pa_usec_t *r = userdata;
1701
1702 r[0] = s->thread_info.min_latency;
1703 r[1] = s->thread_info.max_latency;
1704
1705 return 0;
1706 }
1707
1708 case PA_SINK_MESSAGE_GET_MAX_REWIND:
1709
1710 *((size_t*) userdata) = s->thread_info.max_rewind;
1711 return 0;
1712
1713 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1714
1715 *((size_t*) userdata) = s->thread_info.max_request;
1716 return 0;
1717
1718 case PA_SINK_MESSAGE_SET_MAX_REWIND:
1719
1720 pa_sink_set_max_rewind_within_thread(s, (size_t) offset);
1721 return 0;
1722
1723 case PA_SINK_MESSAGE_SET_MAX_REQUEST:
1724
1725 pa_sink_set_max_request_within_thread(s, (size_t) offset);
1726 return 0;
1727
1728 case PA_SINK_MESSAGE_GET_LATENCY:
1729 case PA_SINK_MESSAGE_MAX:
1730 ;
1731 }
1732
1733 return -1;
1734 }
1735
1736 /* Called from main thread */
1737 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1738 pa_sink *sink;
1739 uint32_t idx;
1740 int ret = 0;
1741
1742 pa_core_assert_ref(c);
1743
1744 for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
1745 int r;
1746
1747 if ((r = pa_sink_suspend(sink, suspend)) < 0)
1748 ret = r;
1749 }
1750
1751 return ret;
1752 }
1753
1754 /* Called from main thread */
1755 void pa_sink_detach(pa_sink *s) {
1756 pa_sink_assert_ref(s);
1757 pa_assert(PA_SINK_IS_LINKED(s->state));
1758
1759 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1760 }
1761
1762 /* Called from main thread */
1763 void pa_sink_attach(pa_sink *s) {
1764 pa_sink_assert_ref(s);
1765 pa_assert(PA_SINK_IS_LINKED(s->state));
1766
1767 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1768 }
1769
1770 /* Called from IO thread */
1771 void pa_sink_detach_within_thread(pa_sink *s) {
1772 pa_sink_input *i;
1773 void *state = NULL;
1774
1775 pa_sink_assert_ref(s);
1776 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1777
1778 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1779 if (i->detach)
1780 i->detach(i);
1781
1782 if (s->monitor_source)
1783 pa_source_detach_within_thread(s->monitor_source);
1784 }
1785
1786 /* Called from IO thread */
1787 void pa_sink_attach_within_thread(pa_sink *s) {
1788 pa_sink_input *i;
1789 void *state = NULL;
1790
1791 pa_sink_assert_ref(s);
1792 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1793
1794 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1795 if (i->attach)
1796 i->attach(i);
1797
1798 if (s->monitor_source)
1799 pa_source_attach_within_thread(s->monitor_source);
1800 }
1801
1802 /* Called from IO thread */
1803 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1804 pa_sink_assert_ref(s);
1805 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1806
1807 if (s->thread_info.state == PA_SINK_SUSPENDED)
1808 return;
1809
1810 if (nbytes == (size_t) -1)
1811 nbytes = s->thread_info.max_rewind;
1812
1813 nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1814
1815 if (s->thread_info.rewind_requested &&
1816 nbytes <= s->thread_info.rewind_nbytes)
1817 return;
1818
1819 s->thread_info.rewind_nbytes = nbytes;
1820 s->thread_info.rewind_requested = TRUE;
1821
1822 if (s->request_rewind)
1823 s->request_rewind(s);
1824 }
1825
1826 /* Called from IO thread */
1827 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1828 pa_usec_t result = (pa_usec_t) -1;
1829 pa_sink_input *i;
1830 void *state = NULL;
1831 pa_usec_t monitor_latency;
1832
1833 pa_sink_assert_ref(s);
1834
1835 if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
1836 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1837
1838 if (s->thread_info.requested_latency_valid)
1839 return s->thread_info.requested_latency;
1840
1841 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1842
1843 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1844 (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1845 result = i->thread_info.requested_sink_latency;
1846
1847 monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1848
1849 if (monitor_latency != (pa_usec_t) -1 &&
1850 (result == (pa_usec_t) -1 || result > monitor_latency))
1851 result = monitor_latency;
1852
1853 if (result != (pa_usec_t) -1)
1854 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1855
1856 s->thread_info.requested_latency = result;
1857 s->thread_info.requested_latency_valid = TRUE;
1858
1859 return result;
1860 }
1861
1862 /* Called from main thread */
1863 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1864 pa_usec_t usec = 0;
1865
1866 pa_sink_assert_ref(s);
1867 pa_assert(PA_SINK_IS_LINKED(s->state));
1868
1869 if (s->state == PA_SINK_SUSPENDED)
1870 return 0;
1871
1872 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1873 return usec;
1874 }
1875
1876 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1877 void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
1878 pa_sink_input *i;
1879 void *state = NULL;
1880
1881 pa_sink_assert_ref(s);
1882
1883 if (max_rewind == s->thread_info.max_rewind)
1884 return;
1885
1886 s->thread_info.max_rewind = max_rewind;
1887
1888 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1889 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1890 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1891 }
1892
1893 if (s->monitor_source)
1894 pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind);
1895 }
1896
1897 /* Called from main thread */
1898 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1899 pa_sink_assert_ref(s);
1900
1901 if (PA_SINK_IS_LINKED(s->state))
1902 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1903 else
1904 pa_sink_set_max_rewind_within_thread(s, max_rewind);
1905 }
1906
1907 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1908 void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
1909 void *state = NULL;
1910
1911 pa_sink_assert_ref(s);
1912
1913 if (max_request == s->thread_info.max_request)
1914 return;
1915
1916 s->thread_info.max_request = max_request;
1917
1918 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1919 pa_sink_input *i;
1920
1921 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1922 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1923 }
1924 }
1925
1926 /* Called from main thread */
1927 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
1928 pa_sink_assert_ref(s);
1929
1930 if (PA_SINK_IS_LINKED(s->state))
1931 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
1932 else
1933 pa_sink_set_max_request_within_thread(s, max_request);
1934 }
1935
1936 /* Called from IO thread */
1937 void pa_sink_invalidate_requested_latency(pa_sink *s) {
1938 pa_sink_input *i;
1939 void *state = NULL;
1940
1941 pa_sink_assert_ref(s);
1942
1943 if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
1944 return;
1945
1946 s->thread_info.requested_latency_valid = FALSE;
1947
1948 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1949
1950 if (s->update_requested_latency)
1951 s->update_requested_latency(s);
1952
1953 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1954 if (i->update_sink_requested_latency)
1955 i->update_sink_requested_latency(i);
1956 }
1957 }
1958
1959 /* Called from main thread */
1960 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1961 pa_sink_assert_ref(s);
1962
1963 /* min_latency == 0: no limit
1964 * min_latency anything else: specified limit
1965 *
1966 * Similar for max_latency */
1967
1968 if (min_latency < ABSOLUTE_MIN_LATENCY)
1969 min_latency = ABSOLUTE_MIN_LATENCY;
1970
1971 if (max_latency <= 0 ||
1972 max_latency > ABSOLUTE_MAX_LATENCY)
1973 max_latency = ABSOLUTE_MAX_LATENCY;
1974
1975 pa_assert(min_latency <= max_latency);
1976
1977 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
1978 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1979 max_latency == ABSOLUTE_MAX_LATENCY) ||
1980 (s->flags & PA_SINK_DYNAMIC_LATENCY));
1981
1982 if (PA_SINK_IS_LINKED(s->state)) {
1983 pa_usec_t r[2];
1984
1985 r[0] = min_latency;
1986 r[1] = max_latency;
1987
1988 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1989 } else
1990 pa_sink_set_latency_range_within_thread(s, min_latency, max_latency);
1991 }
1992
1993 /* Called from main thread */
1994 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1995 pa_sink_assert_ref(s);
1996 pa_assert(min_latency);
1997 pa_assert(max_latency);
1998
1999 if (PA_SINK_IS_LINKED(s->state)) {
2000 pa_usec_t r[2] = { 0, 0 };
2001
2002 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
2003
2004 *min_latency = r[0];
2005 *max_latency = r[1];
2006 } else {
2007 *min_latency = s->thread_info.min_latency;
2008 *max_latency = s->thread_info.max_latency;
2009 }
2010 }
2011
2012 /* Called from IO thread */
2013 void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
2014 void *state = NULL;
2015
2016 pa_sink_assert_ref(s);
2017
2018 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
2019 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
2020 pa_assert(min_latency <= max_latency);
2021
2022 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
2023 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
2024 max_latency == ABSOLUTE_MAX_LATENCY) ||
2025 (s->flags & PA_SINK_DYNAMIC_LATENCY));
2026
2027 s->thread_info.min_latency = min_latency;
2028 s->thread_info.max_latency = max_latency;
2029
2030 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
2031 pa_sink_input *i;
2032
2033 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
2034 if (i->update_sink_latency_range)
2035 i->update_sink_latency_range(i);
2036 }
2037
2038 pa_sink_invalidate_requested_latency(s);
2039
2040 pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency);
2041 }
2042
2043 /* Called from main context */
2044 size_t pa_sink_get_max_rewind(pa_sink *s) {
2045 size_t r;
2046 pa_sink_assert_ref(s);
2047
2048 if (!PA_SINK_IS_LINKED(s->state))
2049 return s->thread_info.max_rewind;
2050
2051 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
2052
2053 return r;
2054 }
2055
2056 /* Called from main context */
2057 size_t pa_sink_get_max_request(pa_sink *s) {
2058 size_t r;
2059 pa_sink_assert_ref(s);
2060
2061 if (!PA_SINK_IS_LINKED(s->state))
2062 return s->thread_info.max_request;
2063
2064 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
2065
2066 return r;
2067 }
2068
2069 /* Called from main context */
2070 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
2071 const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
2072
2073 pa_assert(p);
2074
2075 if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
2076 return TRUE;
2077
2078 if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
2079
2080 if (pa_streq(ff, "microphone"))
2081 t = "audio-input-microphone";
2082 else if (pa_streq(ff, "webcam"))
2083 t = "camera-web";
2084 else if (pa_streq(ff, "computer"))
2085 t = "computer";
2086 else if (pa_streq(ff, "handset"))
2087 t = "phone";
2088 else if (pa_streq(ff, "portable"))
2089 t = "multimedia-player";
2090 else if (pa_streq(ff, "tv"))
2091 t = "video-display";
2092 }
2093
2094 if (!t)
2095 if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
2096 if (pa_streq(c, "modem"))
2097 t = "modem";
2098
2099 if (!t) {
2100 if (is_sink)
2101 t = "audio-card";
2102 else
2103 t = "audio-input-microphone";
2104 }
2105
2106 if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
2107 if (strstr(profile, "analog"))
2108 s = "-analog";
2109 else if (strstr(profile, "iec958"))
2110 s = "-iec958";
2111 else if (strstr(profile, "hdmi"))
2112 s = "-hdmi";
2113 }
2114
2115 bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
2116
2117 pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
2118
2119 return TRUE;
2120 }
2121
2122 pa_bool_t pa_device_init_description(pa_proplist *p) {
2123 const char *s;
2124 pa_assert(p);
2125
2126 if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
2127 return TRUE;
2128
2129 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
2130 if (pa_streq(s, "internal")) {
2131 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
2132 return TRUE;
2133 }
2134
2135 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
2136 if (pa_streq(s, "modem")) {
2137 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
2138 return TRUE;
2139 }
2140
2141 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
2142 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
2143 return TRUE;
2144 }
2145
2146 return FALSE;
2147 }