manual: Do not mention gengetopt and help2man any more.
[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