]> code.delx.au - pulseaudio/blob - src/pulsecore/sink-input.c
Add volume ramping feature - sink-input modification
[pulseaudio] / src / pulsecore / sink-input.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/util.h>
34
35 #include <pulsecore/sample-util.h>
36 #include <pulsecore/core-subscribe.h>
37 #include <pulsecore/log.h>
38 #include <pulsecore/play-memblockq.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/core-util.h>
41 #include <pulse/timeval.h>
42
43 #include "sink-input.h"
44
45 #define MEMBLOCKQ_MAXLENGTH (32*1024*1024)
46 #define CONVERT_BUFFER_LENGTH (PA_PAGE_SIZE)
47
48 static PA_DEFINE_CHECK_TYPE(pa_sink_input, pa_msgobject);
49
50 static void sink_input_free(pa_object *o);
51 static void sink_input_set_ramping_info(pa_sink_input* i, pa_volume_t pre_virtual_volume, pa_volume_t target_virtual_volume, pa_usec_t t);
52 static void sink_input_set_ramping_info_for_mute(pa_sink_input* i, pa_bool_t mute, pa_usec_t t);
53 static void sink_input_volume_ramping(pa_sink_input* i, pa_memchunk* chunk);
54 static void sink_input_rewind_ramp_info(pa_sink_input *i, size_t nbytes);
55 static void sink_input_release_envelope(pa_sink_input *i);
56
57 pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {
58 pa_assert(data);
59
60 memset(data, 0, sizeof(*data));
61 data->resample_method = PA_RESAMPLER_INVALID;
62 data->proplist = pa_proplist_new();
63
64 return data;
65 }
66
67 void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec) {
68 pa_assert(data);
69
70 if ((data->sample_spec_is_set = !!spec))
71 data->sample_spec = *spec;
72 }
73
74 void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map) {
75 pa_assert(data);
76
77 if ((data->channel_map_is_set = !!map))
78 data->channel_map = *map;
79 }
80
81 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
82 pa_assert(data);
83
84 if ((data->volume_is_set = !!volume))
85 data->volume = *volume;
86 }
87
88 void pa_sink_input_new_data_apply_volume_factor(pa_sink_input_new_data *data, const pa_cvolume *volume_factor) {
89 pa_assert(data);
90 pa_assert(volume_factor);
91
92 if (data->volume_factor_is_set)
93 pa_sw_cvolume_multiply(&data->volume_factor, &data->volume_factor, volume_factor);
94 else {
95 data->volume_factor_is_set = TRUE;
96 data->volume_factor = *volume_factor;
97 }
98 }
99
100 void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) {
101 pa_assert(data);
102
103 data->muted_is_set = TRUE;
104 data->muted = !!mute;
105 }
106
107 void pa_sink_input_new_data_done(pa_sink_input_new_data *data) {
108 pa_assert(data);
109
110 pa_proplist_free(data->proplist);
111 }
112
113 /* Called from main context */
114 static void reset_callbacks(pa_sink_input *i) {
115 pa_assert(i);
116
117 i->pop = NULL;
118 i->process_rewind = NULL;
119 i->update_max_rewind = NULL;
120 i->update_max_request = NULL;
121 i->update_sink_requested_latency = NULL;
122 i->update_sink_latency_range = NULL;
123 i->attach = NULL;
124 i->detach = NULL;
125 i->suspend = NULL;
126 i->suspend_within_thread = NULL;
127 i->moving = NULL;
128 i->kill = NULL;
129 i->get_latency = NULL;
130 i->state_change = NULL;
131 i->may_move_to = NULL;
132 i->send_event = NULL;
133 }
134
135 /* Called from main context */
136 int pa_sink_input_new(
137 pa_sink_input **_i,
138 pa_core *core,
139 pa_sink_input_new_data *data,
140 pa_sink_input_flags_t flags) {
141
142 pa_sink_input *i;
143 pa_resampler *resampler = NULL;
144 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
145 pa_channel_map original_cm;
146 int r;
147
148 pa_assert(_i);
149 pa_assert(core);
150 pa_assert(data);
151
152 if (data->client)
153 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
154
155 if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0)
156 return r;
157
158 pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
159
160 if (!data->sink) {
161 data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK);
162 data->save_sink = FALSE;
163 }
164
165 pa_return_val_if_fail(data->sink, -PA_ERR_NOENTITY);
166 pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE);
167 pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED), -PA_ERR_INVALID);
168
169 if (!data->sample_spec_is_set)
170 data->sample_spec = data->sink->sample_spec;
171
172 pa_return_val_if_fail(pa_sample_spec_valid(&data->sample_spec), -PA_ERR_INVALID);
173
174 if (!data->channel_map_is_set) {
175 if (pa_channel_map_compatible(&data->sink->channel_map, &data->sample_spec))
176 data->channel_map = data->sink->channel_map;
177 else
178 pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
179 }
180
181 pa_return_val_if_fail(pa_channel_map_valid(&data->channel_map), -PA_ERR_INVALID);
182 pa_return_val_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec), -PA_ERR_INVALID);
183
184 if (!data->volume_is_set) {
185 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
186 data->volume_is_absolute = FALSE;
187 data->save_volume = FALSE;
188 }
189
190 pa_return_val_if_fail(pa_cvolume_valid(&data->volume), -PA_ERR_INVALID);
191 pa_return_val_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec), -PA_ERR_INVALID);
192
193 if (!data->volume_factor_is_set)
194 pa_cvolume_reset(&data->volume_factor, data->sample_spec.channels);
195
196 pa_return_val_if_fail(pa_cvolume_valid(&data->volume_factor), -PA_ERR_INVALID);
197 pa_return_val_if_fail(pa_cvolume_compatible(&data->volume_factor, &data->sample_spec), -PA_ERR_INVALID);
198
199 if (!data->muted_is_set)
200 data->muted = FALSE;
201
202 if (flags & PA_SINK_INPUT_FIX_FORMAT)
203 data->sample_spec.format = data->sink->sample_spec.format;
204
205 if (flags & PA_SINK_INPUT_FIX_RATE)
206 data->sample_spec.rate = data->sink->sample_spec.rate;
207
208 original_cm = data->channel_map;
209
210 if (flags & PA_SINK_INPUT_FIX_CHANNELS) {
211 data->sample_spec.channels = data->sink->sample_spec.channels;
212 data->channel_map = data->sink->channel_map;
213 }
214
215 pa_assert(pa_sample_spec_valid(&data->sample_spec));
216 pa_assert(pa_channel_map_valid(&data->channel_map));
217
218 /* Due to the fixing of the sample spec the volume might not match anymore */
219 pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map);
220
221 if (data->resample_method == PA_RESAMPLER_INVALID)
222 data->resample_method = core->resample_method;
223
224 pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID);
225
226 if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
227 return r;
228
229 if ((flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) &&
230 pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
231 pa_log_warn("Failed to create sink input: sink is suspended.");
232 return -PA_ERR_BADSTATE;
233 }
234
235 if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
236 pa_log_warn("Failed to create sink input: too many inputs per sink.");
237 return -PA_ERR_TOOLARGE;
238 }
239
240 if ((flags & PA_SINK_INPUT_VARIABLE_RATE) ||
241 !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) ||
242 !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) {
243
244 if (!(resampler = pa_resampler_new(
245 core->mempool,
246 &data->sample_spec, &data->channel_map,
247 &data->sink->sample_spec, &data->sink->channel_map,
248 data->resample_method,
249 ((flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
250 ((flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
251 (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
252 (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
253 pa_log_warn("Unsupported resampling operation.");
254 return -PA_ERR_NOTSUPPORTED;
255 }
256 }
257
258 i = pa_msgobject_new(pa_sink_input);
259 i->parent.parent.free = sink_input_free;
260 i->parent.process_msg = pa_sink_input_process_msg;
261
262 i->core = core;
263 i->state = PA_SINK_INPUT_INIT;
264 i->flags = flags;
265 i->proplist = pa_proplist_copy(data->proplist);
266 i->driver = pa_xstrdup(pa_path_get_filename(data->driver));
267 i->module = data->module;
268 i->sink = data->sink;
269 i->client = data->client;
270
271 i->requested_resample_method = data->resample_method;
272 i->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
273 i->sample_spec = data->sample_spec;
274 i->channel_map = data->channel_map;
275
276 if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !data->volume_is_absolute) {
277 /* When the 'absolute' bool is not set then we'll treat the volume
278 * as relative to the sink volume even in flat volume mode */
279
280 pa_cvolume v = data->sink->reference_volume;
281 pa_cvolume_remap(&v, &data->sink->channel_map, &data->channel_map);
282 pa_sw_cvolume_multiply(&i->virtual_volume, &data->volume, &v);
283 } else
284 i->virtual_volume = data->volume;
285
286 i->volume_factor = data->volume_factor;
287 pa_cvolume_init(&i->soft_volume);
288 memset(i->relative_volume, 0, sizeof(i->relative_volume));
289 i->save_volume = data->save_volume;
290 i->save_sink = data->save_sink;
291 i->save_muted = data->save_muted;
292
293 i->muted = data->muted;
294
295 if (data->sync_base) {
296 i->sync_next = data->sync_base->sync_next;
297 i->sync_prev = data->sync_base;
298
299 if (data->sync_base->sync_next)
300 data->sync_base->sync_next->sync_prev = i;
301 data->sync_base->sync_next = i;
302 } else
303 i->sync_next = i->sync_prev = NULL;
304
305 i->direct_outputs = pa_idxset_new(NULL, NULL);
306
307 reset_callbacks(i);
308 i->userdata = NULL;
309
310 /* Set Ramping info */
311 i->thread_info.ramp_info.is_ramping = FALSE;
312 i->thread_info.ramp_info.envelope_dead = TRUE;
313 i->thread_info.ramp_info.envelope = NULL;
314 i->thread_info.ramp_info.item = NULL;
315 i->thread_info.ramp_info.envelope_dying = 0;
316
317 pa_atomic_store(&i->before_ramping_v, 0);
318 pa_atomic_store(&i->before_ramping_m, 0);
319
320 i->thread_info.state = i->state;
321 i->thread_info.attached = FALSE;
322 pa_atomic_store(&i->thread_info.drained, 1);
323 i->thread_info.sample_spec = i->sample_spec;
324 i->thread_info.resampler = resampler;
325 i->thread_info.soft_volume = i->soft_volume;
326 i->thread_info.muted = i->muted;
327 i->thread_info.requested_sink_latency = (pa_usec_t) -1;
328 i->thread_info.rewrite_nbytes = 0;
329 i->thread_info.rewrite_flush = FALSE;
330 i->thread_info.dont_rewind_render = FALSE;
331 i->thread_info.underrun_for = (uint64_t) -1;
332 i->thread_info.playing_for = 0;
333 i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
334
335 i->thread_info.render_memblockq = pa_memblockq_new(
336 0,
337 MEMBLOCKQ_MAXLENGTH,
338 0,
339 pa_frame_size(&i->sink->sample_spec),
340 0,
341 1,
342 0,
343 &i->sink->silence);
344
345 pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
346 pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0);
347
348 if (i->client)
349 pa_assert_se(pa_idxset_put(i->client->sink_inputs, i, NULL) >= 0);
350
351 pa_log_info("Created input %u \"%s\" on %s with sample spec %s and channel map %s",
352 i->index,
353 pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)),
354 i->sink->name,
355 pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec),
356 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map));
357
358 /* Don't forget to call pa_sink_input_put! */
359
360 *_i = i;
361 return 0;
362 }
363
364 /* Called from main context */
365 static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
366 pa_assert(i);
367
368 if (!i->sink)
369 return;
370
371 if (i->state == PA_SINK_INPUT_CORKED && state != PA_SINK_INPUT_CORKED)
372 pa_assert_se(i->sink->n_corked -- >= 1);
373 else if (i->state != PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_CORKED)
374 i->sink->n_corked++;
375 }
376
377 /* Called from main context */
378 static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
379 pa_sink_input *ssync;
380 pa_assert(i);
381
382 if (state == PA_SINK_INPUT_DRAINED)
383 state = PA_SINK_INPUT_RUNNING;
384
385 if (i->state == state)
386 return;
387
388 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
389
390 update_n_corked(i, state);
391 i->state = state;
392
393 for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev) {
394 update_n_corked(ssync, state);
395 ssync->state = state;
396 }
397 for (ssync = i->sync_next; ssync; ssync = ssync->sync_next) {
398 update_n_corked(ssync, state);
399 ssync->state = state;
400 }
401
402 if (state != PA_SINK_INPUT_UNLINKED) {
403 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], i);
404
405 for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev)
406 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync);
407
408 for (ssync = i->sync_next; ssync; ssync = ssync->sync_next)
409 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync);
410 }
411
412 pa_sink_update_status(i->sink);
413 }
414
415 /* Called from main context */
416 void pa_sink_input_unlink(pa_sink_input *i) {
417 pa_bool_t linked;
418 pa_source_output *o, *p = NULL;
419 pa_assert(i);
420
421 /* See pa_sink_unlink() for a couple of comments how this function
422 * works */
423
424 pa_sink_input_ref(i);
425
426 linked = PA_SINK_INPUT_IS_LINKED(i->state);
427
428 if (linked)
429 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i);
430
431 if (i->sync_prev)
432 i->sync_prev->sync_next = i->sync_next;
433 if (i->sync_next)
434 i->sync_next->sync_prev = i->sync_prev;
435
436 i->sync_prev = i->sync_next = NULL;
437
438 pa_idxset_remove_by_data(i->core->sink_inputs, i, NULL);
439
440 if (i->sink)
441 if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL))
442 pa_sink_input_unref(i);
443
444 if (i->client)
445 pa_idxset_remove_by_data(i->client->sink_inputs, i, NULL);
446
447 while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
448 pa_assert(o != p);
449 pa_source_output_kill(o);
450 p = o;
451 }
452
453 update_n_corked(i, PA_SINK_INPUT_UNLINKED);
454 i->state = PA_SINK_INPUT_UNLINKED;
455
456 if (linked && i->sink) {
457 /* We might need to update the sink's volume if we are in flat volume mode. */
458 if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
459 pa_cvolume new_volume;
460 pa_sink_update_flat_volume(i->sink, &new_volume);
461 pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
462 }
463
464 if (i->sink->asyncmsgq)
465 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL) == 0);
466 }
467
468 reset_callbacks(i);
469
470 if (linked) {
471 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
472 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i);
473 }
474
475 if (i->sink) {
476 pa_sink_update_status(i->sink);
477 i->sink = NULL;
478 }
479
480 pa_core_maybe_vacuum(i->core);
481
482 pa_sink_input_unref(i);
483 }
484
485 /* Called from main context */
486 static void sink_input_free(pa_object *o) {
487 pa_sink_input* i = PA_SINK_INPUT(o);
488
489 pa_assert(i);
490 pa_assert(pa_sink_input_refcnt(i) == 0);
491
492 if (PA_SINK_INPUT_IS_LINKED(i->state))
493 pa_sink_input_unlink(i);
494
495 pa_log_info("Freeing input %u \"%s\"", i->index, pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)));
496
497 pa_assert(!i->thread_info.attached);
498
499 if (i->thread_info.ramp_info.envelope) {
500 pa_log_debug ("Freeing envelope\n");
501 pa_envelope_free(i->thread_info.ramp_info.envelope);
502 i->thread_info.ramp_info.envelope = NULL;
503 }
504
505 if (i->thread_info.render_memblockq)
506 pa_memblockq_free(i->thread_info.render_memblockq);
507
508 if (i->thread_info.resampler)
509 pa_resampler_free(i->thread_info.resampler);
510
511 if (i->proplist)
512 pa_proplist_free(i->proplist);
513
514 if (i->direct_outputs)
515 pa_idxset_free(i->direct_outputs, NULL, NULL);
516
517 if (i->thread_info.direct_outputs)
518 pa_hashmap_free(i->thread_info.direct_outputs, NULL, NULL);
519
520 pa_xfree(i->driver);
521 pa_xfree(i);
522 }
523
524 /* Called from main context */
525 void pa_sink_input_put(pa_sink_input *i) {
526 pa_sink_input_state_t state;
527 pa_sink_input_assert_ref(i);
528
529 pa_assert(i->state == PA_SINK_INPUT_INIT);
530
531 /* The following fields must be initialized properly */
532 pa_assert(i->pop);
533 pa_assert(i->process_rewind);
534 pa_assert(i->kill);
535
536 state = i->flags & PA_SINK_INPUT_START_CORKED ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING;
537
538 update_n_corked(i, state);
539 i->state = state;
540
541 /* We might need to update the sink's volume if we are in flat volume mode. */
542 if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
543 pa_cvolume new_volume;
544 pa_sink_update_flat_volume(i->sink, &new_volume);
545 pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
546 } else
547 pa_sink_input_set_relative_volume(i, &i->virtual_volume);
548
549 i->thread_info.soft_volume = i->soft_volume;
550 i->thread_info.muted = i->muted;
551
552 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL) == 0);
553
554 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
555 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], i);
556
557 pa_sink_update_status(i->sink);
558 }
559
560 /* Called from main context */
561 void pa_sink_input_kill(pa_sink_input*i) {
562 pa_sink_input_assert_ref(i);
563 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
564
565 i->kill(i);
566 }
567
568 /* Called from main context */
569 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) {
570 pa_usec_t r[2] = { 0, 0 };
571
572 pa_sink_input_assert_ref(i);
573 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
574
575 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
576
577 if (i->get_latency)
578 r[0] += i->get_latency(i);
579
580 if (sink_latency)
581 *sink_latency = r[1];
582
583 return r[0];
584 }
585
586 /* Called from thread context */
587 void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, pa_memchunk *chunk, pa_cvolume *volume) {
588 pa_bool_t do_volume_adj_here;
589 pa_bool_t volume_is_norm;
590 pa_bool_t ramping;
591 size_t block_size_max_sink, block_size_max_sink_input;
592 size_t ilength;
593
594 pa_sink_input_assert_ref(i);
595 pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
596 pa_assert(pa_frame_aligned(slength, &i->sink->sample_spec));
597 pa_assert(chunk);
598 pa_assert(volume);
599
600 /* pa_log_debug("peek"); */
601
602 pa_assert(i->thread_info.state == PA_SINK_INPUT_RUNNING ||
603 i->thread_info.state == PA_SINK_INPUT_CORKED ||
604 i->thread_info.state == PA_SINK_INPUT_DRAINED);
605
606 block_size_max_sink_input = i->thread_info.resampler ?
607 pa_resampler_max_block_size(i->thread_info.resampler) :
608 pa_frame_align(pa_mempool_block_size_max(i->core->mempool), &i->sample_spec);
609
610 block_size_max_sink = pa_frame_align(pa_mempool_block_size_max(i->core->mempool), &i->sink->sample_spec);
611
612 /* Default buffer size */
613 if (slength <= 0)
614 slength = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sink->sample_spec);
615
616 if (slength > block_size_max_sink)
617 slength = block_size_max_sink;
618
619 if (i->thread_info.resampler) {
620 ilength = pa_resampler_request(i->thread_info.resampler, slength);
621
622 if (ilength <= 0)
623 ilength = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sample_spec);
624 } else
625 ilength = slength;
626
627 if (ilength > block_size_max_sink_input)
628 ilength = block_size_max_sink_input;
629
630 /* If the channel maps of the sink and this stream differ, we need
631 * to adjust the volume *before* we resample. Otherwise we can do
632 * it after and leave it for the sink code */
633
634 do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map) || i->thread_info.ramp_info.is_ramping;
635 volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.muted;
636
637 while (!pa_memblockq_is_readable(i->thread_info.render_memblockq)) {
638 pa_memchunk tchunk;
639
640 /* There's nothing in our render queue. We need to fill it up
641 * with data from the implementor. */
642
643 if (i->thread_info.state == PA_SINK_INPUT_CORKED ||
644 i->pop(i, ilength, &tchunk) < 0) {
645
646 /* OK, we're corked or the implementor didn't give us any
647 * data, so let's just hand out silence */
648 pa_atomic_store(&i->thread_info.drained, 1);
649
650 pa_memblockq_seek(i->thread_info.render_memblockq, (int64_t) slength, PA_SEEK_RELATIVE, TRUE);
651 i->thread_info.playing_for = 0;
652 if (i->thread_info.underrun_for != (uint64_t) -1)
653 i->thread_info.underrun_for += ilength;
654 break;
655 }
656
657 pa_atomic_store(&i->thread_info.drained, 0);
658
659 pa_assert(tchunk.length > 0);
660 pa_assert(tchunk.memblock);
661
662 i->thread_info.underrun_for = 0;
663 i->thread_info.playing_for += tchunk.length;
664
665 while (tchunk.length > 0) {
666 pa_memchunk wchunk;
667
668 wchunk = tchunk;
669 pa_memblock_ref(wchunk.memblock);
670
671 if (wchunk.length > block_size_max_sink_input)
672 wchunk.length = block_size_max_sink_input;
673
674 /* It might be necessary to adjust the volume here */
675 if (do_volume_adj_here && !volume_is_norm && !i->thread_info.ramp_info.is_ramping) {
676 pa_memchunk_make_writable(&wchunk, 0);
677
678 if (i->thread_info.muted)
679 pa_silence_memchunk(&wchunk, &i->thread_info.sample_spec);
680 else
681 pa_volume_memchunk(&wchunk, &i->thread_info.sample_spec, &i->thread_info.soft_volume);
682 }
683
684 if (!i->thread_info.resampler)
685 pa_memblockq_push_align(i->thread_info.render_memblockq, &wchunk);
686 else {
687 pa_memchunk rchunk;
688 pa_resampler_run(i->thread_info.resampler, &wchunk, &rchunk);
689
690 /* pa_log_debug("pushing %lu", (unsigned long) rchunk.length); */
691
692 if (rchunk.memblock) {
693 pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk);
694 pa_memblock_unref(rchunk.memblock);
695 }
696 }
697
698 pa_memblock_unref(wchunk.memblock);
699
700 tchunk.index += wchunk.length;
701 tchunk.length -= wchunk.length;
702 }
703
704 pa_memblock_unref(tchunk.memblock);
705 }
706
707 pa_assert_se(pa_memblockq_peek(i->thread_info.render_memblockq, chunk) >= 0);
708
709 pa_assert(chunk->length > 0);
710 pa_assert(chunk->memblock);
711
712 /* pa_log_debug("peeking %lu", (unsigned long) chunk->length); */
713
714 if (chunk->length > block_size_max_sink)
715 chunk->length = block_size_max_sink;
716
717 ramping = i->thread_info.ramp_info.is_ramping;
718 if (ramping)
719 sink_input_volume_ramping(i, chunk);
720
721 if (!i->thread_info.ramp_info.envelope_dead) {
722 i->thread_info.ramp_info.envelope_dying += chunk->length;
723 pa_log_debug("Envelope dying is %d, chunk length is %d, dead thresholder is %d\n", i->thread_info.ramp_info.envelope_dying,
724 chunk->length,
725 i->sink->thread_info.max_rewind + pa_envelope_length(i->thread_info.ramp_info.envelope));
726
727 if (i->thread_info.ramp_info.envelope_dying >= (i->sink->thread_info.max_rewind + pa_envelope_length(i->thread_info.ramp_info.envelope))) {
728 pa_log_debug("RELEASE Envelop");
729 i->thread_info.ramp_info.envelope_dead = TRUE;
730 sink_input_release_envelope(i);
731 }
732 }
733
734 /* Let's see if we had to apply the volume adjustment ourselves,
735 * or if this can be done by the sink for us */
736
737 if (do_volume_adj_here)
738 /* We had different channel maps, so we already did the adjustment */
739 pa_cvolume_reset(volume, i->sink->sample_spec.channels);
740 else if (i->thread_info.muted)
741 /* We've both the same channel map, so let's have the sink do the adjustment for us*/
742 pa_cvolume_mute(volume, i->sink->sample_spec.channels);
743 else
744 *volume = i->thread_info.soft_volume;
745 }
746
747 /* Called from thread context */
748 void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
749 pa_sink_input_assert_ref(i);
750
751 pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
752 pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
753 pa_assert(nbytes > 0);
754
755 /* pa_log_debug("dropping %lu", (unsigned long) nbytes); */
756
757 pa_memblockq_drop(i->thread_info.render_memblockq, nbytes);
758 }
759
760 /* Called from thread context */
761 void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
762 size_t lbq;
763 pa_bool_t called = FALSE;
764 pa_sink_input_assert_ref(i);
765
766 pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
767 pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
768
769 /* pa_log_debug("rewind(%lu, %lu)", (unsigned long) nbytes, (unsigned long) i->thread_info.rewrite_nbytes); */
770
771 lbq = pa_memblockq_get_length(i->thread_info.render_memblockq);
772
773 if (nbytes > 0 && !i->thread_info.dont_rewind_render) {
774 pa_log_debug("Have to rewind %lu bytes on render memblockq.", (unsigned long) nbytes);
775 pa_memblockq_rewind(i->thread_info.render_memblockq, nbytes);
776 sink_input_rewind_ramp_info(i, nbytes);
777 }
778
779 if (i->thread_info.rewrite_nbytes == (size_t) -1) {
780
781 /* We were asked to drop all buffered data, and rerequest new
782 * data from implementor the next time push() is called */
783
784 pa_memblockq_flush_write(i->thread_info.render_memblockq);
785
786 } else if (i->thread_info.rewrite_nbytes > 0) {
787 size_t max_rewrite, amount;
788
789 /* Calculate how much make sense to rewrite at most */
790 max_rewrite = nbytes + lbq;
791
792 /* Transform into local domain */
793 if (i->thread_info.resampler)
794 max_rewrite = pa_resampler_request(i->thread_info.resampler, max_rewrite);
795
796 /* Calculate how much of the rewinded data should actually be rewritten */
797 amount = PA_MIN(i->thread_info.rewrite_nbytes, max_rewrite);
798
799 if (amount > 0) {
800 pa_log_debug("Have to rewind %lu bytes on implementor.", (unsigned long) amount);
801
802 /* Tell the implementor */
803 if (i->process_rewind)
804 i->process_rewind(i, amount);
805 called = TRUE;
806
807 /* Convert back to to sink domain */
808 if (i->thread_info.resampler)
809 amount = pa_resampler_result(i->thread_info.resampler, amount);
810
811 if (amount > 0)
812 /* Ok, now update the write pointer */
813 pa_memblockq_seek(i->thread_info.render_memblockq, - ((int64_t) amount), PA_SEEK_RELATIVE, TRUE);
814
815 if (i->thread_info.rewrite_flush)
816 pa_memblockq_silence(i->thread_info.render_memblockq);
817
818 /* And reset the resampler */
819 if (i->thread_info.resampler)
820 pa_resampler_reset(i->thread_info.resampler);
821 }
822 }
823
824 if (!called)
825 if (i->process_rewind)
826 i->process_rewind(i, 0);
827
828 i->thread_info.rewrite_nbytes = 0;
829 i->thread_info.rewrite_flush = FALSE;
830 i->thread_info.dont_rewind_render = FALSE;
831 }
832
833 /* Called from thread context */
834 void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) {
835 pa_sink_input_assert_ref(i);
836 pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
837 pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
838
839 pa_memblockq_set_maxrewind(i->thread_info.render_memblockq, nbytes);
840
841 if (i->update_max_rewind)
842 i->update_max_rewind(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes);
843 }
844
845 /* Called from thread context */
846 void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes /* in the sink's sample spec */) {
847 pa_sink_input_assert_ref(i);
848 pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
849 pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
850
851 if (i->update_max_request)
852 i->update_max_request(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes);
853 }
854
855 /* Called from thread context */
856 pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) {
857 pa_sink_input_assert_ref(i);
858
859 if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
860 usec = i->sink->fixed_latency;
861
862 if (usec != (pa_usec_t) -1)
863 usec = PA_CLAMP(usec, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
864
865 i->thread_info.requested_sink_latency = usec;
866 pa_sink_invalidate_requested_latency(i->sink);
867
868 return usec;
869 }
870
871 /* Called from main context */
872 pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
873 pa_sink_input_assert_ref(i);
874
875 if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
876 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
877 return usec;
878 }
879
880 /* If this sink input is not realized yet or we are being moved,
881 * we have to touch the thread info data directly */
882
883 if (i->sink) {
884 if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
885 usec = i->sink->fixed_latency;
886
887 if (usec != (pa_usec_t) -1) {
888 pa_usec_t min_latency, max_latency;
889 pa_sink_get_latency_range(i->sink, &min_latency, &max_latency);
890 usec = PA_CLAMP(usec, min_latency, max_latency);
891 }
892 }
893
894 i->thread_info.requested_sink_latency = usec;
895
896 return usec;
897 }
898
899 /* Called from main context */
900 pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
901 pa_sink_input_assert_ref(i);
902
903 if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
904 pa_usec_t usec = 0;
905 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
906 return usec;
907 }
908
909 /* If this sink input is not realized yet or we are being moved,
910 * we have to touch the thread info data directly */
911
912 return i->thread_info.requested_sink_latency;
913 }
914
915 /* Called from main context */
916 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute) {
917 /* test ramping -> return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 2000 * PA_USEC_PER_MSEC); */
918 return pa_sink_input_set_volume_with_ramping(i, volume, save, absolute, 0);
919 }
920
921 /* Called from main context */
922 pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) {
923 pa_sink_input_assert_ref(i);
924 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
925
926 if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
927 pa_cvolume v = i->sink->reference_volume;
928 pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
929 pa_sw_cvolume_divide(volume, &i->virtual_volume, &v);
930 } else
931 *volume = i->virtual_volume;
932
933 return volume;
934 }
935
936 /* Called from main context */
937 pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) {
938 unsigned c;
939
940 pa_sink_input_assert_ref(i);
941 pa_assert(v);
942 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
943
944 /* This always returns the relative volume. Converts the float
945 * version into a pa_cvolume */
946
947 v->channels = i->sample_spec.channels;
948
949 for (c = 0; c < v->channels; c++)
950 v->values[c] = pa_sw_volume_from_linear(i->relative_volume[c]);
951
952 return v;
953 }
954
955 /* Called from main context */
956 void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) {
957 unsigned c;
958 pa_cvolume _v;
959
960 pa_sink_input_assert_ref(i);
961 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
962 pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec));
963
964 if (!v)
965 v = pa_cvolume_reset(&_v, i->sample_spec.channels);
966
967 /* This basically calculates:
968 *
969 * i->relative_volume := v
970 * i->soft_volume := i->relative_volume * i->volume_factor */
971
972 i->soft_volume.channels = i->sample_spec.channels;
973
974 for (c = 0; c < i->sample_spec.channels; c++) {
975 i->relative_volume[c] = pa_sw_volume_to_linear(v->values[c]);
976
977 i->soft_volume.values[c] = pa_sw_volume_from_linear(
978 i->relative_volume[c] *
979 pa_sw_volume_to_linear(i->volume_factor.values[c]));
980 }
981
982 /* We don't copy the data to the thread_info data. That's left for someone else to do */
983 }
984
985 /* Called from main context */
986 void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
987 /* test ramping -> return pa_sink_input_set_mute_with_ramping(i, mute, save, 2000 * PA_USEC_PER_MSEC); */
988 return pa_sink_input_set_mute_with_ramping(i, mute, save, 0);
989 }
990
991 /* Called from main context */
992 pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) {
993 pa_sink_input_assert_ref(i);
994 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
995
996 return i->muted;
997 }
998
999 /* Called from main thread */
1000 void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
1001 pa_sink_input_assert_ref(i);
1002
1003 if (p)
1004 pa_proplist_update(i->proplist, mode, p);
1005
1006 if (PA_SINK_IS_LINKED(i->state)) {
1007 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
1008 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1009 }
1010 }
1011
1012 /* Called from main context */
1013 void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
1014 pa_sink_input_assert_ref(i);
1015 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1016
1017 sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
1018 }
1019
1020 /* Called from main context */
1021 int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
1022 pa_sink_input_assert_ref(i);
1023 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1024 pa_return_val_if_fail(i->thread_info.resampler, -PA_ERR_BADSTATE);
1025
1026 if (i->sample_spec.rate == rate)
1027 return 0;
1028
1029 i->sample_spec.rate = rate;
1030
1031 pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL);
1032
1033 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1034 return 0;
1035 }
1036
1037 /* Called from main context */
1038 void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
1039 const char *old;
1040 pa_sink_input_assert_ref(i);
1041
1042 if (!name && !pa_proplist_contains(i->proplist, PA_PROP_MEDIA_NAME))
1043 return;
1044
1045 old = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME);
1046
1047 if (old && name && !strcmp(old, name))
1048 return;
1049
1050 if (name)
1051 pa_proplist_sets(i->proplist, PA_PROP_MEDIA_NAME, name);
1052 else
1053 pa_proplist_unset(i->proplist, PA_PROP_MEDIA_NAME);
1054
1055 if (PA_SINK_INPUT_IS_LINKED(i->state)) {
1056 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
1057 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1058 }
1059 }
1060
1061 /* Called from main context */
1062 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
1063 pa_sink_input_assert_ref(i);
1064
1065 return i->actual_resample_method;
1066 }
1067
1068 /* Called from main context */
1069 pa_bool_t pa_sink_input_may_move(pa_sink_input *i) {
1070 pa_sink_input_assert_ref(i);
1071 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1072
1073 if (i->flags & PA_SINK_INPUT_DONT_MOVE)
1074 return FALSE;
1075
1076 if (i->sync_next || i->sync_prev) {
1077 pa_log_warn("Moving synchronised streams not supported.");
1078 return FALSE;
1079 }
1080
1081 return TRUE;
1082 }
1083
1084 /* Called from main context */
1085 pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
1086 pa_sink_input_assert_ref(i);
1087 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1088 pa_sink_assert_ref(dest);
1089
1090 if (dest == i->sink)
1091 return TRUE;
1092
1093 if (!pa_sink_input_may_move(i))
1094 return FALSE;
1095
1096 if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) {
1097 pa_log_warn("Failed to move sink input: too many inputs per sink.");
1098 return FALSE;
1099 }
1100
1101 if (i->may_move_to)
1102 if (!i->may_move_to(i, dest))
1103 return FALSE;
1104
1105 return TRUE;
1106 }
1107
1108 /* Called from main context */
1109 int pa_sink_input_start_move(pa_sink_input *i) {
1110 pa_source_output *o, *p = NULL;
1111 pa_sink *origin;
1112 int r;
1113
1114 pa_sink_input_assert_ref(i);
1115 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1116 pa_assert(i->sink);
1117
1118 if (!pa_sink_input_may_move(i))
1119 return -PA_ERR_NOTSUPPORTED;
1120
1121 if ((r = pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], i)) < 0)
1122 return r;
1123
1124 origin = i->sink;
1125
1126 /* Kill directly connected outputs */
1127 while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
1128 pa_assert(o != p);
1129 pa_source_output_kill(o);
1130 p = o;
1131 }
1132 pa_assert(pa_idxset_isempty(i->direct_outputs));
1133
1134 pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
1135
1136 if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
1137 pa_assert_se(i->sink->n_corked-- >= 1);
1138
1139 if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
1140 pa_cvolume new_volume;
1141
1142 /* Make the virtual volume relative */
1143 pa_sink_input_get_relative_volume(i, &i->virtual_volume);
1144
1145 /* And reset the the relative volume */
1146 pa_sink_input_set_relative_volume(i, NULL);
1147
1148 /* We might need to update the sink's volume if we are in flat
1149 * volume mode. */
1150 pa_sink_update_flat_volume(i->sink, &new_volume);
1151 pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
1152 }
1153
1154 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
1155
1156 pa_sink_update_status(i->sink);
1157 i->sink = NULL;
1158
1159 pa_sink_input_unref(i);
1160
1161 return 0;
1162 }
1163
1164 /* Called from main context */
1165 int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
1166 pa_resampler *new_resampler;
1167
1168 pa_sink_input_assert_ref(i);
1169 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1170 pa_assert(!i->sink);
1171 pa_sink_assert_ref(dest);
1172
1173 if (!pa_sink_input_may_move_to(i, dest))
1174 return -PA_ERR_NOTSUPPORTED;
1175
1176 if (i->thread_info.resampler &&
1177 pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &dest->sample_spec) &&
1178 pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &dest->channel_map))
1179
1180 /* Try to reuse the old resampler if possible */
1181 new_resampler = i->thread_info.resampler;
1182
1183 else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
1184 !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) ||
1185 !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) {
1186
1187 /* Okey, we need a new resampler for the new sink */
1188
1189 if (!(new_resampler = pa_resampler_new(
1190 i->core->mempool,
1191 &i->sample_spec, &i->channel_map,
1192 &dest->sample_spec, &dest->channel_map,
1193 i->requested_resample_method,
1194 ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
1195 ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
1196 (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
1197 pa_log_warn("Unsupported resampling operation.");
1198 return -PA_ERR_NOTSUPPORTED;
1199 }
1200 } else
1201 new_resampler = NULL;
1202
1203 if (i->moving)
1204 i->moving(i, dest);
1205
1206 i->sink = dest;
1207 i->save_sink = save;
1208 pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL);
1209
1210 if (pa_sink_input_get_state(i) == PA_SINK_INPUT_CORKED)
1211 i->sink->n_corked++;
1212
1213 /* Replace resampler and render queue */
1214 if (new_resampler != i->thread_info.resampler) {
1215
1216 if (i->thread_info.resampler)
1217 pa_resampler_free(i->thread_info.resampler);
1218 i->thread_info.resampler = new_resampler;
1219
1220 pa_memblockq_free(i->thread_info.render_memblockq);
1221
1222 i->thread_info.render_memblockq = pa_memblockq_new(
1223 0,
1224 MEMBLOCKQ_MAXLENGTH,
1225 0,
1226 pa_frame_size(&i->sink->sample_spec),
1227 0,
1228 1,
1229 0,
1230 &i->sink->silence);
1231 }
1232 pa_sink_update_status(dest);
1233
1234 if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
1235 pa_cvolume new_volume;
1236
1237 /* Make relative volume absolute again */
1238 pa_cvolume t = dest->reference_volume;
1239 pa_cvolume_remap(&t, &dest->channel_map, &i->channel_map);
1240 pa_sw_cvolume_multiply(&i->virtual_volume, &i->virtual_volume, &t);
1241
1242 /* We might need to update the sink's volume if we are in flat volume mode. */
1243 pa_sink_update_flat_volume(i->sink, &new_volume);
1244 pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
1245 }
1246
1247 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
1248
1249 pa_log_debug("Successfully moved sink input %i to %s.", i->index, dest->name);
1250
1251 /* Notify everyone */
1252 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i);
1253 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1254
1255 return 0;
1256 }
1257
1258 /* Called from main context */
1259 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
1260 int r;
1261
1262 pa_sink_input_assert_ref(i);
1263 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1264 pa_assert(i->sink);
1265 pa_sink_assert_ref(dest);
1266
1267 if (dest == i->sink)
1268 return 0;
1269
1270 if (!pa_sink_input_may_move_to(i, dest))
1271 return -PA_ERR_NOTSUPPORTED;
1272
1273 pa_sink_input_ref(i);
1274
1275 if ((r = pa_sink_input_start_move(i)) < 0) {
1276 pa_sink_input_unref(i);
1277 return r;
1278 }
1279
1280 if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) {
1281 pa_sink_input_unref(i);
1282 return r;
1283 }
1284
1285 pa_sink_input_unref(i);
1286
1287 return 0;
1288 }
1289
1290 /* Called from IO thread context */
1291 void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) {
1292 pa_bool_t corking, uncorking;
1293 pa_sink_input_assert_ref(i);
1294
1295 if (state == i->thread_info.state)
1296 return;
1297
1298 if ((state == PA_SINK_INPUT_DRAINED || state == PA_SINK_INPUT_RUNNING) &&
1299 !(i->thread_info.state == PA_SINK_INPUT_DRAINED || i->thread_info.state != PA_SINK_INPUT_RUNNING))
1300 pa_atomic_store(&i->thread_info.drained, 1);
1301
1302 corking = state == PA_SINK_INPUT_CORKED && i->thread_info.state == PA_SINK_INPUT_RUNNING;
1303 uncorking = i->thread_info.state == PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_RUNNING;
1304
1305 if (i->state_change)
1306 i->state_change(i, state);
1307
1308 i->thread_info.state = state;
1309
1310 if (corking) {
1311
1312 pa_log_debug("Requesting rewind due to corking");
1313
1314 /* This will tell the implementing sink input driver to rewind
1315 * so that the unplayed already mixed data is not lost */
1316 pa_sink_input_request_rewind(i, 0, TRUE, TRUE, FALSE);
1317
1318 } else if (uncorking) {
1319
1320 i->thread_info.underrun_for = (uint64_t) -1;
1321 i->thread_info.playing_for = 0;
1322
1323 pa_log_debug("Requesting rewind due to uncorking");
1324
1325 /* OK, we're being uncorked. Make sure we're not rewound when
1326 * the hw buffer is remixed and request a remix. */
1327 pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
1328 }
1329 }
1330
1331 /* Called from thread context, except when it is not. */
1332 int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1333 pa_sink_input *i = PA_SINK_INPUT(o);
1334 pa_sink_input_assert_ref(i);
1335
1336 switch (code) {
1337
1338 case PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME:
1339 if (pa_atomic_load(&i->before_ramping_v))
1340 i->thread_info.future_soft_volume = i->soft_volume;
1341
1342 if (!pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume)) {
1343 if (!pa_atomic_load(&i->before_ramping_v))
1344 i->thread_info.soft_volume = i->soft_volume;
1345 pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1346 }
1347 return 0;
1348
1349 case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE:
1350 if (pa_atomic_load(&i->before_ramping_m))
1351 i->thread_info.future_muted = i->muted;
1352
1353 if (i->thread_info.muted != i->muted) {
1354 if (!pa_atomic_load(&i->before_ramping_m))
1355 i->thread_info.muted = i->muted;
1356 pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1357 }
1358 return 0;
1359
1360 case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
1361 pa_usec_t *r = userdata;
1362
1363 r[0] += pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec);
1364 r[1] += pa_sink_get_latency_within_thread(i->sink);
1365
1366 return 0;
1367 }
1368
1369 case PA_SINK_INPUT_MESSAGE_SET_RATE:
1370
1371 i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
1372 pa_resampler_set_input_rate(i->thread_info.resampler, PA_PTR_TO_UINT(userdata));
1373
1374 return 0;
1375
1376 case PA_SINK_INPUT_MESSAGE_SET_STATE: {
1377 pa_sink_input *ssync;
1378
1379 pa_sink_input_set_state_within_thread(i, PA_PTR_TO_UINT(userdata));
1380
1381 for (ssync = i->thread_info.sync_prev; ssync; ssync = ssync->thread_info.sync_prev)
1382 pa_sink_input_set_state_within_thread(ssync, PA_PTR_TO_UINT(userdata));
1383
1384 for (ssync = i->thread_info.sync_next; ssync; ssync = ssync->thread_info.sync_next)
1385 pa_sink_input_set_state_within_thread(ssync, PA_PTR_TO_UINT(userdata));
1386
1387 return 0;
1388 }
1389
1390 case PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY: {
1391 pa_usec_t *usec = userdata;
1392
1393 *usec = pa_sink_input_set_requested_latency_within_thread(i, *usec);
1394 return 0;
1395 }
1396
1397 case PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY: {
1398 pa_usec_t *r = userdata;
1399
1400 *r = i->thread_info.requested_sink_latency;
1401 return 0;
1402 }
1403
1404 case PA_SINK_INPUT_MESSAGE_SET_ENVELOPE: {
1405 if (!i->thread_info.ramp_info.envelope)
1406 i->thread_info.ramp_info.envelope = pa_envelope_new(&i->sink->sample_spec);
1407
1408 if (i->thread_info.ramp_info.envelope && i->thread_info.ramp_info.item) {
1409 pa_envelope_remove(i->thread_info.ramp_info.envelope, i->thread_info.ramp_info.item);
1410 i->thread_info.ramp_info.item = NULL;
1411 }
1412
1413 i->thread_info.ramp_info.item = pa_envelope_add(i->thread_info.ramp_info.envelope, &i->using_def);
1414 i->thread_info.ramp_info.is_ramping = TRUE;
1415 i->thread_info.ramp_info.envelope_dead = FALSE;
1416 i->thread_info.ramp_info.envelope_dying = 0;
1417
1418 if (i->thread_info.ramp_info.envelope)
1419 pa_envelope_restart(i->thread_info.ramp_info.envelope);
1420
1421 return 0;
1422 }
1423 }
1424
1425 return -PA_ERR_NOTIMPLEMENTED;
1426 }
1427
1428 /* Called from main thread */
1429 pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) {
1430 pa_sink_input_assert_ref(i);
1431
1432 if (i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED)
1433 return pa_atomic_load(&i->thread_info.drained) ? PA_SINK_INPUT_DRAINED : PA_SINK_INPUT_RUNNING;
1434
1435 return i->state;
1436 }
1437
1438 /* Called from IO context */
1439 pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) {
1440 pa_sink_input_assert_ref(i);
1441
1442 if (PA_SINK_INPUT_IS_LINKED(i->thread_info.state))
1443 return pa_memblockq_is_empty(i->thread_info.render_memblockq);
1444
1445 return TRUE;
1446 }
1447
1448 /* Called from IO context */
1449 void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush, pa_bool_t dont_rewind_render) {
1450 size_t lbq;
1451
1452 /* If 'rewrite' is TRUE the sink is rewound as far as requested
1453 * and possible and the exact value of this is passed back the
1454 * implementor via process_rewind(). If 'flush' is also TRUE all
1455 * already rendered data is also dropped.
1456 *
1457 * If 'rewrite' is FALSE the sink is rewound as far as requested
1458 * and possible and the already rendered data is dropped so that
1459 * in the next iteration we read new data from the
1460 * implementor. This implies 'flush' is TRUE. If
1461 * dont_rewind_render is TRUE then the render memblockq is not
1462 * rewound. */
1463
1464 pa_sink_input_assert_ref(i);
1465
1466 nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes);
1467
1468 /* pa_log_debug("request rewrite %lu", (unsigned long) nbytes); */
1469
1470 /* We don't take rewind requests while we are corked */
1471 if (i->thread_info.state == PA_SINK_INPUT_CORKED)
1472 return;
1473
1474 pa_assert(rewrite || flush);
1475 pa_assert(!dont_rewind_render || !rewrite);
1476
1477 /* Calculate how much we can rewind locally without having to
1478 * touch the sink */
1479 if (rewrite)
1480 lbq = pa_memblockq_get_length(i->thread_info.render_memblockq);
1481 else
1482 lbq = 0;
1483
1484 /* Check if rewinding for the maximum is requested, and if so, fix up */
1485 if (nbytes <= 0) {
1486
1487 /* Calculate maximum number of bytes that could be rewound in theory */
1488 nbytes = i->sink->thread_info.max_rewind + lbq;
1489
1490 /* Transform from sink domain */
1491 if (i->thread_info.resampler)
1492 nbytes = pa_resampler_request(i->thread_info.resampler, nbytes);
1493 }
1494
1495 if (i->thread_info.rewrite_nbytes != (size_t) -1) {
1496 if (rewrite) {
1497 /* Make sure to not overwrite over underruns */
1498 if (nbytes > i->thread_info.playing_for)
1499 nbytes = (size_t) i->thread_info.playing_for;
1500
1501 i->thread_info.rewrite_nbytes = nbytes;
1502 } else
1503 i->thread_info.rewrite_nbytes = (size_t) -1;
1504 }
1505
1506 i->thread_info.rewrite_flush =
1507 i->thread_info.rewrite_flush ||
1508 (flush && i->thread_info.rewrite_nbytes != 0);
1509
1510 i->thread_info.dont_rewind_render =
1511 i->thread_info.dont_rewind_render ||
1512 dont_rewind_render;
1513
1514 if (nbytes != (size_t) -1) {
1515
1516 /* Transform to sink domain */
1517 if (i->thread_info.resampler)
1518 nbytes = pa_resampler_result(i->thread_info.resampler, nbytes);
1519
1520 if (nbytes > lbq)
1521 pa_sink_request_rewind(i->sink, nbytes - lbq);
1522 else
1523 /* This call will make sure process_rewind() is called later */
1524 pa_sink_request_rewind(i->sink, 0);
1525 }
1526 }
1527
1528 /* Called from main context */
1529 pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) {
1530 pa_sink_input_assert_ref(i);
1531 pa_assert(ret);
1532
1533 pa_silence_memchunk_get(
1534 &i->core->silence_cache,
1535 i->core->mempool,
1536 ret,
1537 &i->sample_spec,
1538 i->thread_info.resampler ? pa_resampler_max_block_size(i->thread_info.resampler) : 0);
1539
1540 return ret;
1541 }
1542
1543 /* Called from main context */
1544 void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *data) {
1545 pa_proplist *pl = NULL;
1546 pa_sink_input_send_event_hook_data hook_data;
1547
1548 pa_sink_input_assert_ref(i);
1549 pa_assert(event);
1550
1551 if (!i->send_event)
1552 return;
1553
1554 if (!data)
1555 data = pl = pa_proplist_new();
1556
1557 hook_data.sink_input = i;
1558 hook_data.data = data;
1559 hook_data.event = event;
1560
1561 if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], &hook_data) < 0)
1562 goto finish;
1563
1564 i->send_event(i, event, data);
1565
1566 finish:
1567 if (pl)
1568 pa_proplist_free(pl);
1569 }
1570
1571 /* Called from IO context */
1572 static void sink_input_volume_ramping(pa_sink_input* i, pa_memchunk* chunk) {
1573 pa_assert(i);
1574 pa_assert(chunk);
1575 pa_assert(chunk->memblock);
1576 pa_assert(i->thread_info.ramp_info.is_ramping);
1577
1578 /* Volume is adjusted with ramping effect here */
1579 pa_envelope_apply(i->thread_info.ramp_info.envelope, chunk);
1580
1581 if (pa_envelope_is_finished(i->thread_info.ramp_info.envelope)) {
1582 i->thread_info.ramp_info.is_ramping = FALSE;
1583 if (pa_atomic_load(&i->before_ramping_v)) {
1584 i->thread_info.soft_volume = i->thread_info.future_soft_volume;
1585 pa_atomic_store(&i->before_ramping_v, 0);
1586 }
1587 else if (pa_atomic_load(&i->before_ramping_m)) {
1588 i->thread_info.muted = i->thread_info.future_muted;
1589 pa_atomic_store(&i->before_ramping_m, 0);
1590 }
1591 }
1592 }
1593
1594 /*
1595 * Called from main context
1596 * This function should be called inside pa_sink_input_set_volume_with_ramping
1597 * should be called after soft_volume of sink_input and sink are all adjusted
1598 */
1599 static void sink_input_set_ramping_info(pa_sink_input* i, pa_volume_t pre_virtual_volume, pa_volume_t target_virtual_volume, pa_usec_t t) {
1600
1601 int32_t target_abs_vol, target_apply_vol, pre_apply_vol;
1602 pa_assert(i);
1603
1604 pa_log_debug("Sink input's soft volume is %d= %f ", pa_cvolume_avg(&i->soft_volume), pa_sw_volume_to_linear(pa_cvolume_avg(&i->soft_volume)));
1605
1606 /* Calculation formula are target_abs_vol := i->soft_volume
1607 * target_apply_vol := lrint(pa_sw_volume_to_linear(target_abs_vol) * 0x10000)
1608 * pre_apply_vol := ( previous_virtual_volume / target_virtual_volume ) * target_apply_vol
1609 *
1610 * Will do volume adjustment inside pa_sink_input_peek
1611 */
1612 target_abs_vol = pa_cvolume_avg(&i->soft_volume);
1613 target_apply_vol = (int32_t) lrint(pa_sw_volume_to_linear(target_abs_vol) * 0x10000);
1614 pre_apply_vol = (int32_t) ((pa_sw_volume_to_linear(pre_virtual_volume) / pa_sw_volume_to_linear(target_virtual_volume)) * target_apply_vol);
1615
1616 i->using_def.n_points = 2;
1617 i->using_def.points_x[0] = 0;
1618 i->using_def.points_x[1] = t;
1619 i->using_def.points_y.i[0] = pre_apply_vol;
1620 i->using_def.points_y.i[1] = target_apply_vol;
1621 i->using_def.points_y.f[0] = ((float) i->using_def.points_y.i[0]) /0x10000;
1622 i->using_def.points_y.f[1] = ((float) i->using_def.points_y.i[1]) /0x10000;
1623
1624 pa_log_debug("Volume Ramping: Point 1 is %d=%f, Point 2 is %d=%f\n", i->using_def.points_y.i[0], i->using_def.points_y.f[0],
1625 i->using_def.points_y.i[1], i->using_def.points_y.f[1]);
1626
1627 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_ENVELOPE, NULL, 0, NULL) == 0);
1628 }
1629
1630 /* Called from main context */
1631 static void sink_input_set_ramping_info_for_mute(pa_sink_input* i, pa_bool_t mute, pa_usec_t t) {
1632
1633 int32_t cur_vol;
1634 pa_assert(i);
1635
1636 i->using_def.n_points = 2;
1637 i->using_def.points_x[0] = 0;
1638 i->using_def.points_x[1] = t;
1639 cur_vol = (int32_t) lrint( pa_sw_volume_to_linear(pa_cvolume_avg(&i->soft_volume)) * 0x10000);
1640
1641 if (mute) {
1642 i->using_def.points_y.i[0] = cur_vol;
1643 i->using_def.points_y.i[1] = 0;
1644 } else {
1645 i->using_def.points_y.i[0] = 0;
1646 i->using_def.points_y.i[1] = cur_vol;
1647 }
1648
1649 i->using_def.points_y.f[0] = ((float) i->using_def.points_y.i[0]) /0x10000;
1650 i->using_def.points_y.f[1] = ((float) i->using_def.points_y.i[1]) /0x10000;
1651
1652 pa_log_debug("Mute Ramping: Point 1 is %d=%f, Point 2 is %d=%f\n", i->using_def.points_y.i[0], i->using_def.points_y.f[0],
1653 i->using_def.points_y.i[1], i->using_def.points_y.f[1]);
1654
1655 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_ENVELOPE, NULL, 0, NULL) == 0);
1656 }
1657
1658 /* Called from IO context */
1659 static void sink_input_release_envelope(pa_sink_input *i) {
1660 pa_assert(i);
1661 pa_assert(!i->thread_info.ramp_info.is_ramping);
1662 pa_assert(i->thread_info.ramp_info.envelope_dead);
1663
1664 pa_envelope_free(i->thread_info.ramp_info.envelope);
1665 i->thread_info.ramp_info.envelope = NULL;
1666 i->thread_info.ramp_info.item = NULL;
1667 }
1668
1669 /* Called from IO context */
1670 static void sink_input_rewind_ramp_info(pa_sink_input *i, size_t nbytes) {
1671 pa_assert(i);
1672
1673 if (!i->thread_info.ramp_info.envelope_dead) {
1674 pa_assert(i->thread_info.ramp_info.envelope);
1675
1676 int32_t envelope_length = pa_envelope_length(i->thread_info.ramp_info.envelope);
1677
1678 if (i->thread_info.ramp_info.envelope_dying > envelope_length) {
1679 if ((i->thread_info.ramp_info.envelope_dying - nbytes) < envelope_length) {
1680 pa_log_debug("Envelope Become Alive");
1681 pa_envelope_rewind(i->thread_info.ramp_info.envelope, envelope_length - (i->thread_info.ramp_info.envelope_dying - nbytes));
1682 i->thread_info.ramp_info.is_ramping = TRUE;
1683 }
1684 } else if (i->thread_info.ramp_info.envelope_dying < envelope_length) {
1685 if ((i->thread_info.ramp_info.envelope_dying - nbytes) <= 0) {
1686 pa_log_debug("Envelope Restart");
1687 pa_envelope_restart(i->thread_info.ramp_info.envelope);
1688 }
1689 else {
1690 pa_log_debug("Envelope Simple Rewind");
1691 pa_envelope_rewind(i->thread_info.ramp_info.envelope, nbytes);
1692 }
1693 }
1694
1695 i->thread_info.ramp_info.envelope_dying -= nbytes;
1696 if (i->thread_info.ramp_info.envelope_dying <= 0)
1697 i->thread_info.ramp_info.envelope_dying = 0;
1698 }
1699 }
1700
1701 void pa_sink_input_set_volume_with_ramping(pa_sink_input *i, const pa_cvolume *volume, pa_bool_t save, pa_bool_t absolute, pa_usec_t t){
1702 pa_cvolume v;
1703 pa_volume_t previous_virtual_volume, target_virtual_volume;
1704 pa_sink_input_assert_ref(i);
1705
1706 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1707 pa_assert(volume);
1708 pa_assert(pa_cvolume_valid(volume));
1709 pa_assert(pa_cvolume_compatible(volume, &i->sample_spec));
1710
1711 if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
1712 v = i->sink->reference_volume;
1713 pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
1714 volume = pa_sw_cvolume_multiply(&v, &v, volume);
1715 }
1716
1717 if (pa_cvolume_equal(volume, &i->virtual_volume))
1718 return;
1719
1720 previous_virtual_volume = pa_cvolume_avg(&i->virtual_volume);
1721 target_virtual_volume = pa_cvolume_avg(volume);
1722 if (t > 0 && target_virtual_volume > 0)
1723 pa_log_debug("SetVolumeWithRamping: Virtual Volume From %u=%f to %u=%f\n", previous_virtual_volume, pa_sw_volume_to_linear(previous_virtual_volume),
1724 target_virtual_volume, pa_sw_volume_to_linear(target_virtual_volume));
1725
1726 i->virtual_volume = *volume;
1727 i->save_volume = save;
1728
1729 /* Set this flag before the following code modify i->thread_info.soft_volume */
1730 if (t > 0 && target_virtual_volume > 0)
1731 pa_atomic_store(&i->before_ramping_v, 1);
1732
1733 if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
1734 pa_cvolume new_volume;
1735
1736 /* We are in flat volume mode, so let's update all sink input
1737 * volumes and update the flat volume of the sink */
1738
1739 pa_sink_update_flat_volume(i->sink, &new_volume);
1740 pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE, FALSE, FALSE);
1741
1742 } else {
1743
1744 /* OK, we are in normal volume mode. The volume only affects
1745 * ourselves */
1746 pa_sink_input_set_relative_volume(i, volume);
1747
1748 /* Hooks have the ability to play games with i->soft_volume */
1749 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1750
1751 /* Copy the new soft_volume to the thread_info struct */
1752 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
1753 }
1754
1755 if (t > 0 && target_virtual_volume > 0)
1756 sink_input_set_ramping_info(i, previous_virtual_volume, target_virtual_volume, t);
1757
1758 /* The virtual volume changed, let's tell people so */
1759 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1760 }
1761
1762 void pa_sink_input_set_mute_with_ramping(pa_sink_input *i, pa_bool_t mute, pa_bool_t save, pa_usec_t t){
1763
1764 pa_assert(i);
1765 pa_sink_input_assert_ref(i);
1766 pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
1767
1768 if (!i->muted == !mute)
1769 return;
1770
1771 i->muted = mute;
1772 i->save_muted = save;
1773 /* Set this flag before the following code modify i->thread_info.muted, otherwise distortion will be heard */
1774 if (t > 0)
1775 pa_atomic_store(&i->before_ramping_m, 1);
1776
1777 pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
1778
1779 if (t > 0)
1780 sink_input_set_ramping_info_for_mute(i, mute, t);
1781
1782 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1783 }