2 This file is part of PulseAudio.
4 Copyright 2013 bct electronic GmbH
5 Contributor: Stefan Huber <s.huber@bct-electronic.com>
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2.1 of the License,
11 or (at your option) any later version.
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 #include <pulse/xmalloc.h>
32 #include <pulsecore/i18n.h>
33 #include <pulsecore/macro.h>
34 #include <pulsecore/namereg.h>
35 #include <pulsecore/module.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/modargs.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/rtpoll.h>
40 #include <pulsecore/sample-util.h>
41 #include <pulsecore/ltdl-helper.h>
42 #include <pulsecore/mix.h>
44 #include "module-remap-source-symdef.h"
46 PA_MODULE_AUTHOR("Stefan Huber");
47 PA_MODULE_DESCRIPTION("Virtual channel remapping source");
48 PA_MODULE_VERSION(PACKAGE_VERSION
);
49 PA_MODULE_LOAD_ONCE(false);
51 "source_name=<name for the source> "
52 "source_properties=<properties for the source> "
53 "master=<name of source to filter> "
54 "master_channel_map=<channel map> "
55 "format=<sample format> "
57 "channels=<number of channels> "
58 "channel_map=<channel map> "
59 "remix=<remix channels?>");
65 pa_source_output
*source_output
;
70 static const char* const valid_modargs
[] = {
83 /* Called from I/O thread context */
84 static int source_process_msg_cb(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
85 struct userdata
*u
= PA_SOURCE(o
)->userdata
;
89 case PA_SOURCE_MESSAGE_GET_LATENCY
:
91 /* The source is _put() before the source output is, so let's
92 * make sure we don't access it in that time. Also, the
93 * source output is first shut down, the source second. */
94 if (!PA_SOURCE_IS_LINKED(u
->source
->thread_info
.state
) ||
95 !PA_SOURCE_OUTPUT_IS_LINKED(u
->source_output
->thread_info
.state
)) {
96 *((pa_usec_t
*) data
) = 0;
100 *((pa_usec_t
*) data
) =
102 /* Get the latency of the master source */
103 pa_source_get_latency_within_thread(u
->source_output
->source
) +
104 /* Add the latency internal to our source output on top */
105 pa_bytes_to_usec(pa_memblockq_get_length(u
->source_output
->thread_info
.delay_memblockq
), &u
->source_output
->source
->sample_spec
);
110 return pa_source_process_msg(o
, code
, data
, offset
, chunk
);
113 /* Called from main context */
114 static int source_set_state_cb(pa_source
*s
, pa_source_state_t state
) {
117 pa_source_assert_ref(s
);
118 pa_assert_se(u
= s
->userdata
);
120 if (!PA_SOURCE_IS_LINKED(state
) ||
121 !PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
)))
124 pa_source_output_cork(u
->source_output
, state
== PA_SOURCE_SUSPENDED
);
128 /* Called from I/O thread context */
129 static void source_update_requested_latency_cb(pa_source
*s
) {
132 pa_source_assert_ref(s
);
133 pa_assert_se(u
= s
->userdata
);
135 if (!PA_SOURCE_IS_LINKED(u
->source
->thread_info
.state
) ||
136 !PA_SOURCE_OUTPUT_IS_LINKED(u
->source_output
->thread_info
.state
))
139 pa_log_debug("Source update requested latency.");
141 /* Just hand this one over to the master source */
142 pa_source_output_set_requested_latency_within_thread(
144 pa_source_get_requested_latency_within_thread(s
));
147 /* Called from output thread context */
148 static void source_output_push_cb(pa_source_output
*o
, const pa_memchunk
*chunk
) {
151 pa_source_output_assert_ref(o
);
152 pa_source_output_assert_io_context(o
);
153 pa_assert_se(u
= o
->userdata
);
155 if (!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u
->source_output
))) {
156 pa_log("push when no link?");
160 pa_source_post(u
->source
, chunk
);
163 /* Called from output thread context */
164 static void source_output_process_rewind_cb(pa_source_output
*o
, size_t nbytes
) {
167 pa_source_output_assert_ref(o
);
168 pa_source_output_assert_io_context(o
);
169 pa_assert_se(u
= o
->userdata
);
171 pa_source_process_rewind(u
->source
, nbytes
);
174 /* Called from output thread context */
175 static void source_output_detach_cb(pa_source_output
*o
) {
178 pa_source_output_assert_ref(o
);
179 pa_source_output_assert_io_context(o
);
180 pa_assert_se(u
= o
->userdata
);
182 pa_source_detach_within_thread(u
->source
);
184 pa_source_set_rtpoll(u
->source
, NULL
);
187 /* Called from output thread context */
188 static void source_output_attach_cb(pa_source_output
*o
) {
191 pa_source_output_assert_ref(o
);
192 pa_source_output_assert_io_context(o
);
193 pa_assert_se(u
= o
->userdata
);
195 pa_source_set_rtpoll(u
->source
, o
->source
->thread_info
.rtpoll
);
196 pa_source_set_latency_range_within_thread(u
->source
, o
->source
->thread_info
.min_latency
, o
->source
->thread_info
.max_latency
);
197 pa_source_set_fixed_latency_within_thread(u
->source
, o
->source
->thread_info
.fixed_latency
);
198 pa_source_set_max_rewind_within_thread(u
->source
, pa_source_output_get_max_rewind(o
));
200 pa_source_attach_within_thread(u
->source
);
203 /* Called from main thread */
204 static void source_output_kill_cb(pa_source_output
*o
) {
207 pa_source_output_assert_ref(o
);
208 pa_assert_ctl_context();
209 pa_assert_se(u
= o
->userdata
);
211 /* The order here matters! We first kill the source output, followed
212 * by the source. That means the source callbacks must be protected
213 * against an unconnected source output! */
214 pa_source_output_unlink(u
->source_output
);
215 pa_source_unlink(u
->source
);
217 pa_source_output_unref(u
->source_output
);
218 u
->source_output
= NULL
;
220 pa_source_unref(u
->source
);
223 pa_module_unload_request(u
->module
, true);
226 /* Called from output thread context */
227 static void source_output_state_change_cb(pa_source_output
*o
, pa_source_output_state_t state
) {
230 pa_source_output_assert_ref(o
);
231 pa_source_output_assert_io_context(o
);
232 pa_assert_se(u
= o
->userdata
);
234 pa_log_debug("Source output %d state %d.", o
->index
, state
);
237 /* Called from main thread */
238 static void source_output_moving_cb(pa_source_output
*o
, pa_source
*dest
) {
241 pa_source_output_assert_ref(o
);
242 pa_assert_ctl_context();
243 pa_assert_se(u
= o
->userdata
);
246 pa_source_set_asyncmsgq(u
->source
, dest
->asyncmsgq
);
247 pa_source_update_flags(u
->source
, PA_SOURCE_LATENCY
|PA_SOURCE_DYNAMIC_LATENCY
, dest
->flags
);
249 pa_source_set_asyncmsgq(u
->source
, NULL
);
251 if (u
->auto_desc
&& dest
) {
255 pl
= pa_proplist_new();
256 k
= pa_proplist_gets(dest
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
257 pa_proplist_setf(pl
, PA_PROP_DEVICE_DESCRIPTION
, "Remapped %s", k
? k
: dest
->name
);
259 pa_source_update_proplist(u
->source
, PA_UPDATE_REPLACE
, pl
);
260 pa_proplist_free(pl
);
264 int pa__init(pa_module
*m
) {
267 pa_channel_map source_map
, stream_map
;
270 pa_source_output_new_data source_output_data
;
271 pa_source_new_data source_data
;
276 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
277 pa_log("Failed to parse module arguments.");
281 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SOURCE
))) {
282 pa_log("Master source not found.");
286 ss
= master
->sample_spec
;
287 source_map
= master
->channel_map
;
288 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &source_map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
289 pa_log("Invalid sample format specification or channel map.");
293 stream_map
= source_map
;
294 if (pa_modargs_get_channel_map(ma
, "master_channel_map", &stream_map
) < 0) {
295 pa_log("Invalid master channel map.");
299 if (stream_map
.channels
!= ss
.channels
) {
300 pa_log("Number of channels doesn't match.");
304 if (pa_channel_map_equal(&stream_map
, &master
->channel_map
))
305 pa_log_warn("No remapping configured, proceeding nonetheless!");
307 if (pa_modargs_get_value_boolean(ma
, "remix", &remix
) < 0) {
308 pa_log("Invalid boolean remix parameter.");
312 u
= pa_xnew0(struct userdata
, 1);
317 pa_source_new_data_init(&source_data
);
318 source_data
.driver
= __FILE__
;
319 source_data
.module
= m
;
320 if (!(source_data
.name
= pa_xstrdup(pa_modargs_get_value(ma
, "source_name", NULL
))))
321 source_data
.name
= pa_sprintf_malloc("%s.remapped", master
->name
);
322 pa_source_new_data_set_sample_spec(&source_data
, &ss
);
323 pa_source_new_data_set_channel_map(&source_data
, &source_map
);
324 pa_proplist_sets(source_data
.proplist
, PA_PROP_DEVICE_MASTER_DEVICE
, master
->name
);
325 pa_proplist_sets(source_data
.proplist
, PA_PROP_DEVICE_CLASS
, "filter");
327 if (pa_modargs_get_proplist(ma
, "source_properties", source_data
.proplist
, PA_UPDATE_REPLACE
) < 0) {
328 pa_log("Invalid properties.");
329 pa_source_new_data_done(&source_data
);
333 if ((u
->auto_desc
= !pa_proplist_contains(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
))) {
336 k
= pa_proplist_gets(master
->proplist
, PA_PROP_DEVICE_DESCRIPTION
);
337 pa_proplist_setf(source_data
.proplist
, PA_PROP_DEVICE_DESCRIPTION
, "Remapped %s", k
? k
: master
->name
);
340 u
->source
= pa_source_new(m
->core
, &source_data
, master
->flags
& (PA_SOURCE_LATENCY
|PA_SOURCE_DYNAMIC_LATENCY
));
341 pa_source_new_data_done(&source_data
);
344 pa_log("Failed to create source.");
348 u
->source
->parent
.process_msg
= source_process_msg_cb
;
349 u
->source
->set_state
= source_set_state_cb
;
350 u
->source
->update_requested_latency
= source_update_requested_latency_cb
;
352 u
->source
->userdata
= u
;
354 pa_source_set_asyncmsgq(u
->source
, master
->asyncmsgq
);
356 /* Create source output */
357 pa_source_output_new_data_init(&source_output_data
);
358 source_output_data
.driver
= __FILE__
;
359 source_output_data
.module
= m
;
360 pa_source_output_new_data_set_source(&source_output_data
, master
, false);
361 source_output_data
.destination_source
= u
->source
;
363 pa_proplist_sets(source_output_data
.proplist
, PA_PROP_MEDIA_NAME
, "Remapped Stream");
364 pa_proplist_sets(source_output_data
.proplist
, PA_PROP_MEDIA_ROLE
, "filter");
365 pa_source_output_new_data_set_sample_spec(&source_output_data
, &ss
);
366 pa_source_output_new_data_set_channel_map(&source_output_data
, &stream_map
);
367 source_output_data
.flags
= remix
? 0 : PA_SOURCE_OUTPUT_NO_REMIX
;
369 pa_source_output_new(&u
->source_output
, m
->core
, &source_output_data
);
370 pa_source_output_new_data_done(&source_output_data
);
372 if (!u
->source_output
)
375 u
->source_output
->push
= source_output_push_cb
;
376 u
->source_output
->process_rewind
= source_output_process_rewind_cb
;
377 u
->source_output
->kill
= source_output_kill_cb
;
378 u
->source_output
->attach
= source_output_attach_cb
;
379 u
->source_output
->detach
= source_output_detach_cb
;
380 u
->source_output
->state_change
= source_output_state_change_cb
;
381 u
->source_output
->moving
= source_output_moving_cb
;
382 u
->source_output
->userdata
= u
;
384 u
->source
->output_from_master
= u
->source_output
;
386 pa_source_put(u
->source
);
387 pa_source_output_put(u
->source_output
);
402 int pa__get_n_used(pa_module
*m
) {
406 pa_assert_se(u
= m
->userdata
);
408 return pa_source_linked_by(u
->source
);
411 void pa__done(pa_module
*m
) {
416 if (!(u
= m
->userdata
))
419 /* See comments in source_output_kill_cb() above regarding
420 * destruction order! */
422 if (u
->source_output
)
423 pa_source_output_unlink(u
->source_output
);
426 pa_source_unlink(u
->source
);
428 if (u
->source_output
)
429 pa_source_output_unref(u
->source_output
);
432 pa_source_unref(u
->source
);