6e4ee0639654eac69ae76cb94e5a0bcffb316688
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
));