]> code.delx.au - pulseaudio/blob - src/modules/module-remap-source.c
alsa-mixer: Add surround 2.1 profile
[pulseaudio] / src / modules / module-remap-source.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2013 bct electronic GmbH
5 Contributor: Stefan Huber <s.huber@bct-electronic.com>
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
29 #include <pulse/xmalloc.h>
30
31 #include <pulsecore/i18n.h>
32 #include <pulsecore/macro.h>
33 #include <pulsecore/namereg.h>
34 #include <pulsecore/module.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/modargs.h>
37 #include <pulsecore/log.h>
38 #include <pulsecore/rtpoll.h>
39 #include <pulsecore/sample-util.h>
40 #include <pulsecore/ltdl-helper.h>
41 #include <pulsecore/mix.h>
42
43 #include "module-remap-source-symdef.h"
44
45 PA_MODULE_AUTHOR("Stefan Huber");
46 PA_MODULE_DESCRIPTION("Virtual channel remapping source");
47 PA_MODULE_VERSION(PACKAGE_VERSION);
48 PA_MODULE_LOAD_ONCE(false);
49 PA_MODULE_USAGE(
50 "source_name=<name for the source> "
51 "source_properties=<properties for the source> "
52 "master=<name of source to filter> "
53 "master_channel_map=<channel map> "
54 "format=<sample format> "
55 "rate=<sample rate> "
56 "channels=<number of channels> "
57 "channel_map=<channel map> "
58 "resample_method=<resampler> "
59 "remix=<remix channels?>");
60
61 struct userdata {
62 pa_module *module;
63
64 pa_source *source;
65 pa_source_output *source_output;
66
67 bool auto_desc;
68 };
69
70 static const char* const valid_modargs[] = {
71 "source_name",
72 "source_properties",
73 "master",
74 "master_channel_map",
75 "format",
76 "rate",
77 "channels",
78 "channel_map",
79 "resample_method",
80 "remix",
81 NULL
82 };
83
84 /* Called from I/O thread context */
85 static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
86 struct userdata *u = PA_SOURCE(o)->userdata;
87
88 switch (code) {
89
90 case PA_SOURCE_MESSAGE_GET_LATENCY:
91
92 /* The source is _put() before the source output is, so let's
93 * make sure we don't access it in that time. Also, the
94 * source output is first shut down, the source second. */
95 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
96 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state)) {
97 *((pa_usec_t*) data) = 0;
98 return 0;
99 }
100
101 *((pa_usec_t*) data) =
102
103 /* Get the latency of the master source */
104 pa_source_get_latency_within_thread(u->source_output->source) +
105 /* Add the latency internal to our source output on top */
106 pa_bytes_to_usec(pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq), &u->source_output->source->sample_spec);
107
108 return 0;
109 }
110
111 return pa_source_process_msg(o, code, data, offset, chunk);
112 }
113
114 /* Called from main context */
115 static int source_set_state_cb(pa_source *s, pa_source_state_t state) {
116 struct userdata *u;
117
118 pa_source_assert_ref(s);
119 pa_assert_se(u = s->userdata);
120
121 if (!PA_SOURCE_IS_LINKED(state) ||
122 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
123 return 0;
124
125 pa_source_output_cork(u->source_output, state == PA_SOURCE_SUSPENDED);
126 return 0;
127 }
128
129 /* Called from I/O thread context */
130 static void source_update_requested_latency_cb(pa_source *s) {
131 struct userdata *u;
132
133 pa_source_assert_ref(s);
134 pa_assert_se(u = s->userdata);
135
136 if (!PA_SOURCE_IS_LINKED(u->source->thread_info.state) ||
137 !PA_SOURCE_OUTPUT_IS_LINKED(u->source_output->thread_info.state))
138 return;
139
140 pa_log_debug("Source update requested latency.");
141
142 /* Just hand this one over to the master source */
143 pa_source_output_set_requested_latency_within_thread(
144 u->source_output,
145 pa_source_get_requested_latency_within_thread(s));
146 }
147
148 /* Called from output thread context */
149 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
150 struct userdata *u;
151
152 pa_source_output_assert_ref(o);
153 pa_source_output_assert_io_context(o);
154 pa_assert_se(u = o->userdata);
155
156 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output))) {
157 pa_log("push when no link?");
158 return;
159 }
160
161 pa_source_post(u->source, chunk);
162 }
163
164 /* Called from output thread context */
165 static void source_output_process_rewind_cb(pa_source_output *o, size_t nbytes) {
166 struct userdata *u;
167
168 pa_source_output_assert_ref(o);
169 pa_source_output_assert_io_context(o);
170 pa_assert_se(u = o->userdata);
171
172 pa_source_process_rewind(u->source, nbytes);
173 }
174
175 /* Called from output thread context */
176 static void source_output_detach_cb(pa_source_output *o) {
177 struct userdata *u;
178
179 pa_source_output_assert_ref(o);
180 pa_source_output_assert_io_context(o);
181 pa_assert_se(u = o->userdata);
182
183 pa_source_detach_within_thread(u->source);
184
185 pa_source_set_rtpoll(u->source, NULL);
186 }
187
188 /* Called from output thread context */
189 static void source_output_attach_cb(pa_source_output *o) {
190 struct userdata *u;
191
192 pa_source_output_assert_ref(o);
193 pa_source_output_assert_io_context(o);
194 pa_assert_se(u = o->userdata);
195
196 pa_source_set_rtpoll(u->source, o->source->thread_info.rtpoll);
197 pa_source_set_latency_range_within_thread(u->source, o->source->thread_info.min_latency, o->source->thread_info.max_latency);
198 pa_source_set_fixed_latency_within_thread(u->source, o->source->thread_info.fixed_latency);
199 pa_source_set_max_rewind_within_thread(u->source, pa_source_output_get_max_rewind(o));
200
201 pa_source_attach_within_thread(u->source);
202 }
203
204 /* Called from main thread */
205 static void source_output_kill_cb(pa_source_output *o) {
206 struct userdata *u;
207
208 pa_source_output_assert_ref(o);
209 pa_assert_ctl_context();
210 pa_assert_se(u = o->userdata);
211
212 /* The order here matters! We first kill the source output, followed
213 * by the source. That means the source callbacks must be protected
214 * against an unconnected source output! */
215 pa_source_output_unlink(u->source_output);
216 pa_source_unlink(u->source);
217
218 pa_source_output_unref(u->source_output);
219 u->source_output = NULL;
220
221 pa_source_unref(u->source);
222 u->source = NULL;
223
224 pa_module_unload_request(u->module, true);
225 }
226
227 /* Called from output thread context */
228 static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
229 struct userdata *u;
230
231 pa_source_output_assert_ref(o);
232 pa_source_output_assert_io_context(o);
233 pa_assert_se(u = o->userdata);
234
235 pa_log_debug("Source output %d state %d.", o->index, state);
236 }
237
238 /* Called from main thread */
239 static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
240 struct userdata *u;
241
242 pa_source_output_assert_ref(o);
243 pa_assert_ctl_context();
244 pa_assert_se(u = o->userdata);
245
246 if (dest) {
247 pa_source_set_asyncmsgq(u->source, dest->asyncmsgq);
248 pa_source_update_flags(u->source, PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY, dest->flags);
249 } else
250 pa_source_set_asyncmsgq(u->source, NULL);
251
252 if (u->auto_desc && dest) {
253 const char *k;
254 pa_proplist *pl;
255
256 pl = pa_proplist_new();
257 k = pa_proplist_gets(dest->proplist, PA_PROP_DEVICE_DESCRIPTION);
258 pa_proplist_setf(pl, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : dest->name);
259
260 pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
261 pa_proplist_free(pl);
262 }
263 }
264
265 int pa__init(pa_module*m) {
266 struct userdata *u;
267 pa_sample_spec ss;
268 pa_resample_method_t resample_method = PA_RESAMPLER_INVALID;
269 pa_channel_map source_map, stream_map;
270 pa_modargs *ma;
271 pa_source *master;
272 pa_source_output_new_data source_output_data;
273 pa_source_new_data source_data;
274 bool remix = true;
275
276 pa_assert(m);
277
278 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
279 pa_log("Failed to parse module arguments.");
280 goto fail;
281 }
282
283 if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SOURCE))) {
284 pa_log("Master source not found.");
285 goto fail;
286 }
287
288 ss = master->sample_spec;
289 source_map = master->channel_map;
290 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &source_map, PA_CHANNEL_MAP_DEFAULT) < 0) {
291 pa_log("Invalid sample format specification or channel map.");
292 goto fail;
293 }
294
295 stream_map = source_map;
296 if (pa_modargs_get_channel_map(ma, "master_channel_map", &stream_map) < 0) {
297 pa_log("Invalid master channel map.");
298 goto fail;
299 }
300
301 if (stream_map.channels != ss.channels) {
302 pa_log("Number of channels doesn't match.");
303 goto fail;
304 }
305
306 if (pa_channel_map_equal(&stream_map, &master->channel_map))
307 pa_log_warn("No remapping configured, proceeding nonetheless!");
308
309 if (pa_modargs_get_value_boolean(ma, "remix", &remix) < 0) {
310 pa_log("Invalid boolean remix parameter.");
311 goto fail;
312 }
313
314 if (pa_modargs_get_resample_method(ma, &resample_method) < 0) {
315 pa_log("Invalid resampling method");
316 goto fail;
317 }
318
319 u = pa_xnew0(struct userdata, 1);
320 u->module = m;
321 m->userdata = u;
322
323 /* Create source */
324 pa_source_new_data_init(&source_data);
325 source_data.driver = __FILE__;
326 source_data.module = m;
327 if (!(source_data.name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL))))
328 source_data.name = pa_sprintf_malloc("%s.remapped", master->name);
329 pa_source_new_data_set_sample_spec(&source_data, &ss);
330 pa_source_new_data_set_channel_map(&source_data, &source_map);
331 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_MASTER_DEVICE, master->name);
332 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "filter");
333
334 if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
335 pa_log("Invalid properties.");
336 pa_source_new_data_done(&source_data);
337 goto fail;
338 }
339
340 if ((u->auto_desc = !pa_proplist_contains(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION))) {
341 const char *k;
342
343 k = pa_proplist_gets(master->proplist, PA_PROP_DEVICE_DESCRIPTION);
344 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Remapped %s", k ? k : master->name);
345 }
346
347 u->source = pa_source_new(m->core, &source_data, master->flags & (PA_SOURCE_LATENCY|PA_SOURCE_DYNAMIC_LATENCY));
348 pa_source_new_data_done(&source_data);
349
350 if (!u->source) {
351 pa_log("Failed to create source.");
352 goto fail;
353 }
354
355 u->source->parent.process_msg = source_process_msg_cb;
356 u->source->set_state = source_set_state_cb;
357 u->source->update_requested_latency = source_update_requested_latency_cb;
358
359 u->source->userdata = u;
360
361 pa_source_set_asyncmsgq(u->source, master->asyncmsgq);
362
363 /* Create source output */
364 pa_source_output_new_data_init(&source_output_data);
365 source_output_data.driver = __FILE__;
366 source_output_data.module = m;
367 pa_source_output_new_data_set_source(&source_output_data, master, false);
368 source_output_data.destination_source = u->source;
369
370 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_NAME, "Remapped Stream");
371 pa_proplist_sets(source_output_data.proplist, PA_PROP_MEDIA_ROLE, "filter");
372 pa_source_output_new_data_set_sample_spec(&source_output_data, &ss);
373 pa_source_output_new_data_set_channel_map(&source_output_data, &stream_map);
374 source_output_data.flags = remix ? 0 : PA_SOURCE_OUTPUT_NO_REMIX;
375 source_output_data.resample_method = resample_method;
376
377 pa_source_output_new(&u->source_output, m->core, &source_output_data);
378 pa_source_output_new_data_done(&source_output_data);
379
380 if (!u->source_output)
381 goto fail;
382
383 u->source_output->push = source_output_push_cb;
384 u->source_output->process_rewind = source_output_process_rewind_cb;
385 u->source_output->kill = source_output_kill_cb;
386 u->source_output->attach = source_output_attach_cb;
387 u->source_output->detach = source_output_detach_cb;
388 u->source_output->state_change = source_output_state_change_cb;
389 u->source_output->moving = source_output_moving_cb;
390 u->source_output->userdata = u;
391
392 u->source->output_from_master = u->source_output;
393
394 pa_source_put(u->source);
395 pa_source_output_put(u->source_output);
396
397 pa_modargs_free(ma);
398
399 return 0;
400
401 fail:
402 if (ma)
403 pa_modargs_free(ma);
404
405 pa__done(m);
406
407 return -1;
408 }
409
410 int pa__get_n_used(pa_module *m) {
411 struct userdata *u;
412
413 pa_assert(m);
414 pa_assert_se(u = m->userdata);
415
416 return pa_source_linked_by(u->source);
417 }
418
419 void pa__done(pa_module*m) {
420 struct userdata *u;
421
422 pa_assert(m);
423
424 if (!(u = m->userdata))
425 return;
426
427 /* See comments in source_output_kill_cb() above regarding
428 * destruction order! */
429
430 if (u->source_output)
431 pa_source_output_unlink(u->source_output);
432
433 if (u->source)
434 pa_source_unlink(u->source);
435
436 if (u->source_output)
437 pa_source_output_unref(u->source_output);
438
439 if (u->source)
440 pa_source_unref(u->source);
441
442 pa_xfree(u);
443 }