]> code.delx.au - pulseaudio/blob - src/modules/module-null-sink.c
A lot of more work to get the lock-free stuff in place
[pulseaudio] / src / modules / module-null-sink.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7
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.
12
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.
17
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
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <sys/stat.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <limits.h>
36 #include <sys/poll.h>
37
38 #include <pulse/timeval.h>
39 #include <pulse/xmalloc.h>
40
41 #include <pulsecore/macro.h>
42 #include <pulsecore/sink.h>
43 #include <pulsecore/module.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/core-error.h>
46 #include <pulsecore/modargs.h>
47 #include <pulsecore/log.h>
48 #include <pulsecore/thread.h>
49
50 #include "module-null-sink-symdef.h"
51
52 PA_MODULE_AUTHOR("Lennart Poettering")
53 PA_MODULE_DESCRIPTION("Clocked NULL sink")
54 PA_MODULE_VERSION(PACKAGE_VERSION)
55 PA_MODULE_USAGE(
56 "format=<sample format> "
57 "channels=<number of channels> "
58 "rate=<sample rate> "
59 "sink_name=<name of sink>"
60 "channel_map=<channel map>"
61 "description=<description for the sink>")
62
63 #define DEFAULT_SINK_NAME "null"
64
65 struct userdata {
66 pa_core *core;
67 pa_module *module;
68 pa_sink *sink;
69 pa_thread *thread;
70 pa_asyncmsgq *asyncmsgq;
71 size_t block_size;
72
73 struct timeval timestamp;
74 };
75
76 static const char* const valid_modargs[] = {
77 "rate",
78 "format",
79 "channels",
80 "sink_name",
81 "channel_map",
82 "description",
83 NULL
84 };
85
86 static int sink_process_msg(pa_msgobject *o, int code, void *data, pa_memchunk *chunk) {
87 struct userdata *u = PA_SINK(o)->userdata;
88
89 switch (code) {
90 case PA_SINK_MESSAGE_SET_STATE:
91
92 if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING)
93 pa_gettimeofday(&u->timestamp);
94
95 break;
96
97 case PA_SINK_MESSAGE_GET_LATENCY: {
98 struct timeval now;
99
100 pa_gettimeofday(&now);
101
102 if (pa_timeval_cmp(&u->timestamp, &now) > 0)
103 *((pa_usec_t*) data) = 0;
104 else
105 *((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
106 break;
107 }
108 }
109
110 return pa_sink_process_msg(o, code, data, chunk);
111 }
112
113 static void thread_func(void *userdata) {
114 struct userdata *u = userdata;
115 struct pollfd pollfd;
116
117 pa_assert(u);
118
119 pa_log_debug("Thread starting up");
120
121 pa_gettimeofday(&u->timestamp);
122
123 memset(&pollfd, 0, sizeof(pollfd));
124 pollfd.fd = pa_asyncmsgq_get_fd(u->asyncmsgq);
125 pollfd.events = POLLIN;
126
127 for (;;) {
128 pa_msgobject *object;
129 int code;
130 void *data;
131 pa_memchunk chunk;
132 int r, timeout;
133 struct timeval now;
134
135 /* Check whether there is a message for us to process */
136 if (pa_asyncmsgq_get(u->asyncmsgq, &object, &code, &data, &chunk, 0) == 0) {
137 int ret;
138
139 if (!object && code == PA_MESSAGE_SHUTDOWN) {
140 pa_asyncmsgq_done(u->asyncmsgq, 0);
141 goto finish;
142 }
143
144 ret = pa_asyncmsgq_dispatch(object, code, data, &chunk);
145 pa_asyncmsgq_done(u->asyncmsgq, ret);
146 continue;
147 }
148
149 /* Render some data and drop it immediately */
150 if (u->sink->thread_info.state == PA_SINK_RUNNING) {
151 pa_gettimeofday(&now);
152
153 if (pa_timeval_cmp(&u->timestamp, &now) <= 0) {
154 size_t l;
155
156 if (pa_sink_render(u->sink, u->block_size, &chunk) >= 0) {
157 l = chunk.length;
158 pa_memblock_unref(chunk.memblock);
159 } else
160 l = u->block_size;
161
162 pa_timeval_add(&u->timestamp, pa_bytes_to_usec(l, &u->sink->sample_spec));
163 continue;
164 }
165
166 timeout = pa_timeval_diff(&u->timestamp, &now)/1000;
167
168 if (timeout < 1)
169 timeout = 1;
170 } else
171 timeout = -1;
172
173 /* Hmm, nothing to do. Let's sleep */
174
175 if (pa_asyncmsgq_before_poll(u->asyncmsgq) < 0)
176 continue;
177
178 r = poll(&pollfd, 1, timeout);
179 pa_asyncmsgq_after_poll(u->asyncmsgq);
180
181 if (r < 0) {
182 if (errno == EINTR)
183 continue;
184
185 pa_log("poll() failed: %s", pa_cstrerror(errno));
186 goto fail;
187 }
188
189 pa_assert(r == 0 || pollfd.revents == POLLIN);
190 }
191
192 fail:
193 /* We have to continue processing messages until we receive the
194 * SHUTDOWN message */
195 pa_asyncmsgq_post(u->core->asyncmsgq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, NULL, NULL);
196 pa_asyncmsgq_wait_for(u->asyncmsgq, PA_MESSAGE_SHUTDOWN);
197
198 finish:
199 pa_log_debug("Thread shutting down");
200 }
201
202 int pa__init(pa_core *c, pa_module*m) {
203 struct userdata *u = NULL;
204 pa_sample_spec ss;
205 pa_channel_map map;
206 pa_modargs *ma = NULL;
207
208 pa_assert(c);
209 pa_assert(m);
210
211 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
212 pa_log("Failed to parse module arguments.");
213 goto fail;
214 }
215
216 ss = c->default_sample_spec;
217 if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
218 pa_log("Invalid sample format specification or channel map");
219 goto fail;
220 }
221
222 u = pa_xnew0(struct userdata, 1);
223 u->core = c;
224 u->module = m;
225 m->userdata = u;
226
227 pa_assert_se(u->asyncmsgq = pa_asyncmsgq_new(0));
228
229 if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
230 pa_log("Failed to create sink.");
231 goto fail;
232 }
233
234 u->sink->parent.process_msg = sink_process_msg;
235 u->sink->userdata = u;
236
237 pa_sink_set_module(u->sink, m);
238 pa_sink_set_asyncmsgq(u->sink, u->asyncmsgq);
239 pa_sink_set_description(u->sink, pa_modargs_get_value(ma, "description", "NULL sink"));
240
241 u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
242 if (u->block_size <= 0)
243 u->block_size = pa_frame_size(&ss);
244
245 if (!(u->thread = pa_thread_new(thread_func, u))) {
246 pa_log("Failed to create thread.");
247 goto fail;
248 }
249
250 pa_modargs_free(ma);
251
252 return 0;
253
254 fail:
255 if (ma)
256 pa_modargs_free(ma);
257
258 pa__done(c, m);
259
260 return -1;
261 }
262
263 void pa__done(pa_core *c, pa_module*m) {
264 struct userdata *u;
265
266 pa_assert(c);
267 pa_assert(m);
268
269 if (!(u = m->userdata))
270 return;
271
272 if (u->sink)
273 pa_sink_disconnect(u->sink);
274
275 if (u->thread) {
276 pa_asyncmsgq_send(u->asyncmsgq, NULL, PA_MESSAGE_SHUTDOWN, NULL, NULL);
277 pa_thread_free(u->thread);
278 }
279
280 if (u->asyncmsgq)
281 pa_asyncmsgq_free(u->asyncmsgq);
282
283 if (u->sink)
284 pa_sink_unref(u->sink);
285
286 pa_xfree(u);
287 }