2 This file is part of PulseAudio.
4 Copyright 2013 bct electronic GmbH
5 Contributor: Stefan Huber <s.huber@bct-electronic.com>
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.
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.
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
29 #include <pulse/xmalloc.h>
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>
43 #include "module-remap-source-symdef.h"
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);
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> "
56 "channels=<number of channels> "
57 "channel_map=<channel map> "
58 "resample_method=<resampler> "
59 "remix=<remix channels?>");
65 pa_source_output
*source_output
;
70 static const char* const valid_modargs
[] = {
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
;
90 case PA_SOURCE_MESSAGE_GET_LATENCY
:
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;
101 *((pa_usec_t
*) data
) =
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
);
111 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
114 /* Called from main context */
115 static int source_set_state_cb(pa_source
*s
, pa_source_state_t state
) {
118 pa_source_assert_ref(s
);
119 pa_assert_se(u
= s
->userdata
);
121 if (!PA_SOURCE_IS_LINKED(state
) ||
122 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
125 pa_source_output_cork(u
->source_output
, state
== PA_SOURCE_SUSPENDED
);
129 /* Called from I/O thread context */
130 static void source_update_requested_latency_cb(pa_source
*s
) {
133 pa_source_assert_ref(s
);
134 pa_assert_se(u
= s
->userdata
);
136 if (!PA_SOURCE_IS_LINKED(u
->source
->thread_info
.state
) ||
137 !PA_SOURCE_OUTPUT_IS_LINKED(u
->source_output
->thread_info
.state
))
140 pa_log_debug("Source update requested latency.");
142 /* Just hand this one over to the master source */
143 pa_source_output_set_requested_latency_within_thread(
145 pa_source_get_requested_latency_within_thread(s
));
148 /* Called from output thread context */
149 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
152 pa_source_output_assert_ref(o
);
153 pa_source_output_assert_io_context(o
);
154 pa_assert_se(u
= o
->userdata
);
156 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
))) {
157 pa_log("push when no link?");
161 pa_source_post(u
->source
, chunk
);
164 /* Called from output thread context */
165 static void source_output_process_rewind_cb(pa_source_output
*o
, size_t nbytes
) {
168 pa_source_output_assert_ref(o
);
169 pa_source_output_assert_io_context(o
);
170 pa_assert_se(u
= o
->userdata
);
172 pa_source_process_rewind(u
->source
, nbytes
);
175 /* Called from output thread context */
176 static void source_output_detach_cb(pa_source_output
*o
) {
179 pa_source_output_assert_ref(o
);
180 pa_source_output_assert_io_context(o
);
181 pa_assert_se(u
= o
->userdata
);
183 pa_source_detach_within_thread(u
->source
);
185 pa_source_set_rtpoll(u
->source
, NULL
);
188 /* Called from output thread context */
189 static void source_output_attach_cb(pa_source_output
*o
) {
192 pa_source_output_assert_ref(o
);
193 pa_source_output_assert_io_context(o
);
194 pa_assert_se(u
= o
->userdata
);
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
));
201 pa_source_attach_within_thread(u
->source
);
204 /* Called from main thread */
205 static void source_output_kill_cb(pa_source_output
*o
) {
208 pa_source_output_assert_ref(o
);
209 pa_assert_ctl_context();
210 pa_assert_se(u
= o
->userdata
);
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
);
218 pa_source_output_unref(u
->source_output
);
219 u
->source_output
= NULL
;
221 pa_source_unref(u
->source
);
224 pa_module_unload_request(u
->module
, true);
227 /* Called from output thread context */
228 static void source_output_state_change_cb(pa_source_output
*o
, pa_source_output_state_t state
) {
231 pa_source_output_assert_ref(o
);
232 pa_source_output_assert_io_context(o
);
233 pa_assert_se(u
= o
->userdata
);
235 pa_log_debug("Source output %d state %d.", o
->index
, state
);
238 /* Called from main thread */
239 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
242 pa_source_output_assert_ref(o
);
243 pa_assert_ctl_context();
244 pa_assert_se(u
= o
->userdata
);
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
);
250 pa_source_set_asyncmsgq(u
->source
, NULL
);
252 if (u
->auto_desc
&& dest
) {
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
);
260 pa_source_update_proplist(u
->source
, PA_UPDATE_REPLACE
, pl
);
261 pa_proplist_free(pl
);
265 int pa__init(pa_module
*m
) {
268 pa_resample_method_t resample_method
= PA_RESAMPLER_INVALID
;
269 pa_channel_map source_map
, stream_map
;
272 pa_source_output_new_data source_output_data
;
273 pa_source_new_data source_data
;
278 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
279 pa_log("Failed to parse module arguments.");
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.");
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.");
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.");
301 if (stream_map
.channels
!= ss
.channels
) {
302 pa_log("Number of channels doesn't match.");
306 if (pa_channel_map_equal(&stream_map
, &master
->channel_map
))
307 pa_log_warn("No remapping configured, proceeding nonetheless!");
309 if (pa_modargs_get_value_boolean(ma
, "remix", &remix
) < 0) {
310 pa_log("Invalid boolean remix parameter.");
314 if (pa_modargs_get_resample_method(ma
, &resample_method
) < 0) {
315 pa_log("Invalid resampling method");
319 u
= pa_xnew0(struct userdata
, 1);
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");
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
);
340 if ((u
->auto_desc
= !pa_proplist_contains(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
))) {
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
);
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
);
351 pa_log("Failed to create source.");
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
;
359 u
->source
->userdata
= u
;
361 pa_source_set_asyncmsgq(u
->source
, master
->asyncmsgq
);
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
;
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
;
377 pa_source_output_new(&u
->source_output
, m
->core
, &source_output_data
);
378 pa_source_output_new_data_done(&source_output_data
);
380 if (!u
->source_output
)
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
;
392 u
->source
->output_from_master
= u
->source_output
;
394 pa_source_put(u
->source
);
395 pa_source_output_put(u
->source_output
);
410 int pa__get_n_used(pa_module
*m
) {
414 pa_assert_se(u
= m
->userdata
);
416 return pa_source_linked_by(u
->source
);
419 void pa__done(pa_module
*m
) {
424 if (!(u
= m
->userdata
))
427 /* See comments in source_output_kill_cb() above regarding
428 * destruction order! */
430 if (u
->source_output
)
431 pa_source_output_unlink(u
->source_output
);
434 pa_source_unlink(u
->source
);
436 if (u
->source_output
)
437 pa_source_output_unref(u
->source_output
);
440 pa_source_unref(u
->source
);