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