static int stream = SND_PCM_STREAM_PLAYBACK;
static int mmap_flag = 0;
static snd_pcm_mmap_control_t *mmap_control = NULL;
+static snd_pcm_mmap_status_t *mmap_status = NULL;
static char *mmap_data = NULL;
static int noplugin = 0;
static int nonblock = 0;
static int frag_length = 250;
static int show_setup = 0;
static int buffer_pos = 0;
+static size_t bits_per_sample, bits_per_frame;
+static size_t buffer_bytes;
static int count;
static int vocmajor, vocminor;
memset(¶ms, 0, sizeof(params));
params.mode = mode;
params.stream = stream;
- memcpy(¶ms.format, &format, sizeof(format));
+ params.format = format;
if (stream == SND_PCM_STREAM_PLAYBACK) {
params.start_mode = SND_PCM_START_FULL;
} else {
params.start_mode = SND_PCM_START_DATA;
}
params.xrun_mode = SND_PCM_XRUN_FLUSH;
- params.frag_size = snd_pcm_format_bytes_per_second(&format) / 1000.0 * frag_length;
+ params.frag_size = format.rate * frag_length / 1000;
params.buffer_size = params.frag_size * 4;
- params.bytes_min = 0;
- params.bytes_xrun_max = 0;
+ params.frames_min = format.rate / 16;
+ params.frames_xrun_max = 0;
params.fill_mode = SND_PCM_FILL_SILENCE;
- params.bytes_fill_max = 1024;
- params.bytes_xrun_max = 0;
+ params.frames_fill_max = 1024;
+ params.frames_xrun_max = 0;
if (snd_pcm_stream_params(pcm_handle, ¶ms) < 0) {
fprintf(stderr, "%s: unable to set stream params\n", command);
exit(EXIT_FAILURE);
}
if (mmap_flag) {
- if (snd_pcm_mmap(pcm_handle, stream, &mmap_control, (void **)&mmap_data)<0) {
+ if (snd_pcm_mmap(pcm_handle, stream, &mmap_status, &mmap_control, (void **)&mmap_data)<0) {
fprintf(stderr, "%s: unable to mmap memory\n", command);
exit(EXIT_FAILURE);
}
snd_pcm_dump_setup(pcm_handle, stream, stderr);
buffer_size = setup.frag_size;
- audiobuf = (char *)realloc(audiobuf, buffer_size > 1024 ? buffer_size : 1024);
+ bits_per_sample = snd_pcm_format_physical_width(setup.format.format);
+ bits_per_frame = bits_per_sample * setup.format.channels;
+ buffer_bytes = buffer_size * bits_per_frame / 8;
+ audiobuf = malloc(buffer_bytes);
if (audiobuf == NULL) {
fprintf(stderr, "%s: not enough memory\n", command);
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
if (status.state == SND_PCM_STATE_XRUN) {
- printf("underrun at position %u!!!\n", status.byte_io);
+ fprintf(stderr, "underrun at position %u!!!\n", status.frame_io);
if (snd_pcm_stream_prepare(pcm_handle, SND_PCM_STREAM_PLAYBACK)<0) {
fprintf(stderr, "underrun: playback stream prepare error\n");
exit(EXIT_FAILURE);
if (status.state == SND_PCM_STATE_RUNNING)
return; /* everything is ok, but the driver is waiting for data */
if (status.state == SND_PCM_STATE_XRUN) {
- printf("overrun at position %u!!!\n", status.byte_io);
+ fprintf(stderr, "overrun at position %u!!!\n", status.frame_io);
if (snd_pcm_stream_prepare(pcm_handle, SND_PCM_STREAM_CAPTURE)<0) {
fprintf(stderr, "overrun: capture stream prepare error\n");
exit(EXIT_FAILURE);
if (mode == SND_PCM_MODE_FRAGMENT &&
count != buffer_size) {
- snd_pcm_format_set_silence(format.format, data + count, buffer_size - count);
+ snd_pcm_format_set_silence(format.format, data + count * bits_per_frame / 8, buffer_size * format.channels);
count = buffer_size;
}
while (count > 0) {
if (r > 0) {
result += r;
count -= r;
- data += r;
+ data += r * bits_per_frame / 8;
}
}
return result;
if (mode == SND_PCM_MODE_FRAGMENT &&
count != buffer_size) {
unsigned int channel;
- size_t offset = count / channels;
- size_t remaining = (buffer_size - count) / channels;
+ size_t offset = count;
+ size_t remaining = buffer_size - count;
for (channel = 0; channel < channels; channel++)
- snd_pcm_format_set_silence(format.format, data[channel] + offset, remaining);
+ snd_pcm_format_set_silence(format.format, data[channel] + offset * bits_per_sample / 8, remaining);
count = buffer_size;
}
while (count > 0) {
unsigned int channel;
struct iovec vec[channels];
- size_t offset = result / channels;
- size_t remaining = count / channels;
+ size_t offset = result;
+ size_t remaining = count;
for (channel = 0; channel < channels; channel++) {
- vec[channel].iov_base = data[channel] + offset;
+ vec[channel].iov_base = data[channel] + offset * bits_per_sample / 8;
vec[channel].iov_len = remaining;
}
r = writev_func(pcm_handle, vec, channels);
if (r > 0) {
result += r;
count -= r;
- data += r;
+ data += r * bits_per_frame / 8;
}
}
return result;
while (count > 0) {
unsigned int channel;
struct iovec vec[channels];
- size_t offset = result / channels;
- size_t remaining = count / channels;
+ size_t offset = result;
+ size_t remaining = count;
for (channel = 0; channel < channels; channel++) {
- vec[channel].iov_base = data[channel] + offset;
+ vec[channel].iov_base = data[channel] + offset * bits_per_sample / 8;
vec[channel].iov_len = remaining;
}
r = readv_func(pcm_handle, vec, channels);
while (count > 0) {
size = count;
- if (size > buffer_size - buffer_pos)
- size = buffer_size - buffer_pos;
+ if (size > buffer_bytes - buffer_pos)
+ size = buffer_bytes - buffer_pos;
memcpy(audiobuf + buffer_pos, data, size);
data += size;
count -= size;
buffer_pos += size;
- if (buffer_pos == buffer_size) {
+ if (buffer_pos == buffer_bytes) {
if ((r = pcm_write(audiobuf, buffer_size)) != buffer_size)
return r;
buffer_pos = 0;
unsigned l;
char *buf;
- buf = (char *) malloc(buffer_size);
+ buf = (char *) malloc(buffer_bytes);
if (buf == NULL) {
fprintf(stderr, "%s: can allocate buffer for silence\n", command);
return; /* not fatal error */
}
- snd_pcm_format_set_silence(format.format, buf, buffer_size);
+ snd_pcm_format_set_silence(format.format, buf, buffer_size * format.channels);
while (x > 0) {
l = x;
if (l > buffer_size)
static void voc_pcm_flush(void)
{
if (buffer_pos > 0) {
+ size_t b;
if (mode == SND_PCM_MODE_FRAGMENT) {
- if (snd_pcm_format_set_silence(format.format, audiobuf + buffer_pos, buffer_size - buffer_pos) < 0)
+ if (snd_pcm_format_set_silence(format.format, audiobuf + buffer_pos, buffer_bytes - buffer_pos * 8 / bits_per_sample) < 0)
fprintf(stderr, "voc_pcm_flush - silence error\n");
- buffer_pos = buffer_size;
+ b = buffer_size;
+ } else {
+ b = buffer_pos * 8 / bits_per_frame;
}
- if (pcm_write(audiobuf, buffer_pos) != buffer_pos)
+ if (pcm_write(audiobuf, b) != b)
fprintf(stderr, "voc_pcm_flush error\n");
}
snd_pcm_stream_flush(pcm_handle, SND_PCM_STREAM_PLAYBACK);
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_size) {
- if (read(fd, buf, buffer_size) != buffer_size) {
+ while (ofs > buffer_bytes) {
+ if (read(fd, buf, buffer_bytes) != buffer_bytes) {
fprintf(stderr, "%s: read error\n", command);
exit(EXIT_FAILURE);
}
- ofs -= buffer_size;
+ ofs -= buffer_bytes;
}
if (ofs) {
if (read(fd, buf, ofs) != ofs) {
if (in_buffer)
memcpy(buf, data, in_buffer);
data = buf;
- if ((l = read(fd, buf + in_buffer, buffer_size - in_buffer)) > 0)
+ if ((l = read(fd, buf + in_buffer, buffer_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_size && written < count) {
+ while (loaded > buffer_bytes && written < count) {
if (pcm_write(audiobuf + written, buffer_size) <= 0)
return;
- written += buffer_size;
- loaded -= buffer_size;
+ written += buffer_bytes;
+ loaded -= buffer_bytes;
}
if (written > 0 && loaded > 0)
memmove(audiobuf, audiobuf + written, loaded);
while (written < count) {
do {
c = count - written;
- if (c > buffer_size)
- c = buffer_size;
+ if (c > buffer_bytes)
+ c = buffer_bytes;
c -= l;
if (c == 0)
if (r == 0)
break;
l += r;
- } while (mode != SND_PCM_MODE_FRAME && l < buffer_size);
+ } while (mode != SND_PCM_MODE_FRAME && l < buffer_bytes);
+ l = l * 8 / bits_per_frame;
r = pcm_write(audiobuf, l);
if (r != l)
break;
+ r = r * bits_per_frame / 8;
written += r;
l = 0;
}
while (count > 0) {
c = count;
- if (c > buffer_size)
- c = buffer_size;
+ if (c > buffer_bytes)
+ c = buffer_bytes;
+ c = c * 8 / bits_per_frame;
if ((r = pcm_read(audiobuf, c)) != c)
break;
+ r = r * bits_per_frame / 8;
if (write(fd, audiobuf, r) != r) {
perror(name);
exit(EXIT_FAILURE);
header(rtype, names[0]);
set_params();
- vsize = buffer_size / channels;
+ vsize = buffer_bytes / channels;
// Not yet implemented
assert(loaded == 0);
break;
c += r;
} while (mode != SND_PCM_MODE_FRAME && c < expected);
- r = pcm_writev(bufs, channels, c * channels);
- if (r != c * channels)
+ c = c * 8 / bits_per_sample;
+ r = pcm_writev(bufs, channels, c);
+ if (r != c)
break;
+ r = r * bits_per_frame / 8;
count -= r;
}
snd_pcm_stream_flush(pcm_handle, SND_PCM_STREAM_PLAYBACK);
header(rtype, names[0]);
set_params();
- vsize = buffer_size / channels;
+ vsize = buffer_bytes / channels;
for (channel = 0; channel < channels; ++channel)
bufs[channel] = audiobuf + vsize * channel;
while (count > 0) {
size_t rv;
c = count;
- if (c > buffer_size)
- c = buffer_size;
+ if (c > buffer_bytes)
+ c = buffer_bytes;
+ c = c * 8 / bits_per_frame;
if ((r = pcm_readv(bufs, channels, c)) != c)
break;
- rv = r / channels;
+ rv = r * bits_per_sample / 8;
for (channel = 0; channel < channels; ++channel) {
if (write(fds[channel], bufs[channel], rv) != rv) {
perror(names[channel]);
exit(EXIT_FAILURE);
}
}
+ r = r * bits_per_frame / 8;
count -= r;
}
}