Merge branch 'refs/heads/t/lopsub'
[paraslash.git] / ao_write.c
1 /*
2 * Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>
3 *
4 * Licensed under the GPL v2. For licencing details see COPYING.
5 */
6
7 /** \file ao_write.c Paraslash's libao output plugin. */
8
9 #include <pthread.h>
10 #include <ao/ao.h>
11 #include <regex.h>
12 #include <lopsub.h>
13
14 #include "write_cmd.lsg.h"
15 #include "para.h"
16 #include "fd.h"
17 #include "string.h"
18 #include "list.h"
19 #include "sched.h"
20 #include "buffer_tree.h"
21 #include "write.h"
22 #include "error.h"
23
24 struct private_aow_data {
25 ao_device *dev;
26 int bytes_per_frame;
27
28 pthread_t thread;
29 pthread_attr_t attr;
30 /* The mutex and the condition variable serialize access to ->btrn */
31 pthread_mutex_t mutex;
32 pthread_cond_t data_available;
33 struct btr_node *thread_btrn;
34 };
35
36 static void aow_close(struct writer_node *wn)
37 {
38 struct private_aow_data *pawd = wn->private_data;
39
40 if (!pawd)
41 return;
42 assert(!pawd->thread_btrn);
43 ao_close(pawd->dev);
44 free(pawd);
45 wn->private_data = NULL;
46 ao_shutdown();
47 }
48
49 static void aow_pre_select(struct sched *s, void *context)
50 {
51 struct writer_node *wn = context;
52 struct private_aow_data *pawd = wn->private_data;
53 int ret;
54
55 if (!pawd) { /* not yet started */
56 assert(wn->btrn);
57 ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
58 if (ret != 0)
59 goto min_delay;
60 return; /* no data available */
61 }
62 if (!wn->btrn) { /* EOF */
63 if (!pawd->thread_btrn) /* ready to exit */
64 goto min_delay;
65 /* wait for the play thread to terminate */
66 goto timeout;
67 }
68 pthread_mutex_lock(&pawd->mutex);
69 ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
70 pthread_mutex_unlock(&pawd->mutex);
71 if (ret != 0)
72 goto min_delay;
73 /*
74 * Even though the node status is zero, we might have data available,
75 * but the output buffer is full. If we don't set a timeout here, we
76 * are woken up only if new data arrives, which might be too late and
77 * result in a buffer underrun in the playing thread. To avoid this we
78 * never sleep longer than the (default) buffer time.
79 */
80 timeout:
81 return sched_request_timeout_ms(20, s);
82 min_delay:
83 sched_min_delay(s);
84 }
85
86 static int aow_set_sample_format(unsigned sample_rate, unsigned channels,
87 int sample_format, ao_sample_format *result)
88 {
89 memset(result, 0, sizeof(*result));
90 switch (sample_format) {
91 case SF_U8:
92 case SF_U16_LE:
93 case SF_U16_BE:
94 return -E_AO_BAD_SAMPLE_FORMAT;
95 case SF_S8:
96 /* no need to set byte_format */
97 result->bits = 8;
98 break;
99 case SF_S16_LE:
100 result->bits = 16;
101 result->byte_format = AO_FMT_LITTLE;
102 break;
103 case SF_S16_BE:
104 result->bits = 16;
105 result->byte_format = AO_FMT_BIG;
106 break;
107 default:
108 PARA_EMERG_LOG("bug: invalid sample format\n");
109 exit(EXIT_FAILURE);
110 }
111 result->channels = channels;
112 result->rate = sample_rate;
113 return 1;
114 }
115
116 static int aow_open_device(int id, ao_sample_format *asf, ao_option *options,
117 ao_device **result)
118 {
119 const char *msg;
120 ao_device *dev = ao_open_live(id, asf, options);
121
122 if (dev) {
123 *result = dev;
124 return 1;
125 }
126 switch (errno) {
127 case AO_ENODRIVER:
128 msg = "No driver corresponds to driver_id";
129 break;
130 case AO_ENOTLIVE:
131 msg = "This driver is not a live output device";
132 break;
133 case AO_EBADOPTION:
134 msg = "A valid option key has an invalid value";
135 break;
136 case AO_EOPENDEVICE:
137 msg = "Cannot open the device";
138 break;
139 case AO_EFAIL:
140 msg = "General libao error";
141 break;
142 default:
143 msg = "Unknown ao error";
144 break;
145 }
146 PARA_ERROR_LOG("%s\n", msg);
147 return -E_AO_OPEN_LIVE;
148 }
149
150 static void aow_show_drivers(void)
151 {
152 int i, j, num_drivers;
153 ao_info **driver_list;
154
155 PARA_DEBUG_LOG("libao drivers available on this host:\n");
156 PARA_DEBUG_LOG("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
157
158 driver_list = ao_driver_info_list(&num_drivers);
159
160 for (i = 0; i < num_drivers; i++) {
161 ao_info *info = driver_list[i];
162 char *keys = NULL, *tmp = NULL;
163
164 if (info->type == AO_TYPE_FILE)
165 continue;
166 PARA_DEBUG_LOG("%s: %s", info->short_name, info->name);
167 PARA_DEBUG_LOG("priority: %d", info->priority);
168 for (j = 0; j < info->option_count; j++) {
169 tmp = make_message("%s%s%s", keys? keys : "",
170 keys? ", " : "",
171 info->options[j]);
172 free(keys);
173 keys = tmp;
174 }
175 PARA_DEBUG_LOG("keys: %s", keys? keys : "[none]");
176 free(keys);
177 PARA_DEBUG_LOG("comment: %s", info->comment?
178 info->comment : "[none]");
179 }
180 }
181
182 static int aow_init(struct writer_node *wn, unsigned sample_rate,
183 unsigned channels, int sample_format)
184 {
185 int id, ret, i;
186 ao_option *aoo = NULL;
187 ao_sample_format asf;
188 ao_info *info;
189 const struct lls_opt_result *r;
190 unsigned n;
191 struct private_aow_data *pawd = para_malloc(sizeof(*pawd));
192
193 ao_initialize();
194 aow_show_drivers();
195 if (WRITE_CMD_OPT_GIVEN(AO, DRIVER, wn->lpr)) {
196 ret = -E_AO_BAD_DRIVER;
197 id = ao_driver_id(WRITE_CMD_OPT_STRING_VAL(AO, DRIVER, wn->lpr));
198 } else {
199 ret = -E_AO_DEFAULT_DRIVER;
200 id = ao_default_driver_id();
201 }
202 if (id < 0)
203 goto fail;
204 info = ao_driver_info(id);
205 assert(info && info->short_name);
206 if (info->type == AO_TYPE_FILE) {
207 ret = -E_AO_FILE_NOT_SUPP;
208 goto fail;
209 }
210 PARA_INFO_LOG("using %s driver\n", info->short_name);
211 r = WRITE_CMD_OPT_RESULT(AO, AO_OPTION, wn->lpr);
212 n = lls_opt_given(r);
213 for (i = 0; i < n; i++) {
214 char *o = para_strdup(lls_string_val(i, r));
215 char *value;
216
217 ret = -E_AO_BAD_OPTION;
218 value = strchr(o, ':');
219 if (!value) {
220 free(o);
221 goto fail;
222 }
223 *value = '\0';
224 value++;
225 PARA_INFO_LOG("appending option: key=%s, value=%s\n", o, value);
226 ret = ao_append_option(&aoo, o, value);
227 free(o);
228 if (ret == 0) {
229 ret = -E_AO_APPEND_OPTION;
230 goto fail;
231 }
232 }
233 ret = aow_set_sample_format(sample_rate, channels, sample_format, &asf);
234 if (ret < 0)
235 goto fail;
236 if (sample_format == SF_S8 || sample_format == SF_U8)
237 pawd->bytes_per_frame = channels;
238 else
239 pawd->bytes_per_frame = channels * 2;
240 ret = aow_open_device(id, &asf, aoo, &pawd->dev);
241 if (ret < 0)
242 goto fail;
243 PARA_INFO_LOG("successfully opened %s\n", info->short_name);
244 wn->private_data = pawd;
245 return 1;
246 fail:
247 free(pawd);
248 return ret;
249 }
250
251 __noreturn static void *aow_play(void *priv)
252 {
253 struct writer_node *wn = priv;
254 struct private_aow_data *pawd = wn->private_data;
255 struct btr_node *btrn = pawd->thread_btrn;
256 size_t frames, bytes;
257 char *data;
258 int ret;
259
260 pthread_mutex_lock(&pawd->mutex);
261 for (;;) {
262 for (;;) {
263 ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF);
264 if (ret < 0)
265 goto fail;
266 if (ret > 0) {
267 btr_merge(btrn, wn->min_iqs);
268 bytes = btr_next_buffer(btrn, &data);
269 frames = bytes / pawd->bytes_per_frame;
270 if (frames > 0)
271 break;
272 /* eof and less than a single frame available */
273 ret = -E_WRITE_COMMON_EOF;
274 goto fail;
275 }
276 /*
277 * No data available, go to sleep and wait for the main
278 * thread to wake us up. pthread_cond_wait() unlocks
279 * the mutex while it waits and locks it again upon
280 * return.
281 */
282 ret = pthread_cond_wait(&pawd->data_available,
283 &pawd->mutex);
284 /* pthread_cond_wait() can never fail here */
285 assert(ret == 0);
286 }
287 assert(frames > 0);
288 bytes = frames * pawd->bytes_per_frame;
289 pthread_mutex_unlock(&pawd->mutex);
290 ret = ao_play(pawd->dev, data, bytes);
291 pthread_mutex_lock(&pawd->mutex);
292 if (ret == 0) { /* failure */
293 ret = -E_AO_PLAY;
294 goto fail;
295 }
296 btr_consume(btrn, bytes);
297 }
298 fail:
299 btr_remove_node(&pawd->thread_btrn);
300 assert(ret < 0);
301 PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
302 pthread_mutex_unlock(&pawd->mutex);
303 pthread_exit(NULL);
304 }
305
306 static int aow_create_thread(struct writer_node *wn)
307 {
308 struct private_aow_data *pawd = wn->private_data;
309 int ret;
310 const char *msg;
311
312 /* initialize with default attributes */
313 msg = "could not init mutex";
314 ret = pthread_mutex_init(&pawd->mutex, NULL);
315 if (ret < 0)
316 goto fail;
317
318 msg = "could not initialize condition variable";
319 ret = pthread_cond_init(&pawd->data_available, NULL);
320 if (ret < 0)
321 goto fail;
322
323 msg = "could not initialize thread attributes";
324 ret = pthread_attr_init(&pawd->attr);
325 if (ret < 0)
326 goto fail;
327
328 /* schedule this thread under the real-time policy SCHED_FIFO */
329 msg = "could not set sched policy";
330 ret = pthread_attr_setschedpolicy(&pawd->attr, SCHED_FIFO);
331 if (ret < 0)
332 goto fail;
333
334 msg = "could not set detach state to joinable";
335 ret = pthread_attr_setdetachstate(&pawd->attr, PTHREAD_CREATE_JOINABLE);
336 if (ret < 0)
337 goto fail;
338
339 msg = "could not create thread";
340 ret = pthread_create(&pawd->thread, &pawd->attr, aow_play, wn);
341 if (ret < 0)
342 goto fail;
343 return 1;
344 fail:
345 PARA_ERROR_LOG("%s (%s)\n", msg, strerror(ret));
346 return -E_AO_PTHREAD;
347 }
348
349 static int aow_post_select(__a_unused struct sched *s, void *context)
350 {
351 struct writer_node *wn = context;
352 struct private_aow_data *pawd = wn->private_data;
353 int ret;
354
355 if (!pawd) {
356 int32_t rate, ch, format;
357 struct btr_node_description bnd;
358
359 ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
360 if (ret < 0)
361 goto remove_btrn;
362 if (ret == 0)
363 return 0;
364 get_btr_sample_rate(wn->btrn, &rate);
365 get_btr_channels(wn->btrn, &ch);
366 get_btr_sample_format(wn->btrn, &format);
367 ret = aow_init(wn, rate, ch, format);
368 if (ret < 0)
369 goto remove_btrn;
370 pawd = wn->private_data;
371
372 /* set up thread btr node */
373 bnd.name = "ao_thread_btrn";
374 bnd.parent = wn->btrn;
375 bnd.child = NULL;
376 bnd.handler = NULL;
377 bnd.context = pawd;
378 pawd->thread_btrn = btr_new_node(&bnd);
379 wn->private_data = pawd;
380
381 ret = aow_create_thread(wn);
382 if (ret < 0)
383 goto remove_thread_btrn;
384 return 0;
385 }
386 if (!wn->btrn) {
387 if (!pawd->thread_btrn) {
388 pthread_join(pawd->thread, NULL);
389 return -E_AO_EOF;
390 }
391 PARA_INFO_LOG("waiting for play thread to terminate\n");
392 return 0;
393 }
394 pthread_mutex_lock(&pawd->mutex);
395 ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
396 if (ret > 0) {
397 btr_pushdown(wn->btrn);
398 if (pthread_cond_signal(&pawd->data_available) != 0) {
399 ret = -E_AO_PTHREAD;
400 PARA_ERROR_LOG("pthread_cond_signal() failed\n");
401 goto remove_thread_btrn;
402 }
403 }
404 if (ret >= 0) {
405 pthread_mutex_unlock(&pawd->mutex);
406 goto out;
407 }
408 btr_remove_node(&wn->btrn);
409 pthread_cond_signal(&pawd->data_available);
410 pthread_mutex_unlock(&pawd->mutex);
411 return 0;
412 remove_thread_btrn:
413 btr_remove_node(&pawd->thread_btrn);
414 remove_btrn:
415 btr_remove_node(&wn->btrn);
416 out:
417 return ret;
418 }
419
420 struct writer lsg_write_cmd_com_ao_user_data = {
421 .close = aow_close,
422 .pre_select = aow_pre_select,
423 .post_select = aow_post_select,
424 };
425