2 * Copyright (C) 2005-2006 Andre Noll <maan@systemlinux.org>
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.
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.
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.
21 #include "write.cmdline.h"
23 #include "write_common.h"
26 #include <sys/time.h> /* gettimeofday */
30 #define WAV_HEADER_LEN 44
32 static char *audiobuf;
33 static struct timeval *start_time;
34 struct gengetopt_args_info conf;
38 void para_log(int ll, const char* fmt,...)
42 if (ll < conf.loglevel_arg)
45 vfprintf(stderr, fmt, argp);
50 * read WAV_HEADER_LEN bytes from stdin to audio buffer
52 * \return -E_READ_HDR on errors and on eof before WAV_HEADER_LEN could be
53 * read. A positive return value indicates success.
55 static int read_wav_header(void)
57 ssize_t ret, count = 0;
59 while (count < WAV_HEADER_LEN) {
60 ret = read(STDIN_FILENO, audiobuf + count, WAV_HEADER_LEN - count);
69 * check if current time is later than start_time
70 * \param diff pointer to write remaining time to
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
78 static int start_time_in_future(struct timeval *diff)
82 if (!conf.start_time_given)
84 gettimeofday(&now, NULL);
85 return tv_diff(start_time, &now, diff) > 0? 1 : 0;
89 * sleep until time given at command line
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.
96 static void do_initial_delay(struct timeval *delay)
99 para_select(1, NULL, NULL, delay);
100 while (start_time_in_future(delay));
103 static int read_stdin(char *buf, size_t bytes_to_load, size_t *loaded)
107 while (*loaded < bytes_to_load) {
108 ret = read(STDIN_FILENO, buf + *loaded, bytes_to_load - *loaded);
120 * \param loaded number of bytes already loaded
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
126 * \return positive on success, negative on errors.
128 static int pcm_write(struct writer_node_group *wng, size_t loaded)
130 size_t bufsize, prebuf_size, bytes_to_load;
131 struct timeval delay;
132 int ret, not_yet_started = 1;
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) {
146 ret = -E_PREMATURE_END;
149 if (not_yet_started && start_time && start_time_in_future(&delay))
150 do_initial_delay(&delay);
153 ret = wng_write(wng, audiobuf, &loaded);
156 ret = -E_WRITE_OVERRUN;
157 if (loaded >= bufsize)
159 bytes_to_load = PARA_MIN(wng->max_chunk_bytes, bufsize);
160 ret = read_stdin(audiobuf, bytes_to_load, &loaded);
171 static struct writer_node_group *check_args(void)
173 int i, ret = -E_WRITE_SYNTAX;
174 static struct timeval tv;
175 struct writer_node_group *wng = NULL;
177 if (conf.list_writers_given) {
180 char *tmp = make_message("%s%s%s",
187 fprintf(stderr, "%s\n", msg);
191 if (conf.prebuffer_arg < 0 || conf.prebuffer_arg > 100)
193 if (conf.start_time_given) {
194 long unsigned sec, usec;
195 if (sscanf(conf.start_time_arg, "%lu:%lu",
202 if (!conf.writer_given) {
203 wng = setup_default_wng();
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]);
212 wng->writer_nodes[i].writer = &writers[ret];
223 * test if audio buffer contains a valid wave header
225 * \return If not, return 0, otherwise, store number of channels and sample rate
226 * in struct conf and return WAV_HEADER_LEN.
228 static size_t check_wave(void)
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);
238 int main(int argc, char *argv[])
240 int ret = -E_WRITE_SYNTAX;
241 struct writer_node_group *wng = NULL;
243 cmdline_parser(argc, argv, &conf);
247 init_supported_writers();
248 audiobuf = para_malloc(WAV_HEADER_LEN);
249 ret = read_wav_header();
252 ret = pcm_write(wng, check_wave());
257 PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));