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
37 #include <pulse/timeval.h>
38 #include <pulse/xmalloc.h>
40 #include <pulsecore/macro.h>
41 #include <pulsecore/iochannel.h>
42 #include <pulsecore/sink.h>
43 #include <pulsecore/module.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/modargs.h>
46 #include <pulsecore/log.h>
48 #include "module-null-sink-symdef.h"
50 PA_MODULE_AUTHOR("Lennart Poettering")
51 PA_MODULE_DESCRIPTION("Clocked NULL sink")
52 PA_MODULE_VERSION(PACKAGE_VERSION)
54 "format=<sample format> "
55 "channels=<number of channels> "
57 "sink_name=<name of sink>"
58 "channel_map=<channel map>"
59 "description=<description for the sink>")
61 #define DEFAULT_SINK_NAME "null"
69 struct timeval timestamp;
72 static const char* const valid_modargs[] = {
82 static void thread_func(void *userdata) {
83 struct userdata *u = userdata;
90 pa_log_debug("Thread starting up");
92 memset(&pollfd, 0, sizeof(pollfd));
93 pollfd.fd = pa_asyncmsgq_get_fd(u->sink->asyncmsgq, PA_ASYNCQ_POP);
94 pollfd.events = POLLIN;
96 pa_gettimeofday(u->timestamp);
104 /* Check whether there is a message for us to process */
105 if (pa_asyncmsgq_get(u->sink->asyncmsgq, &object, &code, &data) == 0) {
108 /* Now process these messages our own way */
112 case PA_MESSAGE_SHUTDOWN:
116 pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
120 } else if (object == u->sink) {
123 case PA_SINK_MESSAGE_STOP:
128 case PA_SINK_MESSAGE_START:
132 pa_gettimeofday(u->timestamp);
135 case PA_SINK_MESSAGE_GET_LATENCY:
137 if (pa_timeval_cmp(&u->timestamp, &now) > 0)
138 *((pa_usec_t*) data) = 0;
140 *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
146 pa_sink_process_msg(u->sink->asyncmsgq, object, code, data);
150 pa_asyncmsgq_done(u->sink->asyncmsgq);
154 /* Render some data and drop it immediately */
157 pa_gettimeofday(&now);
159 if (pa_timeval_cmp(u->timestamp, &now) <= 0) {
163 if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) {
165 pa_memblock_unref(chunk.memblock);
169 pa_timeval_add(&u->timestamp, pa_bytes_to_usec(l, &u->sink->sample_spec));
173 timeout = pa_timeval_diff(&u->timestamp, &now)/1000;
180 /* Hmm, nothing to do. Let's sleep */
182 if (pa_asyncmsgq_before_poll(u->sink->asyncmsgq) < 0)
185 r = poll(&pollfd, 1, timeout);
186 pa_asyncmsgq_after_poll(u->sink->asyncmsgq);
192 pa_log("poll() failed: %s", pa_cstrerror(errno));
196 pa_assert(r == 0 || pollfd.revents == POLLIN);
200 /* We have to continue processing messages until we receive the
201 * SHUTDOWN message */
202 pa_asyncmsgq_post(u->core->asyncmsgq, u->core, PA_CORE_MESSAGE_UNLOAD_MODULE, pa_module_ref(u->module), NULL, pa_module_unref);
203 pa_asyncmsgq_wait_for(PA_MESSAGE_SHUTDOWN);
206 pa_log_debug("Thread shutting down");
209 int pa__init(pa_core *c, pa_module*m) {
210 struct userdata *u = NULL;
213 pa_modargs *ma = NULL;
218 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
219 pa_log("Failed to parse module arguments.");
223 ss = c->default_sample_spec;
224 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
225 pa_log("Invalid sample format specification or channel map");
229 u = pa_xnew0(struct userdata, 1);
234 if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
235 pa_log("Failed to create sink.");
239 u->sink->userdata = u;
240 pa_sink_set_owner(u->sink, m);
241 pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));
243 u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
245 if (u->block_size <= 0)
246 u->block_size = pa_frame_size(&ss);
248 if (!(u->thread = pa_thread_new(thread_func, u))) {
249 pa_log("Failed to create thread.");
266 void pa__done(pa_core *c, pa_module*m) {
272 if (!(u = m->userdata))
275 pa_sink_disconnect(u->sink);
278 pa_asyncmsgq_send(u->sink->asyncmsgq, PA_SINK_MESSAGE_SHUTDOWN, NULL);
279 pa_thread_free(u->thread);
282 pa_sink_unref(u->sink);