para_play -> para_write documentation update
[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 unsigned 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: %d\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 /* write.c */
171
172 struct writer_node_group *check_args(void)
173 {
174 int i, ret = -E_WRITE_SYNTAX;
175 static struct timeval tv;
176 struct writer_node_group *wng = NULL;
177
178 if (conf.list_writers_given) {
179 char *msg = NULL;
180 FOR_EACH_WRITER(i) {
181 char *tmp = make_message("%s%s%s",
182 i? msg : "",
183 i? " " : "",
184 writer_names[i]);
185 free(msg);
186 msg = tmp;
187 }
188 fprintf(stderr, "%s\n", msg);
189 free(msg);
190 exit(EXIT_SUCCESS);
191 }
192 if (conf.prebuffer_arg < 0 || conf.prebuffer_arg > 100)
193 goto out;
194 if (conf.start_time_given) {
195 long unsigned sec, usec;
196 if (sscanf(conf.start_time_arg, "%lu:%lu",
197 &sec, &usec) != 2)
198 goto out;
199 tv.tv_sec = sec;
200 tv.tv_usec = usec;
201 start_time = &tv;
202 }
203 if (!conf.writer_given) {
204 wng = setup_default_wng();
205 ret = 1;
206 goto out;
207 }
208 wng = wng_new(conf.writer_given);
209 for (i = 0; i < conf.writer_given; i++) {
210 ret = check_writer_arg(conf.writer_arg[i]);
211 if (ret < 0)
212 goto out;
213 wng->writer_nodes[i].writer = &writers[ret];
214 }
215 ret = 1;
216 out:
217 if (ret > 0)
218 return wng;
219 free(wng);
220 return NULL;
221 }
222
223 /**
224 * test if audio buffer contains a valid wave header
225 *
226 * \return If not, return 0, otherwise, store number of channels and sample rate
227 * in struct conf and return WAV_HEADER_LEN.
228 */
229 static size_t check_wave(void)
230 {
231 unsigned char *a = audiobuf;
232 if (a[0] != 'R' || a[1] != 'I' || a[2] != 'F' || a[3] != 'F')
233 return WAV_HEADER_LEN;
234 conf.channels_arg = (unsigned) a[22];
235 conf.sample_rate_arg = a[24] + (a[25] << 8) + (a[26] << 16) + (a[27] << 24);
236 return 0;
237 }
238
239 int main(int argc, char *argv[])
240 {
241 int ret = -E_WRITE_SYNTAX;
242 struct writer_node_group *wng = NULL;
243
244 cmdline_parser(argc, argv, &conf);
245 wng = check_args();
246 if (!wng)
247 goto out;
248 init_supported_writers();
249 audiobuf = para_malloc(WAV_HEADER_LEN);
250 ret = read_wav_header();
251 if (ret < 0)
252 goto out;
253 ret = pcm_write(wng, check_wave());
254 out:
255 wng_destroy(wng);
256 free(audiobuf);
257 if (ret < 0)
258 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
259 return ret;
260 }