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