4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
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 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
28 #include <pulse/xmalloc.h>
30 #include <pulsecore/core-error.h>
31 #include <pulsecore/namereg.h>
32 #include <pulsecore/sink.h>
33 #include <pulsecore/module.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/modargs.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/thread.h>
38 #include <pulsecore/thread-mq.h>
39 #include <pulsecore/rtpoll.h>
41 #include "module-remap-sink-symdef.h"
43 PA_MODULE_AUTHOR("Lennart Poettering")
44 PA_MODULE_DESCRIPTION("Virtual channel remapping sink")
45 PA_MODULE_VERSION(PACKAGE_VERSION
)
47 "sink_name=<name for the sink> "
48 "master=<name of sink to remap> "
49 "master_channel_map=<channel map> "
50 "format=<sample format> "
51 "channels=<number of channels> "
53 "channel_map=<channel map>")
59 pa_sink
*sink
, *master
;
60 pa_sink_input
*sink_input
;
65 static const char* const valid_modargs
[] = {
76 /* Called from I/O thread context */
77 static int sink_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
78 struct userdata
*u
= PA_SINK(o
)->userdata
;
82 case PA_SINK_MESSAGE_GET_LATENCY
: {
85 if (PA_MSGOBJECT(u
->master
)->process_msg(PA_MSGOBJECT(u
->master
), PA_SINK_MESSAGE_GET_LATENCY
, &usec
, 0, NULL
) < 0)
88 *((pa_usec_t
*) data
) = usec
+ pa_bytes_to_usec(u
->memchunk
.length
, &u
->sink
->sample_spec
);
93 return pa_sink_process_msg(o
, code
, data
, offset
, chunk
);
96 /* Called from main context */
97 static int sink_set_state(pa_sink
*s
, pa_sink_state_t state
) {
100 pa_sink_assert_ref(s
);
101 pa_assert_se(u
= s
->userdata
);
103 if (PA_SINK_LINKED(state
) && u
->sink_input
)
104 pa_sink_input_cork(u
->sink_input
, state
== PA_SINK_SUSPENDED
);
109 /* Called from I/O thread context */
110 static int sink_input_process_msg(pa_msgobject
*o
, int code
, void *data
, int64_t offset
, pa_memchunk
*chunk
) {
111 struct userdata
*u
= PA_SINK_INPUT(o
)->userdata
;
114 case PA_SINK_INPUT_MESSAGE_GET_LATENCY
:
115 *((pa_usec_t
*) data
) = pa_bytes_to_usec(u
->memchunk
.length
, &u
->sink_input
->sample_spec
);
117 /* Fall through, the default handler will add in the extra
118 * latency added by the resampler */
122 return pa_sink_input_process_msg(o
, code
, data
, offset
, chunk
);
125 /* Called from I/O thread context */
126 static int sink_input_peek_cb(pa_sink_input
*i
, size_t length
, pa_memchunk
*chunk
) {
129 pa_sink_input_assert_ref(i
);
130 pa_assert_se(u
= i
->userdata
);
132 if (!u
->memchunk
.memblock
)
133 pa_sink_render(u
->sink
, length
, &u
->memchunk
);
135 pa_assert(u
->memchunk
.memblock
);
136 *chunk
= u
->memchunk
;
137 pa_memblock_ref(chunk
->memblock
);
141 /* Called from I/O thread context */
142 static void sink_input_drop_cb(pa_sink_input
*i
, size_t length
) {
145 pa_sink_input_assert_ref(i
);
146 pa_assert_se(u
= i
->userdata
);
147 pa_assert(length
> 0);
149 if (u
->memchunk
.memblock
) {
151 if (length
< u
->memchunk
.length
) {
152 u
->memchunk
.index
+= length
;
153 u
->memchunk
.length
-= length
;
157 pa_memblock_unref(u
->memchunk
.memblock
);
158 length
-= u
->memchunk
.length
;
159 pa_memchunk_reset(&u
->memchunk
);
163 pa_sink_skip(u
->sink
, length
);
166 /* Called from I/O thread context */
167 static void sink_input_detach_cb(pa_sink_input
*i
) {
170 pa_sink_input_assert_ref(i
);
171 pa_assert_se(u
= i
->userdata
);
173 pa_sink_detach_within_thread(u
->sink
);
176 /* Called from I/O thread context */
177 static void sink_input_attach_cb(pa_sink_input
*i
) {
180 pa_sink_input_assert_ref(i
);
181 pa_assert_se(u
= i
->userdata
);
183 pa_sink_set_asyncmsgq(u
->sink
, i
->sink
->asyncmsgq
);
184 pa_sink_set_rtpoll(u
->sink
, i
->sink
->rtpoll
);
186 pa_sink_attach_within_thread(u
->sink
);
189 /* Called from main context */
190 static void sink_input_kill_cb(pa_sink_input
*i
) {
193 pa_sink_input_assert_ref(i
);
194 pa_assert_se(u
= i
->userdata
);
196 pa_sink_input_unlink(u
->sink_input
);
197 pa_sink_input_unref(u
->sink_input
);
198 u
->sink_input
= NULL
;
200 pa_sink_unlink(u
->sink
);
201 pa_sink_unref(u
->sink
);
204 pa_module_unload_request(u
->module
);
207 int pa__init(pa_module
*m
) {
210 pa_channel_map sink_map
, stream_map
;
214 pa_sink_input_new_data data
;
215 char *default_sink_name
= NULL
;
219 if (!(ma
= pa_modargs_new(m
->argument
, valid_modargs
))) {
220 pa_log("Failed to parse module arguments.");
224 if (!(master
= pa_namereg_get(m
->core
, pa_modargs_get_value(ma
, "master", NULL
), PA_NAMEREG_SINK
, 1))) {
225 pa_log("Master sink not found");
229 ss
= master
->sample_spec
;
230 sink_map
= master
->channel_map
;
231 if (pa_modargs_get_sample_spec_and_channel_map(ma
, &ss
, &sink_map
, PA_CHANNEL_MAP_DEFAULT
) < 0) {
232 pa_log("Invalid sample format specification or channel map");
236 stream_map
= sink_map
;
237 if (pa_modargs_get_channel_map(ma
, "master_channel_map", &stream_map
) < 0) {
238 pa_log("Invalid master hannel map");
242 if (stream_map
.channels
!= ss
.channels
) {
243 pa_log("Number of channels doesn't match");
247 u
= pa_xnew0(struct userdata
, 1);
252 pa_memchunk_reset(&u
->memchunk
);
254 default_sink_name
= pa_sprintf_malloc("%s.remapped", master
->name
);
257 if (!(u
->sink
= pa_sink_new(m
->core
, __FILE__
, pa_modargs_get_value(ma
, "sink_name", default_sink_name
), 0, &ss
, &sink_map
))) {
258 pa_log("Failed to create sink.");
262 u
->sink
->parent
.process_msg
= sink_process_msg
;
263 u
->sink
->set_state
= sink_set_state
;
264 u
->sink
->userdata
= u
;
265 u
->sink
->flags
= PA_SINK_LATENCY
;
267 pa_sink_set_module(u
->sink
, m
);
268 pa_sink_set_description(u
->sink
, t
= pa_sprintf_malloc("Remapped %s", master
->description
));
270 pa_sink_set_asyncmsgq(u
->sink
, master
->asyncmsgq
);
271 pa_sink_set_rtpoll(u
->sink
, master
->rtpoll
);
273 /* Create sink input */
274 pa_sink_input_new_data_init(&data
);
275 data
.sink
= u
->master
;
276 data
.driver
= __FILE__
;
277 data
.name
= "Remapped Stream";
278 pa_sink_input_new_data_set_sample_spec(&data
, &ss
);
279 pa_sink_input_new_data_set_channel_map(&data
, &stream_map
);
282 if (!(u
->sink_input
= pa_sink_input_new(m
->core
, &data
, PA_SINK_INPUT_DONT_MOVE
)))
285 u
->sink_input
->parent
.process_msg
= sink_input_process_msg
;
286 u
->sink_input
->peek
= sink_input_peek_cb
;
287 u
->sink_input
->drop
= sink_input_drop_cb
;
288 u
->sink_input
->kill
= sink_input_kill_cb
;
289 u
->sink_input
->attach
= sink_input_attach_cb
;
290 u
->sink_input
->detach
= sink_input_detach_cb
;
291 u
->sink_input
->userdata
= u
;
293 pa_sink_put(u
->sink
);
294 pa_sink_input_put(u
->sink_input
);
297 pa_xfree(default_sink_name
);
307 pa_xfree(default_sink_name
);
312 void pa__done(pa_module
*m
) {
317 if (!(u
= m
->userdata
))
321 pa_sink_input_unlink(u
->sink_input
);
322 pa_sink_input_unref(u
->sink_input
);
326 pa_sink_unlink(u
->sink
);
327 pa_sink_unref(u
->sink
);
330 if (u
->memchunk
.memblock
)
331 pa_memblock_unref(u
->memchunk
.memblock
);