Merge HUGE set of changes temporarily into a branch, to allow me to move them from...
[profile/ivi/pulseaudio-panda.git] / src / pulsecore / sink-input.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5
6   Copyright 2004-2006 Lennart Poettering
7   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9   PulseAudio is free software; you can redistribute it and/or modify
10   it under the terms of the GNU Lesser General Public License as published
11   by the Free Software Foundation; either version 2 of the License,
12   or (at your option) any later version.
13
14   PulseAudio is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with PulseAudio; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22   USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <pulse/utf8.h>
34 #include <pulse/xmalloc.h>
35
36 #include <pulsecore/sample-util.h>
37 #include <pulsecore/core-subscribe.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/play-memblockq.h>
40 #include <pulsecore/namereg.h>
41
42 #include "sink-input.h"
43
44 #define CONVERT_BUFFER_LENGTH 4096
45 #define MOVE_BUFFER_LENGTH (1024*1024)
46 #define SILENCE_BUFFER_LENGTH (64*1024)
47
48 static void sink_input_free(pa_msgobject *o);
49
50 pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {
51     pa_assert(data);
52
53     memset(data, 0, sizeof(*data));
54     data->resample_method = PA_RESAMPLER_INVALID;
55     
56     return data;
57 }
58
59 void pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map) {
60     pa_assert(data);
61
62     if ((data->channel_map_is_set = !!map))
63         data->channel_map = *map;
64 }
65
66 void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
67     pa_assert(data);
68
69     if ((data->volume_is_set = !!volume))
70         data->volume = *volume;
71 }
72
73 void pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec) {
74     pa_assert(data);
75
76     if ((data->sample_spec_is_set = !!spec))
77         data->sample_spec = *spec;
78 }
79
80 void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, int mute) {
81     pa_assert(data);
82
83     data->muted_is_set = 1;
84     data->muted = !!mute;
85 }
86
87 pa_sink_input* pa_sink_input_new(
88         pa_core *core,
89         pa_sink_input_new_data *data,
90         pa_sink_input_flags_t flags) {
91
92     pa_sink_input *i;
93     pa_resampler *resampler = NULL;
94     char st[PA_SAMPLE_SPEC_SNPRINT_MAX];
95
96     pa_assert(core);
97     pa_assert(data);
98
99     if (!(flags & PA_SINK_INPUT_NO_HOOKS))
100         if (pa_hook_fire(&core->hook_sink_input_new, data) < 0)
101             return NULL;
102
103     pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
104     pa_return_null_if_fail(!data->name || pa_utf8_valid(data->name));
105
106     if (!data->sink)
107         data->sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK, 1);
108
109     pa_return_null_if_fail(data->sink);
110     pa_return_null_if_fail(pa_sink_get_state(data->sink) != PA_SINK_DISCONNECTED);
111
112     if (!data->sample_spec_is_set)
113         data->sample_spec = data->sink->sample_spec;
114
115     pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec));
116
117     if (!data->channel_map_is_set) {
118         if (data->sink->channel_map.channels == data->sample_spec.channels)
119             data->channel_map = data->sink->channel_map;
120         else 
121             pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
122     }
123
124     pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
125     pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
126
127     if (!data->volume_is_set)
128         pa_cvolume_reset(&data->volume, data->sample_spec.channels);
129
130     pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
131     pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
132
133     if (!data->muted_is_set)
134         data->muted = 0;
135     
136     if (data->resample_method == PA_RESAMPLER_INVALID)
137         data->resample_method = core->resample_method;
138
139     pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX);
140
141     if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
142         pa_log_warn("Failed to create sink input: too many inputs per sink.");
143         return NULL;
144     }
145
146     if ((flags & PA_SINK_INPUT_VARIABLE_RATE) ||
147         !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) ||
148         !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) {
149
150         if (!(resampler = pa_resampler_new(
151                       core->mempool,
152                       &data->sample_spec, &data->channel_map,
153                       &data->sink->sample_spec, &data->sink->channel_map,
154                       data->resample_method))) {
155             pa_log_warn("Unsupported resampling operation.");
156             return NULL;
157         }
158
159         data->resample_method = pa_resampler_get_method(resampler);
160     }
161
162     i = pa_msgobject_new(pa_sink_input);
163
164     i->parent.parent.free = sink_input_free;
165     i->parent.process_msg = pa_sink_input_process_msg;
166     
167     i->core = core;
168     pa_atomic_load(&i->state, PA_SINK_INPUT_DRAINED);
169     i->flags = flags;
170     i->name = pa_xstrdup(data->name);
171     i->driver = pa_xstrdup(data->driver);
172     i->module = data->module;
173     i->sink = data->sink;
174     i->client = data->client;
175     
176     i->resample_method = data->resample_method;
177     i->sample_spec = data->sample_spec;
178     i->channel_map = data->channel_map;
179
180     i->volume = data->volume;
181     i->muted = data->muted;
182     
183     i->process_msg = NULL;
184     i->peek = NULL;
185     i->drop = NULL;
186     i->kill = NULL;
187     i->get_latency = NULL;
188     i->underrun = NULL;
189     i->userdata = NULL;
190
191     i->thread_info.silence_memblock = NULL;
192     i->thread_info.move_silence = 0;
193     pa_memchunk_reset(&i->thread_info.resampled_chunk);
194     i->thread_info.resampler = resampler;
195     i->thread_info.soft_volume = i->volume;
196     i->thread_info.soft_muted = i->muted;
197
198     pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
199     pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0);
200
201     pa_log_info("Created input %u \"%s\" on %s with sample spec %s",
202                 i->index,
203                 i->name,
204                 i->sink->name,
205                 pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec));
206
207     /* Don't forget to call pa_sink_input_put! */
208
209     return i;
210 }
211
212 void pa_sink_input_disconnect(pa_sink_input *i) {
213     pa_assert(i);
214     pa_return_if_fail(pa_sink_input_get_state(i) != PA_SINK_INPUT_DISCONNECTED);
215
216     pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_REMOVE_INPUT, i, NULL);
217     
218     pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
219     pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
220
221     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
222     i->sink = NULL;
223
224     i->process_msg = NULL;
225     i->peek = NULL;
226     i->drop = NULL;
227     i->kill = NULL;
228     i->get_latency = NULL;
229     i->underrun = NULL;
230
231     pa_atomic_load(&i->state, PA_SINK_INPUT_DISCONNECTED);
232 }
233
234 static void sink_input_free(pa_msgobject *o) {
235     pa_sink_input* i = PA_SINK_INPUT(o);
236
237     pa_assert(i);
238     pa_assert(pa_sink_input_refcnt(i) == 0);
239     
240     pa_sink_input_disconnect(i);
241
242     pa_log_info("Freeing output %u \"%s\"", i->index, i->name);
243
244     if (i->resampled_chunk.memblock)
245         pa_memblock_unref(i->resampled_chunk.memblock);
246
247     if (i->thread_info.resampler)
248         pa_resampler_free(i->thread_info.resampler);
249
250     if (i->thread_info.silence_memblock)
251         pa_memblock_unref(i->thread_info.silence_memblock);
252
253     pa_xfree(i->name);
254     pa_xfree(i->driver);
255     pa_xfree(i);
256 }
257
258 void pa_sink_input_put(pa_sink_input *i) {
259     pa_sink_input_assert_ref(i);
260
261     i->thread_info.volume = i->volume;
262     i->thread_info.muted = i->muted;
263
264     pa_asyncmsgq_post(i->sink->asyncmsgq, i->sink, PA_SINK_MESSAGE_ADD_INPUT, i, NULL, pa_sink_unref, pa_sink_input_unref);
265     pa_sink_update_status(i->sink);
266
267     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
268 }
269
270 void pa_sink_input_kill(pa_sink_input*i) {
271     pa_sink_input_assert_ref(i);
272
273     if (i->kill)
274         i->kill(i);
275 }
276
277 pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
278     pa_usec_t r = 0;
279
280     pa_sink_input_assert_ref(i);
281
282     if (pa_asyncmsgq_send(i->sink->asyncmsgq, i->sink, PA_SINK_INPUT_MESSAGE_GET_LATENCY, &r, NULL) < 0)
283         r = 0;
284     
285     if (i->get_latency)
286         r += i->get_latency(i);
287
288     return r;
289 }
290
291 int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) {
292     int ret = -1;
293     int do_volume_adj_here;
294     int volume_is_norm;
295     pa_sink_input_state_t state;
296     
297     pa_sink_input_assert_ref(i);
298     pa_assert(chunk);
299     pa_assert(volume);
300
301     state = pa_sink_input_get_state(i);
302
303     if (state == PA_SINK_INPUT_DISCONNECTED)
304         return -1;
305
306     if (!i->peek || !i->drop || state == PA_SINK_INPUT_CORKED)
307         goto finish;
308
309     pa_assert(state == PA_SINK_INPUT_RUNNING || state == PA_SINK_INPUT_DRAINED);
310
311 /*     if (i->thread_info.move_silence > 0) { */
312 /*         size_t l; */
313
314 /*         /\* We have just been moved and shall play some silence for a */
315 /*          * while until the old sink has drained its playback buffer *\/ */
316
317 /*         if (!i->thread_info.silence_memblock) */
318 /*             i->thread_info.silence_memblock = pa_silence_memblock_new(i->sink->core->mempool, &i->sink->sample_spec, SILENCE_BUFFER_LENGTH); */
319
320 /*         chunk->memblock = pa_memblock_ref(i->thread_info.silence_memblock); */
321 /*         chunk->index = 0; */
322 /*         l = pa_memblock_get_length(chunk->memblock); */
323 /*         chunk->length = i->move_silence < l ? i->move_silence : l; */
324
325 /*         ret = 0; */
326 /*         do_volume_adj_here = 1; */
327 /*         goto finish; */
328 /*     } */
329
330     if (!i->resampler) {
331         do_volume_adj_here = 0;
332         ret = i->peek(i, chunk);
333         goto finish;
334     }
335
336     do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
337     volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.soft_muted;
338
339     while (!i->thread_info.resampled_chunk.memblock) {
340         pa_memchunk tchunk;
341         size_t l;
342
343         if ((ret = i->peek(i, &tchunk)) < 0)
344             goto finish;
345
346         pa_assert(tchunk.length);
347
348         l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
349
350         if (l > tchunk.length)
351             l = tchunk.length;
352
353         i->drop(i, &tchunk, l);
354         tchunk.length = l;
355
356         /* It might be necessary to adjust the volume here */
357         if (do_volume_adj_here && !volume_is_norm) {
358             pa_memchunk_make_writable(&tchunk, 0);
359             pa_volume_memchunk(&tchunk, &i->sample_spec, &i->thread_info.soft_volume);
360         }
361
362         pa_resampler_run(i->resampler, &tchunk, &i->thread_info.resampled_chunk);
363         pa_memblock_unref(tchunk.memblock);
364     }
365
366     pa_assert(i->thread_info.resampled_chunk.memblock);
367     pa_assert(i->thread_info.resampled_chunk.length);
368
369     *chunk = i->thread_info.resampled_chunk;
370     pa_memblock_ref(i->thread_info.resampled_chunk.memblock);
371
372     ret = 0;
373
374 finish:
375
376     if (ret < 0 && state == PA_SINK_INPUT_RUNNING && i->underrun)
377         i->underrun(i);
378
379     if (ret >= 0)
380         pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_RUNNING);
381     else if (ret < 0 && i->state == PA_SINK_INPUT_RUNNING)
382         pa_atomic_cmpxchg(&i->state, state, PA_SINK_INPUT_DRAINED);
383
384     if (ret >= 0) {
385         /* Let's see if we had to apply the volume adjustment
386          * ourselves, or if this can be done by the sink for us */
387
388         if (do_volume_adj_here)
389             /* We had different channel maps, so we already did the adjustment */
390             pa_cvolume_reset(volume, i->sink->sample_spec.channels);
391         else
392             /* We've both the same channel map, so let's have the sink do the adjustment for us*/
393             *volume = i->thread_info.volume;
394     }
395
396     return ret;
397 }
398
399 void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
400     pa_sink_input_assert_ref(i);
401     pa_assert(length > 0);
402
403 /*     if (i->move_silence > 0) { */
404
405 /*         if (chunk) { */
406 /*             size_t l; */
407
408 /*             l = pa_memblock_get_length(i->silence_memblock); */
409
410 /*             if (chunk->memblock != i->silence_memblock || */
411 /*                 chunk->index != 0 || */
412 /*                 (chunk->memblock && (chunk->length != (l < i->move_silence ? l : i->move_silence)))) */
413 /*                 return; */
414
415 /*         } */
416
417 /*         pa_assert(i->move_silence >= length); */
418
419 /*         i->move_silence -= length; */
420
421 /*         if (i->move_silence <= 0) { */
422 /*             pa_assert(i->silence_memblock); */
423 /*             pa_memblock_unref(i->silence_memblock); */
424 /*             i->silence_memblock = NULL; */
425 /*         } */
426
427 /*         return; */
428 /*     } */
429
430     if (!i->resampler) {
431         if (i->drop)
432             i->drop(i, chunk, length);
433         return;
434     }
435
436     pa_assert(i->thread_info.resampled_chunk.memblock);
437     pa_assert(i->thread_info.resampled_chunk.length >= length);
438
439     i->thread_info.resampled_chunk.index += length;
440     i->thread_info.resampled_chunk.length -= length;
441
442     if (i->thread_info.resampled_chunk.length <= 0) {
443         pa_memblock_unref(i->thread_info.resampled_chunk.memblock);
444         i->thread_info.resampled_chunk.memblock = NULL;
445         i->thread_info.resampled_chunk.index = i->thread_info.resampled_chunk.length = 0;
446     }
447 }
448
449 void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
450     pa_sink_input_assert_ref(i);
451
452     if (pa_cvolume_equal(&i->volume, volume))
453         return;
454
455     i->volume = *volume;
456
457     pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, pa_xnewdup(struct pa_cvolume, volume, 1), pa_sink_input_unref, pa_xfree);
458     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
459 }
460
461 const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) {
462     pa_sink_input_assert_ref(i);
463
464     return &i->volume;
465 }
466
467 void pa_sink_input_set_mute(pa_sink_input *i, int mute) {
468     pa_assert(i);
469     pa_sink_input_assert_ref(i);
470
471     if (!i->muted == !mute)
472         return;
473
474     i->muted = mute;
475
476     pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_MUTE, PA_UINT_TO_PTR(mute), pa_sink_input_unref, NULL);
477     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
478 }
479
480 int pa_sink_input_get_mute(pa_sink_input *i) {
481     pa_sink_input_assert_ref(i);
482
483     return !!i->mute;
484 }
485
486 void pa_sink_input_cork(pa_sink_input *i, int b) {
487     int n;
488     pa_sink_input_state_t state;
489
490     pa_sink_input_assert_ref(i);
491
492     state = pa_sink_input_get_state(i);
493     pa_assert(state != PA_SINK_INPUT_DISCONNECTED);
494
495     if (b && state != PA_SINK_INPUT_CORKED)
496         pa_atomic_store(i->state, PA_SINK_INPUT_CORKED);
497     else if (!b && state == PA_SINK_INPUT_CORKED)
498         pa_atomic_cmpxchg(i->state, state, PA_SINK_INPUT_DRAINED);
499 }
500
501 int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
502     pa_sink_input_assert_ref(i);
503     pa_return_val_if_fail(u->thread_info.resampler, -1);
504
505     if (i->sample_spec.rate == rate)
506         return 0;
507
508     i->sample_spec.rate = rate;
509
510     pa_asyncmsgq_post(s->asyncmsgq, pa_sink_input_ref(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), NULL, pa_sink_input_unref, NULL);
511     
512     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
513     return 0
514 }
515
516 void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
517     pa_sink_input_assert_ref(i);
518
519     if (!i->name && !name)
520         return;
521
522     if (i->name && name && !strcmp(i->name, name))
523         return;
524
525     pa_xfree(i->name);
526     i->name = pa_xstrdup(name);
527
528     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
529 }
530
531 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
532     pa_sink_input_assert_ref(i);
533
534     return i->resample_method;
535 }
536
537 int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, int immediately) {
538     pa_resampler *new_resampler = NULL;
539     pa_memblockq *buffer = NULL;
540     pa_sink *origin;
541
542     pa_sink_input_assert_ref(i);
543     pa_sink_assert_ref(dest);
544
545     return -1;
546     
547 /*     origin = i->sink; */
548
549 /*     if (dest == origin) */
550 /*         return 0; */
551
552 /*     if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { */
553 /*         pa_log_warn("Failed to move sink input: too many inputs per sink."); */
554 /*         return -1; */
555 /*     } */
556
557 /*     if (i->resampler && */
558 /*         pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) && */
559 /*         pa_channel_map_equal(&origin->channel_map, &dest->channel_map)) */
560
561 /*         /\* Try to reuse the old resampler if possible *\/ */
562 /*         new_resampler = i->resampler; */
563
564 /*     else if ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) || */
565 /*         !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec) || */
566 /*         !pa_channel_map_equal(&i->channel_map, &dest->channel_map)) { */
567
568 /*         /\* Okey, we need a new resampler for the new sink *\/ */
569
570 /*         if (!(new_resampler = pa_resampler_new( */
571 /*                       dest->core->mempool, */
572 /*                       &i->sample_spec, &i->channel_map, */
573 /*                       &dest->sample_spec, &dest->channel_map, */
574 /*                       i->resample_method))) { */
575 /*             pa_log_warn("Unsupported resampling operation."); */
576 /*             return -1; */
577 /*         } */
578 /*     } */
579
580 /*     if (!immediately) { */
581 /*         pa_usec_t old_latency, new_latency; */
582 /*         pa_usec_t silence_usec = 0; */
583
584 /*         buffer = pa_memblockq_new(0, MOVE_BUFFER_LENGTH, 0, pa_frame_size(&origin->sample_spec), 0, 0, NULL); */
585
586 /*         /\* Let's do a little bit of Voodoo for compensating latency */
587 /*          * differences *\/ */
588
589 /*         old_latency = pa_sink_get_latency(origin); */
590 /*         new_latency = pa_sink_get_latency(dest); */
591
592 /*         /\* The already resampled data should go to the old sink *\/ */
593
594 /*         if (old_latency >= new_latency) { */
595
596 /*             /\* The latency of the old sink is larger than the latency */
597 /*              * of the new sink. Therefore to compensate for the */
598 /*              * difference we to play silence on the new one for a */
599 /*              * while *\/ */
600
601 /*             silence_usec = old_latency - new_latency; */
602
603 /*         } else { */
604 /*             size_t l; */
605 /*             int volume_is_norm; */
606
607 /*             /\* The latency of new sink is larger than the latency of */
608 /*              * the old sink. Therefore we have to precompute a little */
609 /*              * and make sure that this is still played on the old */
610 /*              * sink, until we can play the first sample on the new */
611 /*              * sink.*\/ */
612
613 /*             l = pa_usec_to_bytes(new_latency - old_latency, &origin->sample_spec); */
614
615 /*             volume_is_norm = pa_cvolume_is_norm(&i->volume); */
616
617 /*             while (l > 0) { */
618 /*                 pa_memchunk chunk; */
619 /*                 pa_cvolume volume; */
620 /*                 size_t n; */
621
622 /*                 if (pa_sink_input_peek(i, &chunk, &volume) < 0) */
623 /*                     break; */
624
625 /*                 n = chunk.length > l ? l : chunk.length; */
626 /*                 pa_sink_input_drop(i, &chunk, n); */
627 /*                 chunk.length = n; */
628
629 /*                 if (!volume_is_norm) { */
630 /*                     pa_memchunk_make_writable(&chunk, 0); */
631 /*                     pa_volume_memchunk(&chunk, &origin->sample_spec, &volume); */
632 /*                 } */
633
634 /*                 if (pa_memblockq_push(buffer, &chunk) < 0) { */
635 /*                     pa_memblock_unref(chunk.memblock); */
636 /*                     break; */
637 /*                 } */
638
639 /*                 pa_memblock_unref(chunk.memblock); */
640 /*                 l -= n; */
641 /*             } */
642 /*         } */
643
644 /*         if (i->resampled_chunk.memblock) { */
645
646 /*             /\* There is still some data left in the already resampled */
647 /*              * memory block. Hence, let's output it on the old sink */
648 /*              * and sleep so long on the new sink *\/ */
649
650 /*             pa_memblockq_push(buffer, &i->resampled_chunk); */
651 /*             silence_usec += pa_bytes_to_usec(i->resampled_chunk.length, &origin->sample_spec); */
652 /*         } */
653
654 /*         /\* Calculate the new sleeping time *\/ */
655 /*         i->move_silence = pa_usec_to_bytes( */
656 /*                 pa_bytes_to_usec(i->move_silence, &i->sample_spec) + */
657 /*                 silence_usec, */
658 /*                 &i->sample_spec); */
659 /*     } */
660
661 /*     /\* Okey, let's move it *\/ */
662 /*     pa_idxset_remove_by_data(origin->inputs, i, NULL); */
663 /*     pa_idxset_put(dest->inputs, i, NULL); */
664 /*     i->sink = dest; */
665
666 /*     /\* Replace resampler *\/ */
667 /*     if (new_resampler != i->resampler) { */
668 /*         if (i->resampler) */
669 /*             pa_resampler_free(i->resampler); */
670 /*         i->resampler = new_resampler; */
671
672 /*         /\* if the resampler changed, the silence memblock is */
673 /*          * probably invalid now, too *\/ */
674 /*         if (i->silence_memblock) { */
675 /*             pa_memblock_unref(i->silence_memblock); */
676 /*             i->silence_memblock = NULL; */
677 /*         } */
678 /*     } */
679
680 /*     /\* Dump already resampled data *\/ */
681 /*     if (i->resampled_chunk.memblock) { */
682 /*         pa_memblock_unref(i->resampled_chunk.memblock); */
683 /*         i->resampled_chunk.memblock = NULL; */
684 /*         i->resampled_chunk.index = i->resampled_chunk.length = 0; */
685 /*     } */
686
687 /*     /\* Notify everyone *\/ */
688 /*     pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); */
689 /*     pa_sink_notify(i->sink); */
690
691 /*     /\* Ok, now let's feed the precomputed buffer to the old sink *\/ */
692 /*     if (buffer) */
693 /*         pa_play_memblockq(origin, "Ghost Stream", &origin->sample_spec, &origin->channel_map, buffer, NULL); */
694
695 /*     return 0; */
696 }
697
698 int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, pa_memchunk *chunk) {
699     pa_sink_input *i = PA_SINK_INPUT(o);
700     
701     pa_sink_input_assert_ref(i);
702
703     switch (code) {
704         case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
705             s->thread_info.soft_volume = *((pa_cvolume*) userdata);
706             return 0;
707             
708         case PA_SINK_INPUT_MESSAGE_SET_MUTE:
709             s->thread_info.soft_muted = PA_PTR_TO_UINT(userdata);
710             return 0;
711             
712         case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
713             pa_usec_t *r = userdata;
714             
715             if (i->thread_info.resampled_chunk.memblock)
716                 *r += pa_bytes_to_usec(i->resampled_chunk.length, &i->sink->sample_spec);
717
718 /*             if (i->move_silence) */
719 /*                 r += pa_bytes_to_usec(i->move_silence, &i->sink->sample_spec); */
720             
721             return 0;
722         }
723             
724         case PA_SINK_INPUT_MESSAGE_SET_RATE: {
725             
726             i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
727             pa_resampler_set_input_rate(i->resampler, PA_PTR_TO_UINT(userdata));
728
729             return 0;
730         }
731     }
732
733     return -1;
734 }