#define EXIT(EXP) \
do { if (EXP) \
- fprintf (stderr, "error: " #EXP "\n"); exit(EXP);} \
+ fprintf (stderr, "error: " #EXP "\n"); exit(EXP);} \
while (0)
static snd_pcm_t *handle;
/*
* pcm_write - push out pcm frames
- * @data: pointer do data to be written
- * @count: number of frames
+ * \param data pointer do data to be written
+ * \param count number of frames
*
- * Return value: Number of bytes written. Exit on errors.
+ * \return Number of bytes written. Exit on errors.
*/
static snd_pcm_sframes_t pcm_write(u_char *data, size_t count)
{
snd_pcm_sframes_t r, result = 0;
-#if 0
- if (count < chunk_size) {
- snd_pcm_format_set_silence(FORMAT, data
- + count * bytes_per_frame,
- (chunk_size - count) * conf.channels_arg);
- count = chunk_size;
- }
-#endif
while (count > 0) {
/* write interleaved frames */
r = snd_pcm_writei(handle, data, count);
+ if (r < 0)
+ fprintf(stderr, "write error: %s\n", snd_strerror(r));
if (r == -EAGAIN || (r >= 0 && r < count))
snd_pcm_wait(handle, 1);
else if (r == -EPIPE)
/*
* start_time_in_future - check if current time is later than start_time
- * @diff: pointer to write remaining time to
+ * \param diff pointer to write remaining time to
*
* If start_time was not given, or current time is later than given
* start_time, return 0. Otherwise, return 1 and write the time
* or if the given start time is in the past.
*
*/
-static void do_initial_delay(void)
+static void do_initial_delay(struct timeval *delay)
{
- struct timeval diff;
- int ret;
-
- fprintf(stderr, "initial delay\n");
- if (!conf.start_time_given)
- return;
-again:
- if (!start_time_in_future(&diff))
- return;
- ret = select(1, NULL, NULL, NULL, &diff);
- if (ret < 0 && errno == EINTR)
- goto again;
+ fprintf(stderr, "sleeping %lums\n", tv2ms(delay));
+ do
+ select(1, NULL, NULL, NULL, delay);
+ while (start_time_in_future(delay));
}
-
/*
* play_pcm - play raw pcm data
- * @l: number of bytes already loaded
+ * \param loaded number of bytes already loaded
*
* If start_time was given, prebuffer data until buffer is full or
* start_time is reached. In any case, do not start playing before
* start_time.
*/
-static void play_pcm(size_t l)
+static void play_pcm(size_t loaded)
{
- ssize_t r, w;
- unsigned long written = 0;
- size_t chunk_bytes;
+ size_t chunk_bytes, bufsize, written = 0;
+ ssize_t ret;
+ unsigned char *p;
+ int dont_write;
+ struct timeval delay;
set_alsa_params();
chunk_bytes = chunk_size * bytes_per_frame;
- audiobuf = realloc(audiobuf, BUFFER_SIZE);
-// fprintf(stderr, "loaded: %d, chunk_bytes: %d\n", l, chunk_bytes);
+ bufsize = chunk_bytes * 1024;
+ audiobuf = realloc(audiobuf, bufsize);
if (!audiobuf)
EXIT(E_MEM);
- for (;;) {
- for (;;) {
- if (l >= chunk_bytes) {
- if (written)
- break;
- if (!start_time)
- break;
- if (!start_time_in_future(NULL))
- break;
- if (l > BUFFER_SIZE) {
- do_initial_delay();
- break;
- }
+again:
+ dont_write = 0;
+ if (!written && start_time)
+ dont_write = start_time_in_future(&delay);
+ if (!dont_write) {
+ p = audiobuf;
+ while (loaded >= chunk_bytes) {
+ ret = (ssize_t) pcm_write(p, chunk_size) * bytes_per_frame;
+ if (ret <= 0) {
+ fprintf(stderr, "write error: %d\n", ret);
+ EXIT(E_WRITE);
}
-// fprintf(stderr, "l = %d, chunk_Bytes = %d\n", l, chunk_bytes);
- r = read(STDIN_FILENO, audiobuf + l, BUFFER_SIZE -l);
- if (r < 0)
- EXIT(E_READ);
- l += r;
-// fprintf(stderr, "loaded: %d, r= %d\n", l, r);
- if (!r)
- goto out;;
+ p += ret;
+ written += ret;
+ loaded -= ret;
}
- w = MIN(chunk_bytes, l);
-// fprintf(stderr, "play: writing %d\n", w);
- r = (ssize_t) pcm_write(audiobuf, w / bytes_per_frame) * bytes_per_frame;
-// fprintf(stderr, "wrote %d\n", r);
- if (r < 0)
- EXIT(E_WRITE);
- written += r;
- l -= r;
- if (l)
- memmove(audiobuf, audiobuf + r, l);
-// fprintf(stderr, "written %lu, loaded : %d\n", written, l);
+ if (loaded && p != audiobuf) {
+ fprintf(stderr, "memcpy: %d\n", loaded);
+ memcpy(audiobuf, p, loaded);
+ }
+ }
+ if (dont_write && loaded >= bufsize) {
+ do_initial_delay(&delay);
+ start_time = NULL;
+ goto again;
+ }
+ ret = read(STDIN_FILENO, audiobuf, bufsize - loaded);
+ if (ret < 0)
+ EXIT(E_READ);
+ if (ret) {
+ loaded += ret;
+ goto again;
}
-out:
snd_pcm_drain(handle);
}
snd_pcm_info_alloca(&info);
if (snd_output_stdio_attach(&log, stderr, 0) < 0)
EXIT(E_LOG);
- err = snd_pcm_open(&handle, "plug:swmix",
+ err = snd_pcm_open(&handle, conf.device_arg,
SND_PCM_STREAM_PLAYBACK, 0);
if (err < 0)
EXIT(E_PCM_OPEN);
play_pcm(check_wave());
snd_pcm_close(handle);
free(audiobuf);
- snd_output_close(log);
+// snd_output_close(log);
snd_config_update_free_global();
return EXIT_SUCCESS;
}