6e4ee0639654eac69ae76cb94e5a0bcffb316688
[paraslash.git] / write.c
1 /*
2 * Copyright (C) 2005-2006 Andre Noll <maan@systemlinux.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
17 */
18
19 #include "para.h"
20 #include "string.h"
21 #include "write.cmdline.h"
22 #include "write.h"
23 #include "write_common.h"
24 #include "fd.h"
25
26 #include <sys/time.h> /* gettimeofday */
27
28 #include "error.h"
29
30 #define WAV_HEADER_LEN 44
31
32 static char *audiobuf;
33 static struct timeval *start_time;
34 struct gengetopt_args_info conf;
35
36 INIT_WRITE_ERRLISTS;
37
38 void para_log(int ll, const char* fmt,...)
39 {
40 va_list argp;
41
42 if (ll < conf.loglevel_arg)
43 return;
44 va_start(argp, fmt);
45 vfprintf(stderr, fmt, argp);
46 va_end(argp);
47 }
48
49 /**
50 * read WAV_HEADER_LEN bytes from stdin to audio buffer
51 *
52 * \return -E_READ_HDR on errors and on eof before WAV_HEADER_LEN could be
53 * read. A positive return value indicates success.
54 */
55 static int read_wav_header(void)
56 {
57 ssize_t ret, count = 0;
58
59 while (count < WAV_HEADER_LEN) {
60 ret = read(STDIN_FILENO, audiobuf + count, WAV_HEADER_LEN - count);
61 if (ret <= 0)
62 return -E_READ_HDR;
63 count += ret;
64 }
65 return 1;
66 }
67
68 /**
69 * check if current time is later than start_time
70 * \param diff pointer to write remaining time to
71 *
72 * If start_time was not given, or current time is later than given
73 * start_time, return 0. Otherwise, return 1 and write the time
74 * difference between current time and start_time to diff. diff may be
75 * NULL.
76 *
77 */
78 static int start_time_in_future(struct timeval *diff)
79 {
80 struct timeval now;
81
82 if (!conf.start_time_given)
83 return 0;
84 gettimeofday(&now, NULL);
85 return tv_diff(start_time, &now, diff) > 0? 1 : 0;
86 }
87
88 /**
89 * sleep until time given at command line
90 *
91 * This is called if the initial buffer is filled. It returns
92 * immediately if no start_time was given at the command line
93 * or if the given start time is in the past.
94 *
95 */
96 static void do_initial_delay(struct timeval *delay)
97 {
98 do
99 para_select(1, NULL, NULL, delay);
100 while (start_time_in_future(delay));
101 }
102
103 static int read_stdin(char *buf, size_t bytes_to_load, size_t *loaded)
104 {
105 ssize_t ret;
106
107 while (*loaded < bytes_to_load) {
108 ret = read(STDIN_FILENO, buf + *loaded, bytes_to_load - *loaded);
109 if (ret <= 0) {
110 if (ret < 0)
111 ret = -E_READ_STDIN;
112 return ret;
113 }
114 *loaded += ret;
115 }
116 return 1;
117 }
118 /**
119 * play raw pcm data
120 * \param loaded number of bytes already loaded
121 *
122 * If start_time was given, prebuffer data until buffer is full or
123 * start_time is reached. In any case, do not start playing before
124 * start_time.
125 *
126 * \return positive on success, negative on errors.
127 */
128 static int pcm_write(struct writer_node_group *wng, size_t loaded)
129 {
130 size_t bufsize, prebuf_size, bytes_to_load;
131 struct timeval delay;
132 int ret, not_yet_started = 1;
133
134 ret = wng_open(wng);
135 if (ret < 0)
136 goto out;
137 PARA_INFO_LOG("max chunk_bytes: %zd\n", wng->max_chunk_bytes);
138 bufsize = (conf.bufsize_arg * 1024 / wng->max_chunk_bytes)
139 * wng->max_chunk_bytes;
140 audiobuf = para_realloc(audiobuf, bufsize);
141 prebuf_size = conf.prebuffer_arg * bufsize / 100;
142 bytes_to_load = PARA_MAX(prebuf_size, wng->max_chunk_bytes);
143 ret = read_stdin(audiobuf, bytes_to_load, &loaded);
144 if (ret <= 0 || loaded < bytes_to_load) {
145 if (ret >= 0)
146 ret = -E_PREMATURE_END;
147 goto out;
148 }
149 if (not_yet_started && start_time && start_time_in_future(&delay))
150 do_initial_delay(&delay);
151 not_yet_started = 0;
152 again:
153 ret = wng_write(wng, audiobuf, &loaded);
154 if (ret <= 0)
155 goto out;
156 ret = -E_WRITE_OVERRUN;
157 if (loaded >= bufsize)
158 goto out;
159 bytes_to_load = PARA_MIN(wng->max_chunk_bytes, bufsize);
160 ret = read_stdin(audiobuf, bytes_to_load, &loaded);
161 if (ret < 0)
162 goto out;
163 if (!ret)
164 wng->eof = 1;
165 goto again;
166 out:
167 wng_close(wng);
168 return ret;
169 }
170
171 static struct writer_node_group *check_args(void)
172 {
173 int i, ret = -E_WRITE_SYNTAX;
174 static struct timeval tv;
175 struct writer_node_group *wng = NULL;
176
177 if (conf.list_writers_given) {
178 char *msg = NULL;
179 FOR_EACH_WRITER(i) {
180 char *tmp = make_message("%s%s%s",
181 i? msg : "",
182 i? " " : "",
183 writer_names[i]);
184 free(msg);
185 msg = tmp;
186 }
187 fprintf(stderr, "%s\n", msg);
188 free(msg);
189 exit(EXIT_SUCCESS);
190 }
191 if (conf.prebuffer_arg < 0 || conf.prebuffer_arg > 100)
192 goto out;
193 if (conf.start_time_given) {
194 long unsigned sec, usec;
195 if (sscanf(conf.start_time_arg, "%lu:%lu",
196 &sec, &usec) != 2)
197 goto out;
198 tv.tv_sec = sec;
199 tv.tv_usec = usec;
200 start_time = &tv;
201 }
202 if (!conf.writer_given) {
203 wng = setup_default_wng();
204 ret = 1;
205 goto out;
206 }
207 wng = wng_new(conf.writer_given);
208 for (i = 0; i < conf.writer_given; i++) {
209 ret = check_writer_arg(conf.writer_arg[i]);
210 if (ret < 0)
211 goto out;
212 wng->writer_nodes[i].writer = &writers[ret];
213 }
214 ret = 1;
215 out:
216 if (ret > 0)
217 return wng;
218 free(wng);
219 return NULL;
220 }
221
222 /**
223 * test if audio buffer contains a valid wave header
224 *
225 * \return If not, return 0, otherwise, store number of channels and sample rate
226 * in struct conf and return WAV_HEADER_LEN.
227 */
228 static size_t check_wave(void)
229 {
230 unsigned char *a = (unsigned char*)audiobuf;
231 if (a[0] != 'R' || a[1] != 'I' || a[2] != 'F' || a[3] != 'F')
232 return WAV_HEADER_LEN;
233 conf.channels_arg = (unsigned) a[22];
234 conf.sample_rate_arg = a[24] + (a[25] << 8) + (a[26] << 16) + (a[27] << 24);
235 return 0;
236 }
237
238 int main(int argc, char *argv[])
239 {
240 int ret = -E_WRITE_SYNTAX;
241 struct writer_node_group *wng = NULL;
242
243 cmdline_parser(argc, argv, &conf);
244 wng = check_args();
245 if (!wng)
246 goto out;
247 init_supported_writers();
248 audiobuf = para_malloc(WAV_HEADER_LEN);
249 ret = read_wav_header();
250 if (ret < 0)
251 goto out;
252 ret = pcm_write(wng, check_wave());
253 out:
254 wng_destroy(wng);
255 free(audiobuf);
256 if (ret < 0)
257 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
258 return ret;
259 }