static int timelimit = 0;
static int quiet_mode = 0;
static int file_type = FORMAT_DEFAULT;
-static int xrun_mode = SND_PCM_XRUN_FRAGMENT;
-static int ready_mode = SND_PCM_READY_FRAGMENT;
+static unsigned int sleep_min = 0;
static int open_mode = 0;
static int stream = SND_PCM_STREAM_PLAYBACK;
static int mmap_flag = 0;
static int interleaved = 1;
static int nonblock = 0;
static char *audiobuf = NULL;
-static int buffer_size = -1;
-static int frag_length = 125000;
-static int buffer_length = 500000;
-static int avail_min = 50000;
+static int chunk_size = -1;
+static int period_time = -1;
+static int buffer_time = -1;
+static int avail_min = -1;
static int verbose = 0;
static int buffer_pos = 0;
static size_t bits_per_sample, bits_per_frame;
-static size_t buffer_bytes;
+static size_t chunk_bytes;
static int digtype = SND_CONTROL_TYPE_NONE;
static snd_digital_audio_t diga;
-f, --format=FORMAT sample format (case insensitive)
-r, --rate=# sample rate
-d, --duration=# interrupt after # seconds
--e, --frame-mode use frame mode instead of default fragment mode
+-s, --sleep-min=# min ticks to sleep
-M, --mmap mmap stream
-N, --nonblock nonblocking mode
--F, --fragment-length=# fragment length is # microseconds
--B, --buffer-length=# buffer length is # microseconds
+-F, --period-time=# distance between interrupts is # microseconds
+-B, --buffer-time=# buffer duration is # microseconds
-A, --avail-min=# min available space for wakeup is # microseconds
-X, --xfer-min=# min xfer size is # microseconds
-v, --verbose show PCM structure and setup
int main(int argc, char *argv[])
{
int option_index;
- char *short_options = "lLD:qt:c:f:r:d:eMNF:A:X:B:vIPC";
+ char *short_options = "lLD:qt:c:f:r:d:s:MNF:A:X:B:vIPC";
static struct option long_options[] = {
{"help", 0, 0, OPT_HELP},
{"version", 0, 0, OPT_VERSION},
{"format", 1, 0, 'f'},
{"rate", 1, 0, 'r'},
{"duration", 1, 0 ,'d'},
- {"asap-mode", 0, 0, 'e'},
+ {"sleep-min", 0, 0, 's'},
{"mmap", 0, 0, 'M'},
{"nonblock", 0, 0, 'N'},
- {"fragment-length", 1, 0, 'F'},
+ {"period_time", 1, 0, 'F'},
{"avail-min", 1, 0, 'A'},
{"xfer-min", 1, 0, 'X'},
- {"buffer-length", 1, 0, 'B'},
+ {"buffer-time", 1, 0, 'B'},
{"verbose", 0, 0, 'v'},
{"iec958c", 0, 0, 'C'},
{"iec958p", 0, 0, 'P'},
return 1;
}
- buffer_size = -1;
+ chunk_size = -1;
rhwparams.format = SND_PCM_FORMAT_U8;
rhwparams.rate = DEFAULT_SPEED;
rhwparams.channels = 1;
case 'd':
timelimit = atoi(optarg);
break;
- case 'e':
- xrun_mode = SND_PCM_XRUN_ASAP;
- ready_mode = SND_PCM_READY_ASAP;
+ case 's':
+ sleep_min = atoi(optarg);
break;
case 'N':
nonblock = 1;
open_mode |= SND_PCM_NONBLOCK;
break;
case 'F':
- frag_length = atoi(optarg);
+ period_time = atoi(optarg);
break;
case 'B':
- buffer_length = atoi(optarg);
+ buffer_time = atoi(optarg);
break;
case 'A':
avail_min = atoi(optarg);
}
}
- buffer_size = 1024;
+ chunk_size = 1024;
hwparams = rhwparams;
audiobuf = (char *)malloc(1024);
{
snd_pcm_hw_params_t params;
snd_pcm_sw_params_t swparams;
- size_t bufsize;
+ size_t buffer_size;
int err;
size_t n;
+ size_t xfer_align;
err = snd_pcm_hw_params_any(handle, ¶ms);
if (err < 0) {
error("Broken configuration for this PCM: no configurations available");
} else if (interleaved)
err = snd_pcm_hw_param_set(handle, ¶ms,
SND_PCM_HW_PARAM_ACCESS,
- SND_PCM_ACCESS_RW_INTERLEAVED);
+ SND_PCM_ACCESS_RW_INTERLEAVED, 0);
else
err = snd_pcm_hw_param_set(handle, ¶ms,
SND_PCM_HW_PARAM_ACCESS,
- SND_PCM_ACCESS_RW_NONINTERLEAVED);
+ SND_PCM_ACCESS_RW_NONINTERLEAVED, 0);
if (err < 0) {
error("Access type not available");
exit(EXIT_FAILURE);
}
err = snd_pcm_hw_param_set(handle, ¶ms, SND_PCM_HW_PARAM_FORMAT,
- hwparams.format);
+ hwparams.format, 0);
if (err < 0) {
error("Sample format non available");
exit(EXIT_FAILURE);
}
err = snd_pcm_hw_param_set(handle, ¶ms, SND_PCM_HW_PARAM_CHANNELS,
- hwparams.channels);
+ hwparams.channels, 0);
if (err < 0) {
error("Channels count non available");
exit(EXIT_FAILURE);
}
+#if 0
err = snd_pcm_hw_param_min(handle, ¶ms,
- SND_PCM_HW_PARAM_FRAGMENTS, 2);
- assert(err >= 0);
- err = snd_pcm_hw_param_near(handle, ¶ms,
- SND_PCM_HW_PARAM_RATE, hwparams.rate);
- assert(err >= 0);
- err = snd_pcm_hw_param_near(handle, ¶ms,
- SND_PCM_HW_PARAM_FRAGMENT_LENGTH,
- frag_length);
+ SND_PCM_HW_PARAM_PERIODS, 2);
assert(err >= 0);
+#endif
err = snd_pcm_hw_param_near(handle, ¶ms,
- SND_PCM_HW_PARAM_BUFFER_LENGTH,
- buffer_length);
+ SND_PCM_HW_PARAM_RATE, hwparams.rate, 0);
assert(err >= 0);
+ if (buffer_time < 0)
+ buffer_time = 500000;
+ buffer_time = snd_pcm_hw_param_near(handle, ¶ms,
+ SND_PCM_HW_PARAM_BUFFER_TIME,
+ buffer_time, 0);
+ assert(buffer_time >= 0);
+ if (period_time < 0)
+ period_time = buffer_time / 4;
+ period_time = snd_pcm_hw_param_near(handle, ¶ms,
+ SND_PCM_HW_PARAM_PERIOD_TIME,
+ period_time, 0);
+ assert(period_time >= 0);
err = snd_pcm_hw_params(handle, ¶ms);
if (err < 0) {
fprintf(stderr, "Unable to install hw params:\n");
snd_pcm_hw_params_dump(¶ms, stderr);
exit(EXIT_FAILURE);
}
- buffer_size = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_FRAGMENT_SIZE);
- bufsize = buffer_size * snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_FRAGMENTS);
-
+ chunk_size = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_PERIOD_SIZE, 0);
+ buffer_size = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_BUFFER_SIZE, 0);
snd_pcm_sw_params_current(handle, &swparams);
+ xfer_align = snd_pcm_sw_param_value(&swparams, SND_PCM_SW_PARAM_XFER_ALIGN);
+ if (sleep_min)
+ xfer_align = 1;
err = snd_pcm_sw_param_set(handle, &swparams,
- SND_PCM_SW_PARAM_READY_MODE, ready_mode);
+ SND_PCM_SW_PARAM_SLEEP_MIN, sleep_min);
assert(err >= 0);
- err = snd_pcm_sw_param_set(handle, &swparams,
- SND_PCM_SW_PARAM_XRUN_MODE, xrun_mode);
- assert(err >= 0);
- n = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_RATE) * avail_min / 1000000;
- if (n > bufsize - buffer_size)
- n = bufsize - buffer_size;
+ if (avail_min < 0)
+ n = chunk_size;
+ else
+ n = snd_pcm_hw_param_value(¶ms, SND_PCM_HW_PARAM_RATE, 0) * (double) avail_min / 1000000;
err = snd_pcm_sw_param_near(handle, &swparams,
SND_PCM_SW_PARAM_AVAIL_MIN, n);
- if (xrun_mode == SND_PCM_XRUN_ASAP) {
- err = snd_pcm_sw_param_near(handle, &swparams,
- SND_PCM_SW_PARAM_XFER_ALIGN, 1);
- assert(err >= 0);
- }
+ err = snd_pcm_sw_param_near(handle, &swparams,
+ SND_PCM_SW_PARAM_XFER_ALIGN, xfer_align);
+ assert(err >= 0);
if (snd_pcm_sw_params(handle, &swparams) < 0) {
error("unable to install sw params:");
snd_pcm_sw_params_dump(&swparams, stderr);
bits_per_sample = snd_pcm_format_physical_width(hwparams.format);
bits_per_frame = bits_per_sample * hwparams.channels;
- buffer_bytes = buffer_size * bits_per_frame / 8;
- audiobuf = realloc(audiobuf, buffer_bytes);
+ chunk_bytes = chunk_size * bits_per_frame / 8;
+ audiobuf = realloc(audiobuf, chunk_bytes);
if (audiobuf == NULL) {
error("not enough memory");
exit(EXIT_FAILURE);
}
- // fprintf(stderr, "real buffer_size = %i, frags = %i, total = %i\n", buffer_size, setup.buf.block.frags, setup.buf.block.frags * buffer_size);
+ // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size);
}
/* playback write error hander */
ssize_t r;
ssize_t result = 0;
- if (xrun_mode == SND_PCM_XRUN_FRAGMENT &&
- count < buffer_size) {
- snd_pcm_format_set_silence(hwparams.format, data + count * bits_per_frame / 8, (buffer_size - count) * hwparams.channels);
- count = buffer_size;
+ if (sleep_min == 0 &&
+ count < chunk_size) {
+ snd_pcm_format_set_silence(hwparams.format, data + count * bits_per_frame / 8, (chunk_size - count) * hwparams.channels);
+ count = chunk_size;
}
while (count > 0) {
r = writei_func(handle, data, count);
ssize_t r;
size_t result = 0;
- if (xrun_mode == SND_PCM_XRUN_FRAGMENT &&
- count != buffer_size) {
+ if (sleep_min == 0 &&
+ count != chunk_size) {
unsigned int channel;
size_t offset = count;
- size_t remaining = buffer_size - count;
+ size_t remaining = chunk_size - count;
for (channel = 0; channel < channels; channel++)
snd_pcm_format_set_silence(hwparams.format, data[channel] + offset * bits_per_sample / 8, remaining);
- count = buffer_size;
+ count = chunk_size;
}
while (count > 0) {
unsigned int channel;
size_t result = 0;
size_t count = rcount;
- if (xrun_mode == SND_PCM_XRUN_FRAGMENT &&
- count != buffer_size) {
- count = buffer_size;
+ if (sleep_min == 0 &&
+ count != chunk_size) {
+ count = chunk_size;
}
while (count > 0) {
size_t result = 0;
size_t count = rcount;
- if (xrun_mode == SND_PCM_XRUN_FRAGMENT &&
- count != buffer_size) {
- count = buffer_size;
+ if (sleep_min == 0 &&
+ count != chunk_size) {
+ count = chunk_size;
}
while (count > 0) {
while (count > 0) {
size = count;
- if (size > buffer_bytes - buffer_pos)
- size = buffer_bytes - buffer_pos;
+ if (size > chunk_bytes - buffer_pos)
+ size = chunk_bytes - buffer_pos;
memcpy(audiobuf + buffer_pos, data, size);
data += size;
count -= size;
buffer_pos += size;
- if (buffer_pos == buffer_bytes) {
- if ((r = pcm_write(audiobuf, buffer_size)) != buffer_size)
+ if (buffer_pos == chunk_bytes) {
+ if ((r = pcm_write(audiobuf, chunk_size)) != chunk_size)
return r;
buffer_pos = 0;
}
unsigned l;
char *buf;
- buf = (char *) malloc(buffer_bytes);
+ buf = (char *) malloc(chunk_bytes);
if (buf == NULL) {
error("can't allocate buffer for silence");
return; /* not fatal error */
}
- snd_pcm_format_set_silence(hwparams.format, buf, buffer_size * hwparams.channels);
+ snd_pcm_format_set_silence(hwparams.format, buf, chunk_size * hwparams.channels);
while (x > 0) {
l = x;
- if (l > buffer_size)
- l = buffer_size;
+ if (l > chunk_size)
+ l = chunk_size;
if (voc_pcm_write(buf, l) != l) {
error("write error");
exit(EXIT_FAILURE);
{
if (buffer_pos > 0) {
size_t b;
- if (xrun_mode == SND_PCM_XRUN_FRAGMENT) {
- if (snd_pcm_format_set_silence(hwparams.format, audiobuf + buffer_pos, buffer_bytes - buffer_pos * 8 / bits_per_sample) < 0)
+ if (sleep_min == 0) {
+ if (snd_pcm_format_set_silence(hwparams.format, audiobuf + buffer_pos, chunk_bytes - buffer_pos * 8 / bits_per_sample) < 0)
fprintf(stderr, "voc_pcm_flush - silence error");
- b = buffer_size;
+ b = chunk_size;
} else {
b = buffer_pos * 8 / bits_per_frame;
}
fprintf(stderr, "Playing Creative Labs Channel file '%s'...\n", name);
}
/* first we waste the rest of header, ugly but we don't need seek */
- while (ofs > buffer_bytes) {
- if (safe_read(fd, buf, buffer_bytes) != buffer_bytes) {
+ while (ofs > chunk_bytes) {
+ if (safe_read(fd, buf, chunk_bytes) != chunk_bytes) {
error("read error");
exit(EXIT_FAILURE);
}
- ofs -= buffer_bytes;
+ ofs -= chunk_bytes;
}
if (ofs) {
if (safe_read(fd, buf, ofs) != ofs) {
if (in_buffer)
memcpy(buf, data, in_buffer);
data = buf;
- if ((l = safe_read(fd, buf + in_buffer, buffer_bytes - in_buffer)) > 0)
+ if ((l = safe_read(fd, buf + in_buffer, chunk_bytes - in_buffer)) > 0)
in_buffer += l;
else if (!in_buffer) {
/* the file is truncated, so simulate 'Terminator'
header(rtype, name);
set_params();
- while (loaded > buffer_bytes && written < count) {
- if (pcm_write(audiobuf + written, buffer_size) <= 0)
+ while (loaded > chunk_bytes && written < count) {
+ if (pcm_write(audiobuf + written, chunk_size) <= 0)
return;
- written += buffer_bytes;
- loaded -= buffer_bytes;
+ written += chunk_bytes;
+ loaded -= chunk_bytes;
}
if (written > 0 && loaded > 0)
memmove(audiobuf, audiobuf + written, loaded);
while (written < count) {
do {
c = count - written;
- if (c > buffer_bytes)
- c = buffer_bytes;
+ if (c > chunk_bytes)
+ c = chunk_bytes;
c -= l;
if (c == 0)
if (r == 0)
break;
l += r;
- } while (xrun_mode != SND_PCM_XRUN_ASAP && l < buffer_bytes);
+ } while (sleep_min == 0 && l < chunk_bytes);
l = l * 8 / bits_per_frame;
r = pcm_write(audiobuf, l);
if (r != l)
while (count > 0) {
c = count;
- if (c > buffer_bytes)
- c = buffer_bytes;
+ if (c > chunk_bytes)
+ c = chunk_bytes;
c = c * 8 / bits_per_frame;
if ((r = pcm_read(audiobuf, c)) != c)
break;
header(rtype, names[0]);
set_params();
- vsize = buffer_bytes / channels;
+ vsize = chunk_bytes / channels;
// Not yet implemented
assert(loaded == 0);
if (r == 0)
break;
c += r;
- } while (xrun_mode != SND_PCM_XRUN_ASAP && c < expected);
+ } while (sleep_min == 0 && c < expected);
c = c * 8 / bits_per_sample;
r = pcm_writev(bufs, channels, c);
if (r != c)
header(rtype, names[0]);
set_params();
- vsize = buffer_bytes / channels;
+ vsize = chunk_bytes / channels;
for (channel = 0; channel < channels; ++channel)
bufs[channel] = audiobuf + vsize * channel;
while (count > 0) {
size_t rv;
c = count;
- if (c > buffer_bytes)
- c = buffer_bytes;
+ if (c > chunk_bytes)
+ c = chunk_bytes;
c = c * 8 / bits_per_frame;
if ((r = pcm_readv(bufs, channels, c)) != c)
break;