]> code.delx.au - pulseaudio/blob - src/pulsecore/source-output.c
get rid of svn $ keywords
[pulseaudio] / src / pulsecore / source-output.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <pulse/utf8.h>
31 #include <pulse/xmalloc.h>
32
33 #include <pulsecore/sample-util.h>
34 #include <pulsecore/core-subscribe.h>
35 #include <pulsecore/log.h>
36 #include <pulsecore/namereg.h>
37 #include <pulsecore/core-util.h>
38
39 #include "source-output.h"
40
41 #define MEMBLOCKQ_MAXLENGTH (32*1024*1024)
42
43 static PA_DEFINE_CHECK_TYPE(pa_source_output, pa_msgobject);
44
45 static void source_output_free(pa_object* mo);
46
47 pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) {
48 pa_assert(data);
49
50 memset(data, 0, sizeof(*data));
51 data->resample_method = PA_RESAMPLER_INVALID;
52 data->proplist = pa_proplist_new();
53
54 return data;
55 }
56
57 void pa_source_output_new_data_set_sample_spec(pa_source_output_new_data *data, const pa_sample_spec *spec) {
58 pa_assert(data);
59
60 if ((data->sample_spec_is_set = !!spec))
61 data->sample_spec = *spec;
62 }
63
64 void pa_source_output_new_data_set_channel_map(pa_source_output_new_data *data, const pa_channel_map *map) {
65 pa_assert(data);
66
67 if ((data->channel_map_is_set = !!map))
68 data->channel_map = *map;
69 }
70
71 void pa_source_output_new_data_done(pa_source_output_new_data *data) {
72 pa_assert(data);
73
74 pa_proplist_free(data->proplist);
75 }
76
77 static void reset_callbacks(pa_source_output *o) {
78 pa_assert(o);
79
80 o->push = NULL;
81 o->process_rewind = NULL;
82 o->update_max_rewind = NULL;
83 o->attach = NULL;
84 o->detach = NULL;
85 o->suspend = NULL;
86 o->moved = NULL;
87 o->kill = NULL;
88 o->get_latency = NULL;
89 o->state_change = NULL;
90 }
91
92 pa_source_output* pa_source_output_new(
93 pa_core *core,
94 pa_source_output_new_data *data,
95 pa_source_output_flags_t flags) {
96
97 pa_source_output *o;
98 pa_resampler *resampler = NULL;
99 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
100
101 pa_assert(core);
102 pa_assert(data);
103
104 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], data) < 0)
105 return NULL;
106
107 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
108
109 if (!data->source)
110 data->source = pa_namereg_get(core, NULL, PA_NAMEREG_SOURCE, 1);
111
112 pa_return_null_if_fail(data->source);
113 pa_return_null_if_fail(pa_source_get_state(data->source) != PA_SOURCE_UNLINKED);
114
115 pa_return_null_if_fail(!data->direct_on_input || data->direct_on_input->sink == data->source->monitor_of);
116
117 if (!data->sample_spec_is_set)
118 data->sample_spec = data->source->sample_spec;
119
120 pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec));
121
122 if (!data->channel_map_is_set) {
123 if (data->source->channel_map.channels == data->sample_spec.channels)
124 data->channel_map = data->source->channel_map;
125 else
126 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
127 }
128
129 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
130 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
131
132 if (flags & PA_SOURCE_OUTPUT_FIX_FORMAT)
133 data->sample_spec.format = data->source->sample_spec.format;
134
135 if (flags & PA_SOURCE_OUTPUT_FIX_RATE)
136 data->sample_spec.rate = data->source->sample_spec.rate;
137
138 if (flags & PA_SOURCE_OUTPUT_FIX_CHANNELS) {
139 data->sample_spec.channels = data->source->sample_spec.channels;
140 data->channel_map = data->source->channel_map;
141 }
142
143 pa_assert(pa_sample_spec_valid(&data->sample_spec));
144 pa_assert(pa_channel_map_valid(&data->channel_map));
145
146 if (data->resample_method == PA_RESAMPLER_INVALID)
147 data->resample_method = core->resample_method;
148
149 pa_return_null_if_fail(data->resample_method < PA_RESAMPLER_MAX);
150
151 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE], data) < 0)
152 return NULL;
153
154 if (pa_idxset_size(data->source->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
155 pa_log("Failed to create source output: too many outputs per source.");
156 return NULL;
157 }
158
159 if ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
160 !pa_sample_spec_equal(&data->sample_spec, &data->source->sample_spec) ||
161 !pa_channel_map_equal(&data->channel_map, &data->source->channel_map)) {
162
163 if (!(resampler = pa_resampler_new(
164 core->mempool,
165 &data->source->sample_spec, &data->source->channel_map,
166 &data->sample_spec, &data->channel_map,
167 data->resample_method,
168 ((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
169 ((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
170 (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
171 pa_log_warn("Unsupported resampling operation.");
172 return NULL;
173 }
174
175 data->resample_method = pa_resampler_get_method(resampler);
176 }
177
178 o = pa_msgobject_new(pa_source_output);
179 o->parent.parent.free = source_output_free;
180 o->parent.process_msg = pa_source_output_process_msg;
181
182 o->core = core;
183 o->state = PA_SOURCE_OUTPUT_INIT;
184 o->flags = flags;
185 o->proplist = pa_proplist_copy(data->proplist);
186 o->driver = pa_xstrdup(data->driver);
187 o->module = data->module;
188 o->source = data->source;
189 o->client = data->client;
190
191 o->resample_method = data->resample_method;
192 o->sample_spec = data->sample_spec;
193 o->channel_map = data->channel_map;
194
195 o->direct_on_input = data->direct_on_input;
196
197 reset_callbacks(o);
198 o->userdata = NULL;
199
200 o->thread_info.state = o->state;
201 o->thread_info.attached = FALSE;
202 o->thread_info.sample_spec = o->sample_spec;
203 o->thread_info.resampler = resampler;
204 o->thread_info.requested_source_latency = (pa_usec_t) -1;
205 o->thread_info.direct_on_input = o->direct_on_input;
206
207 o->thread_info.delay_memblockq = pa_memblockq_new(
208 0,
209 MEMBLOCKQ_MAXLENGTH,
210 0,
211 pa_frame_size(&o->source->sample_spec),
212 0,
213 1,
214 0,
215 &o->source->silence);
216
217 pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
218 pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);
219
220 if (o->direct_on_input)
221 pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0);
222
223 pa_log_info("Created output %u \"%s\" on %s with sample spec %s and channel map %s",
224 o->index,
225 pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)),
226 o->source->name,
227 pa_sample_spec_snprint(st, sizeof(st), &o->sample_spec),
228 pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map));
229
230 /* Don't forget to call pa_source_output_put! */
231
232 return o;
233 }
234
235 static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) {
236 pa_assert(o);
237
238 if (o->state == PA_SOURCE_OUTPUT_CORKED && state != PA_SOURCE_OUTPUT_CORKED)
239 pa_assert_se(o->source->n_corked -- >= 1);
240 else if (o->state != PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_CORKED)
241 o->source->n_corked++;
242
243 pa_source_update_status(o->source);
244 }
245
246 static int source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
247 pa_assert(o);
248
249 if (o->state == state)
250 return 0;
251
252 if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) < 0)
253 return -1;
254
255 update_n_corked(o, state);
256 o->state = state;
257
258 if (state != PA_SOURCE_OUTPUT_UNLINKED)
259 pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED], o);
260
261 return 0;
262 }
263
264 void pa_source_output_unlink(pa_source_output*o) {
265 pa_bool_t linked;
266 pa_assert(o);
267
268 /* See pa_sink_unlink() for a couple of comments how this function
269 * works */
270
271 pa_source_output_ref(o);
272
273 linked = PA_SOURCE_OUTPUT_IS_LINKED(o->state);
274
275 if (linked)
276 pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], o);
277
278 if (o->direct_on_input)
279 pa_idxset_remove_by_data(o->direct_on_input->direct_outputs, o, NULL);
280 pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
281 if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
282 pa_source_output_unref(o);
283
284 update_n_corked(o, PA_SOURCE_OUTPUT_UNLINKED);
285 o->state = PA_SOURCE_OUTPUT_UNLINKED;
286
287 if (linked)
288 if (o->source->asyncmsgq)
289 pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
290
291 reset_callbacks(o);
292
293 if (linked) {
294 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_REMOVE, o->index);
295 pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], o);
296 }
297
298 o->source = NULL;
299 pa_source_output_unref(o);
300 }
301
302 static void source_output_free(pa_object* mo) {
303 pa_source_output *o = PA_SOURCE_OUTPUT(mo);
304
305 pa_assert(o);
306 pa_assert(pa_source_output_refcnt(o) == 0);
307
308 if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
309 pa_source_output_unlink(o);
310
311 pa_log_info("Freeing output %u \"%s\"", o->index, pa_strnull(pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME)));
312
313 pa_assert(!o->thread_info.attached);
314
315 if (o->thread_info.delay_memblockq)
316 pa_memblockq_free(o->thread_info.delay_memblockq);
317
318 if (o->thread_info.resampler)
319 pa_resampler_free(o->thread_info.resampler);
320
321 if (o->proplist)
322 pa_proplist_free(o->proplist);
323
324 pa_xfree(o->driver);
325 pa_xfree(o);
326 }
327
328 void pa_source_output_put(pa_source_output *o) {
329 pa_source_output_state_t state;
330 pa_source_output_assert_ref(o);
331
332 pa_assert(o->state == PA_SOURCE_OUTPUT_INIT);
333 pa_assert(o->push);
334
335 state = o->flags & PA_SOURCE_OUTPUT_START_CORKED ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
336
337 update_n_corked(o, state);
338 o->state = state;
339
340 pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL);
341
342 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW, o->index);
343 pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], o);
344 }
345
346 void pa_source_output_kill(pa_source_output*o) {
347 pa_source_output_assert_ref(o);
348 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
349
350 if (o->kill)
351 o->kill(o);
352 }
353
354 pa_usec_t pa_source_output_get_latency(pa_source_output *o) {
355 pa_usec_t r = 0;
356
357 pa_source_output_assert_ref(o);
358 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
359
360 if (pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, &r, 0, NULL) < 0)
361 r = 0;
362
363 if (o->get_latency)
364 r += o->get_latency(o);
365
366 return r;
367 }
368
369 /* Called from thread context */
370 void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
371 size_t length;
372 size_t limit, mbs = 0;
373
374 pa_source_output_assert_ref(o);
375 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
376 pa_assert(chunk);
377 pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec));
378
379 if (!o->push || o->thread_info.state == PA_SOURCE_OUTPUT_CORKED)
380 return;
381
382 pa_assert(o->thread_info.state == PA_SOURCE_OUTPUT_RUNNING);
383
384 if (pa_memblockq_push(o->thread_info.delay_memblockq, chunk) < 0) {
385 pa_log_debug("Delay queue overflow!");
386 pa_memblockq_seek(o->thread_info.delay_memblockq, chunk->length, PA_SEEK_RELATIVE);
387 }
388
389 limit = o->process_rewind ? 0 : o->source->thread_info.max_rewind;
390
391 /* Implement the delay queue */
392 while ((length = pa_memblockq_get_length(o->thread_info.delay_memblockq)) > limit) {
393 pa_memchunk qchunk;
394
395 length -= limit;
396
397 pa_assert_se(pa_memblockq_peek(o->thread_info.delay_memblockq, &qchunk) >= 0);
398
399 if (qchunk.length > length)
400 qchunk.length = length;
401
402 pa_assert(qchunk.length > 0);
403
404 if (!o->thread_info.resampler)
405 o->push(o, &qchunk);
406 else {
407 pa_memchunk rchunk;
408
409 if (mbs == 0)
410 mbs = pa_resampler_max_block_size(o->thread_info.resampler);
411
412 if (qchunk.length > mbs)
413 qchunk.length = mbs;
414
415 pa_resampler_run(o->thread_info.resampler, &qchunk, &rchunk);
416
417 if (rchunk.length > 0)
418 o->push(o, &rchunk);
419
420 if (rchunk.memblock)
421 pa_memblock_unref(rchunk.memblock);
422 }
423
424 pa_memblock_unref(qchunk.memblock);
425 pa_memblockq_drop(o->thread_info.delay_memblockq, qchunk.length);
426 }
427 }
428
429 /* Called from thread context */
430 void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in sink sample spec */) {
431 pa_source_output_assert_ref(o);
432
433 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
434 pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
435
436 if (nbytes <= 0)
437 return;
438
439 if (o->process_rewind) {
440 pa_assert(pa_memblockq_get_length(o->thread_info.delay_memblockq) == 0);
441
442 if (o->thread_info.resampler)
443 nbytes = pa_resampler_result(o->thread_info.resampler, nbytes);
444
445 pa_log_debug("Have to rewind %lu bytes on implementor.", (unsigned long) nbytes);
446
447 if (nbytes > 0)
448 o->process_rewind(o, nbytes);
449
450 if (o->thread_info.resampler)
451 pa_resampler_reset(o->thread_info.resampler);
452
453 } else
454 pa_memblockq_rewind(o->thread_info.delay_memblockq, nbytes);
455 }
456
457 /* Called from thread context */
458 void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* in the source's sample spec */) {
459 pa_source_output_assert_ref(o);
460 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
461 pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
462
463 if (o->update_max_rewind)
464 o->update_max_rewind(o, o->thread_info.resampler ? pa_resampler_result(o->thread_info.resampler, nbytes) : nbytes);
465 }
466
467 static pa_usec_t fixup_latency(pa_source *s, pa_usec_t usec) {
468 pa_source_assert_ref(s);
469
470 if (usec == (pa_usec_t) -1)
471 return usec;
472
473 if (s->max_latency > 0 && usec > s->max_latency)
474 usec = s->max_latency;
475
476 if (s->min_latency > 0 && usec < s->min_latency)
477 usec = s->min_latency;
478
479 return usec;
480 }
481
482 pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) {
483 pa_source_output_assert_ref(o);
484
485 usec = fixup_latency(o->source, usec);
486
487 o->thread_info.requested_source_latency = usec;
488 pa_source_invalidate_requested_latency(o->source);
489
490 return usec;
491 }
492
493 pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
494 pa_source_output_assert_ref(o);
495
496 usec = fixup_latency(o->source, usec);
497
498 if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
499 pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL);
500 else {
501 /* If this sink input is not realized yet, we have to touch
502 * the thread info data directly */
503 o->thread_info.requested_source_latency = usec;
504 o->source->thread_info.requested_latency_valid = FALSE;
505 }
506
507 return usec;
508 }
509
510 pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
511 pa_usec_t usec = 0;
512
513 pa_source_output_assert_ref(o);
514
515 if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
516 pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL);
517 else
518 /* If this sink input is not realized yet, we have to touch
519 * the thread info data directly */
520 usec = o->thread_info.requested_source_latency;
521
522 return usec;
523 }
524
525 void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
526 pa_source_output_assert_ref(o);
527 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
528
529 source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING);
530 }
531
532 int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
533 pa_source_output_assert_ref(o);
534 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
535 pa_return_val_if_fail(o->thread_info.resampler, -1);
536
537 if (o->sample_spec.rate == rate)
538 return 0;
539
540 o->sample_spec.rate = rate;
541
542 pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL);
543
544 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
545 return 0;
546 }
547
548 void pa_source_output_set_name(pa_source_output *o, const char *name) {
549 const char *old;
550 pa_source_output_assert_ref(o);
551
552 if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME))
553 return;
554
555 old = pa_proplist_gets(o->proplist, PA_PROP_MEDIA_NAME);
556
557 if (old && name && !strcmp(old, name))
558 return;
559
560 if (name)
561 pa_proplist_sets(o->proplist, PA_PROP_MEDIA_NAME, name);
562 else
563 pa_proplist_unset(o->proplist, PA_PROP_MEDIA_NAME);
564
565 if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
566 pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
567 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
568 }
569 }
570
571 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
572 pa_source_output_assert_ref(o);
573
574 return o->resample_method;
575 }
576
577 int pa_source_output_move_to(pa_source_output *o, pa_source *dest) {
578 pa_source *origin;
579 pa_resampler *new_resampler;
580 pa_source_output_move_hook_data hook_data;
581
582 pa_source_output_assert_ref(o);
583 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
584 pa_source_assert_ref(dest);
585
586 origin = o->source;
587
588 if (dest == origin)
589 return 0;
590
591 if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
592 return -1;
593
594 if (o->direct_on_input)
595 return -1;
596
597 if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
598 pa_log_warn("Failed to move source output: too many outputs per source.");
599 return -1;
600 }
601
602 if (o->thread_info.resampler &&
603 pa_sample_spec_equal(&origin->sample_spec, &dest->sample_spec) &&
604 pa_channel_map_equal(&origin->channel_map, &dest->channel_map))
605
606 /* Try to reuse the old resampler if possible */
607 new_resampler = o->thread_info.resampler;
608
609 else if ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ||
610 !pa_sample_spec_equal(&o->sample_spec, &dest->sample_spec) ||
611 !pa_channel_map_equal(&o->channel_map, &dest->channel_map)) {
612
613 /* Okey, we need a new resampler for the new source */
614
615 if (!(new_resampler = pa_resampler_new(
616 dest->core->mempool,
617 &dest->sample_spec, &dest->channel_map,
618 &o->sample_spec, &o->channel_map,
619 o->resample_method,
620 ((o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
621 ((o->flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
622 (o->core->disable_remixing || (o->flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
623 pa_log_warn("Unsupported resampling operation.");
624 return -1;
625 }
626 } else
627 new_resampler = NULL;
628
629 hook_data.source_output = o;
630 hook_data.destination = dest;
631 pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE], &hook_data);
632
633 /* Okey, let's move it */
634 pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_REMOVE_OUTPUT, o, 0, NULL);
635
636 pa_idxset_remove_by_data(origin->outputs, o, NULL);
637 pa_idxset_put(dest->outputs, o, NULL);
638 o->source = dest;
639
640 if (pa_source_output_get_state(o) == PA_SOURCE_OUTPUT_CORKED) {
641 pa_assert_se(origin->n_corked-- >= 1);
642 dest->n_corked++;
643 }
644
645 /* Replace resampler */
646 if (new_resampler != o->thread_info.resampler) {
647 if (o->thread_info.resampler)
648 pa_resampler_free(o->thread_info.resampler);
649 o->thread_info.resampler = new_resampler;
650
651 pa_memblockq_free(o->thread_info.delay_memblockq);
652
653 o->thread_info.delay_memblockq = pa_memblockq_new(
654 0,
655 MEMBLOCKQ_MAXLENGTH,
656 0,
657 pa_frame_size(&o->source->sample_spec),
658 0,
659 1,
660 0,
661 &o->source->silence);
662 }
663
664 pa_source_update_status(origin);
665 pa_source_update_status(dest);
666
667 pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o->source), PA_SOURCE_MESSAGE_ADD_OUTPUT, o, 0, NULL);
668
669 if (o->moved)
670 o->moved(o);
671
672 pa_hook_fire(&o->source->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST], o);
673
674 pa_log_debug("Successfully moved source output %i from %s to %s.", o->index, origin->name, dest->name);
675
676 /* Notify everyone */
677 pa_subscription_post(o->source->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
678
679 return 0;
680 }
681
682 void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) {
683 pa_source_output_assert_ref(o);
684
685 if (state == o->thread_info.state)
686 return;
687
688 if (o->state_change)
689 o->state_change(o, state);
690
691 o->thread_info.state = state;
692 }
693
694 /* Called from thread context */
695 int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int64_t offset, pa_memchunk* chunk) {
696 pa_source_output *o = PA_SOURCE_OUTPUT(mo);
697
698 pa_source_output_assert_ref(o);
699 pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
700
701 switch (code) {
702
703 case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY: {
704 pa_usec_t *r = userdata;
705
706 *r += pa_bytes_to_usec(pa_memblockq_get_length(o->thread_info.delay_memblockq), &o->source->sample_spec);
707 return 0;
708 }
709
710 case PA_SOURCE_OUTPUT_MESSAGE_SET_RATE:
711
712 o->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
713 pa_resampler_set_output_rate(o->thread_info.resampler, PA_PTR_TO_UINT(userdata));
714 return 0;
715
716 case PA_SOURCE_OUTPUT_MESSAGE_SET_STATE:
717
718 pa_source_output_set_state_within_thread(o, PA_PTR_TO_UINT(userdata));
719 return 0;
720
721 case PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY:
722
723 pa_source_output_set_requested_latency_within_thread(o, (pa_usec_t) offset);
724 return 0;
725
726 case PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY: {
727 pa_usec_t *r = userdata;
728
729 *r = o->thread_info.requested_source_latency;
730 return 0;
731 }
732 }
733
734 return -1;
735 }