chiark / gitweb /
Set resource limits on the server to prevent more than FD_SETSIZE
[disorder] / driver / disorder.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2005, 2007 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file driver/disorder.c
19  * @brief libao driver used by DisOrder
20  *
21  * The output from this driver is expected to be fed to @c
22  * disorder-normalize to convert to the confnigured target format.
23  */
24
25 #include "common.h"
26
27 #include <errno.h>
28 #include <unistd.h>
29 #include <poll.h>
30 #include <ao/ao.h>
31 #include <ao/plugin.h>
32
33 #include "speaker-protocol.h"
34
35 /* extra declarations to help out lazy <ao/plugin.h> */
36 int ao_plugin_test(void);
37 ao_info *ao_plugin_driver_info(void);
38 char *ao_plugin_file_extension(void);
39
40 /** @brief Private data structure for this driver */
41 struct internal {
42   int fd;                               /* output file descriptor */
43   int exit_on_error;                    /* exit on write error */
44
45   /** @brief Record of sample format */
46   struct stream_header header;
47
48 };
49
50 /* like write() but never returns EINTR/EAGAIN or short */
51 static int do_write(int fd, const void *ptr, size_t n) {
52   size_t written = 0;
53   int ret;
54   struct pollfd ufd;
55
56   memset(&ufd, 0, sizeof ufd);
57   ufd.fd = fd;
58   ufd.events = POLLOUT;
59   while(written < n) {
60     ret = write(fd, (const char *)ptr + written, n - written);
61     if(ret < 0) {
62       switch(errno) {
63       case EINTR: break;
64       case EAGAIN:
65         /* Someone sneakily gave us a nonblocking file descriptor, wait until
66          * we can write again */
67         ret = poll(&ufd, 1, -1);
68         if(ret < 0 && errno != EINTR) return -1;
69         break;
70       default:
71         return -1;
72       }
73     } else
74       written += ret;
75   }
76   return written;
77 }
78
79 /* return 1 if this driver can be opened */
80 int ao_plugin_test(void) {
81   return 1;
82 }
83
84 /* return info about this driver */
85 ao_info *ao_plugin_driver_info(void) {
86   static const char *options[] = { "fd" };
87   static const ao_info info = {
88     AO_TYPE_LIVE,                       /* type */
89     (char *)"DisOrder format driver",   /* name */
90     (char *)"disorder",                 /* short_name */
91     (char *)"http://www.greenend.org.uk/rjk/disorder/", /* comment */
92     (char *)"Richard Kettlewell",       /* author */
93     AO_FMT_NATIVE,                      /* preferred_byte_format */
94     0,                                  /* priority */
95     (char **)options,                   /* options */
96     1,                                  /* option_count */
97   };
98   return (ao_info *)&info;
99 }
100
101 /* initialize the private data structure */
102 int ao_plugin_device_init(ao_device *device) {
103   struct internal *i = malloc(sizeof (struct internal));
104   const char *e;
105
106   if(!i) return 0;
107   memset(i, 0, sizeof *i);
108   if((e = getenv("DISORDER_RAW_FD")))
109     i->fd = atoi(e);
110   else
111     i->fd = 1;
112   device->internal = i;
113   return 1;
114 }
115
116 /* set an option */
117 int ao_plugin_set_option(ao_device *device,
118                          const char *key,
119                          const char *value) {
120   struct internal *i = device->internal;
121
122   if(!strcmp(key, "fd"))
123     i->fd = atoi(value);
124   else if(!strcmp(key, "fragile"))
125     i->exit_on_error = atoi(value);
126   /* unknown options are required to be ignored */
127   return 1;
128 }
129
130 /* open the device */
131 int ao_plugin_open(ao_device *device, ao_sample_format *format) {
132   struct internal *i = device->internal;
133   
134   /* we would like native-order samples */
135   device->driver_byte_format = AO_FMT_NATIVE;
136   i->header.rate = format->rate;
137   i->header.channels = format->channels;
138   i->header.bits = format->bits;
139   i->header.endian = ENDIAN_NATIVE;
140   return 1;
141 }
142
143 /* play some samples */
144 int ao_plugin_play(ao_device *device, const char *output_samples, 
145                    uint_32 num_bytes) {
146   struct internal *i = device->internal;
147
148   /* Fill in and write the header */
149   i->header.nbytes = num_bytes;
150   if(do_write(i->fd, &i->header, sizeof i->header) < 0) {
151     if(i->exit_on_error) _exit(-1);
152     return 0;
153   }
154
155   /* Write the sample data */
156   if(do_write(i->fd, output_samples, num_bytes) < 0) {
157     if(i->exit_on_error) _exit(-1);
158     return 0;
159   }
160   return 1;
161 }
162
163 /* close the device */
164 int ao_plugin_close(ao_device attribute((unused)) *device) {
165   return 1;
166 }
167
168 /* delete private data structures */
169 void ao_plugin_device_clear(ao_device *device) {
170   free(device->internal);
171   device->internal = 0;
172 }
173
174 /* report preferred filename extension */
175 char *ao_plugin_file_extension(void) {
176   return 0;
177 }
178
179 /*
180 Local Variables:
181 c-basic-offset:2
182 comment-column:40
183 End:
184 */