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