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