mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-09 03:05:43 +01:00
Initial implementation of non interleaved play/record
This commit is contained in:
parent
25765774b5
commit
23221cc296
1 changed files with 383 additions and 122 deletions
505
aplay/aplay.c
505
aplay/aplay.c
|
@ -39,6 +39,7 @@
|
|||
#include <sys/asoundlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/uio.h>
|
||||
#include "aconfig.h"
|
||||
#include "formats.h"
|
||||
#include "version.h"
|
||||
|
@ -55,6 +56,8 @@
|
|||
|
||||
static ssize_t (*read_func)(snd_pcm_t *handle, void *buffer, size_t size);
|
||||
static ssize_t (*write_func)(snd_pcm_t *handle, const void *buffer, size_t size);
|
||||
static ssize_t (*readv_func)(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
|
||||
static ssize_t (*writev_func)(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
|
||||
|
||||
static char *command;
|
||||
static snd_pcm_t *pcm_handle;
|
||||
|
@ -64,7 +67,6 @@ static snd_pcm_channel_setup_t setup;
|
|||
static int timelimit = 0;
|
||||
static int quiet_mode = 0;
|
||||
static int verbose_mode = 0;
|
||||
static int format_change = 0;
|
||||
static int active_format = FORMAT_DEFAULT;
|
||||
static int mode = SND_PCM_MODE_BLOCK;
|
||||
static int direction = SND_PCM_OPEN_PLAYBACK;
|
||||
|
@ -89,15 +91,17 @@ static int vocmajor, vocminor;
|
|||
|
||||
static void playback(char *filename);
|
||||
static void capture(char *filename);
|
||||
static void playbackv(char **filenames, unsigned int count);
|
||||
static void capturev(char **filenames, unsigned int count);
|
||||
|
||||
static void begin_voc(int fd, u_long count);
|
||||
static void begin_voc(int fd, size_t count);
|
||||
static void end_voc(int fd);
|
||||
static void begin_wave(int fd, u_long count);
|
||||
static void begin_wave(int fd, size_t count);
|
||||
static void end_wave(int fd);
|
||||
static void begin_au(int fd, u_long count);
|
||||
static void begin_au(int fd, size_t count);
|
||||
|
||||
struct fmt_capture {
|
||||
void (*start) (int fd, u_long count);
|
||||
void (*start) (int fd, size_t count);
|
||||
void (*end) (int fd);
|
||||
char *what;
|
||||
} fmt_rec_table[] = {
|
||||
|
@ -222,6 +226,7 @@ static void usage(char *command)
|
|||
" -E mmap mode\n"
|
||||
" -N Don't use plugins\n"
|
||||
" -B Nonblocking mode\n"
|
||||
" -I Noninterleaved mode\n"
|
||||
" -S Show setup\n"
|
||||
,command, snd_cards()-1);
|
||||
fprintf(stderr, "\nRecognized data formats are:");
|
||||
|
@ -342,7 +347,7 @@ int main(int argc, char *argv[])
|
|||
version();
|
||||
return 0;
|
||||
}
|
||||
while ((c = getopt(argc, argv, "hlc:d:qs:o:t:vrwxc:p:mMVeEf:NBF:S")) != EOF)
|
||||
while ((c = getopt(argc, argv, "hlc:d:qs:o:t:vrwxc:p:mMVeEf:NBF:SI")) != EOF)
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(command);
|
||||
|
@ -443,6 +448,9 @@ int main(int argc, char *argv[])
|
|||
case 'S':
|
||||
show_setup = 1;
|
||||
break;
|
||||
case 'I':
|
||||
rformat.interleave = 0;
|
||||
break;
|
||||
default:
|
||||
usage(command);
|
||||
return 1;
|
||||
|
@ -496,23 +504,34 @@ int main(int argc, char *argv[])
|
|||
if (mmap_flag) {
|
||||
write_func = snd_pcm_mmap_write;
|
||||
read_func = snd_pcm_mmap_read;
|
||||
writev_func = snd_pcm_mmap_writev;
|
||||
readv_func = snd_pcm_mmap_readv;
|
||||
} else {
|
||||
write_func = snd_pcm_write;
|
||||
read_func = snd_pcm_read;
|
||||
writev_func = snd_pcm_writev;
|
||||
readv_func = snd_pcm_readv;
|
||||
}
|
||||
|
||||
if (optind > argc - 1) {
|
||||
if (channel == SND_PCM_CHANNEL_PLAYBACK)
|
||||
playback(NULL);
|
||||
else
|
||||
capture(NULL);
|
||||
} else {
|
||||
while (optind <= argc - 1) {
|
||||
if (rformat.interleave) {
|
||||
if (optind > argc - 1) {
|
||||
if (channel == SND_PCM_CHANNEL_PLAYBACK)
|
||||
playback(argv[optind++]);
|
||||
playback(NULL);
|
||||
else
|
||||
capture(argv[optind++]);
|
||||
capture(NULL);
|
||||
} else {
|
||||
while (optind <= argc - 1) {
|
||||
if (channel == SND_PCM_CHANNEL_PLAYBACK)
|
||||
playback(argv[optind++]);
|
||||
else
|
||||
capture(argv[optind++]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (channel == SND_PCM_CHANNEL_PLAYBACK)
|
||||
playbackv(&argv[optind], argc - optind);
|
||||
else
|
||||
capturev(&argv[optind], argc - optind);
|
||||
}
|
||||
snd_pcm_close(pcm_handle);
|
||||
return EXIT_SUCCESS;
|
||||
|
@ -646,12 +665,10 @@ static void setup_print(snd_pcm_channel_setup_t *setup)
|
|||
}
|
||||
}
|
||||
|
||||
static void set_format(void)
|
||||
static void set_params(void)
|
||||
{
|
||||
snd_pcm_channel_params_t params;
|
||||
|
||||
if (!format_change)
|
||||
return;
|
||||
align = (snd_pcm_format_physical_width(format.format) + 7) / 8;
|
||||
|
||||
if (mmap_flag)
|
||||
|
@ -710,12 +727,11 @@ static void set_format(void)
|
|||
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);
|
||||
format_change = 0;
|
||||
}
|
||||
|
||||
/* playback write error hander */
|
||||
|
||||
void playback_write_error(void)
|
||||
void playback_underrun(void)
|
||||
{
|
||||
snd_pcm_channel_status_t status;
|
||||
|
||||
|
@ -739,7 +755,7 @@ void playback_write_error(void)
|
|||
|
||||
/* capture read error hander */
|
||||
|
||||
void capture_read_error(void)
|
||||
void capture_overrun(void)
|
||||
{
|
||||
snd_pcm_channel_status_t status;
|
||||
|
||||
|
@ -769,53 +785,75 @@ void capture_read_error(void)
|
|||
|
||||
static ssize_t pcm_write(u_char *data, size_t count)
|
||||
{
|
||||
char *buf = data;
|
||||
ssize_t result = count, r;
|
||||
ssize_t r;
|
||||
ssize_t result = 0;
|
||||
|
||||
count += align - 1;
|
||||
count -= count % align;
|
||||
if (mode == SND_PCM_MODE_BLOCK) {
|
||||
if (count != buffer_size)
|
||||
snd_pcm_format_set_silence(format.format, buf + count, buffer_size - count);
|
||||
while (1) {
|
||||
int bytes = write_func(pcm_handle, buf, buffer_size);
|
||||
if (bytes == -EAGAIN || bytes == 0) {
|
||||
struct pollfd pfd;
|
||||
pfd.fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
pfd.events = POLLOUT | POLLERR;
|
||||
poll(&pfd, 1, 1000);
|
||||
} else if (bytes == -EPIPE) {
|
||||
playback_write_error();
|
||||
} else if (bytes != buffer_size) {
|
||||
fprintf(stderr, "write error: %s\n", snd_strerror(bytes));
|
||||
exit(EXIT_FAILURE);
|
||||
} else break;
|
||||
}
|
||||
} else {
|
||||
while (count > 0) {
|
||||
if (mode == SND_PCM_MODE_BLOCK &&
|
||||
count != buffer_size) {
|
||||
snd_pcm_format_set_silence(format.format, data + count, buffer_size - count);
|
||||
count = buffer_size;
|
||||
}
|
||||
while (count > 0) {
|
||||
struct pollfd pfd;
|
||||
r = write_func(pcm_handle, data, count);
|
||||
if (r == -EAGAIN || (r >= 0 && r < count)) {
|
||||
struct pollfd pfd;
|
||||
r = write_func(pcm_handle, buf, count);
|
||||
if (r == -EPIPE) {
|
||||
playback_write_error();
|
||||
continue;
|
||||
}
|
||||
if (r < 0 && r != -EAGAIN) {
|
||||
fprintf(stderr, "write error: %s\n", snd_strerror(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (r != count) {
|
||||
pfd.fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
pfd.events = POLLOUT | POLLERR;
|
||||
#ifdef FIXED_STREAM_POLL
|
||||
poll(&pfd, 1, 1000);
|
||||
#else
|
||||
poll(&pfd, 1, 50);
|
||||
#endif
|
||||
}
|
||||
if (r > 0) {
|
||||
count -= r;
|
||||
buf += r;
|
||||
}
|
||||
pfd.fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
pfd.events = POLLOUT | POLLERR;
|
||||
poll(&pfd, 1, 1000);
|
||||
} else if (r == -EPIPE) {
|
||||
playback_underrun();
|
||||
} else if (r < 0) {
|
||||
fprintf(stderr, "write error: %s\n", snd_strerror(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (r > 0) {
|
||||
result += r;
|
||||
count -= r;
|
||||
data += r;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t pcm_writev(u_char **data, unsigned int voices, size_t count)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t result = 0;
|
||||
|
||||
if (mode == SND_PCM_MODE_BLOCK &&
|
||||
count != buffer_size) {
|
||||
unsigned int voice;
|
||||
size_t offset = count / voices;
|
||||
size_t remaining = (buffer_size - count) / voices;
|
||||
for (voice = 0; voice < voices; voice++)
|
||||
snd_pcm_format_set_silence(format.format, data[voice] + offset, remaining);
|
||||
count = buffer_size;
|
||||
}
|
||||
while (count > 0) {
|
||||
unsigned int voice;
|
||||
struct iovec vec[voices];
|
||||
size_t offset = result / voices;
|
||||
size_t remaining = count / voices;
|
||||
for (voice = 0; voice < voices; voice++) {
|
||||
vec[voice].iov_base = data[voice] + offset;
|
||||
vec[voice].iov_len = remaining;
|
||||
}
|
||||
r = writev_func(pcm_handle, vec, voices);
|
||||
if (r == -EAGAIN || (r >= 0 && r < count)) {
|
||||
struct pollfd pfd;
|
||||
pfd.fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
pfd.events = POLLOUT | POLLERR;
|
||||
poll(&pfd, 1, 1000);
|
||||
} else if (r == -EPIPE) {
|
||||
playback_underrun();
|
||||
} else if (r < 0) {
|
||||
fprintf(stderr, "writev error: %s\n", snd_strerror(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (r > 0) {
|
||||
result += r;
|
||||
count -= r;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -830,26 +868,58 @@ static ssize_t pcm_read(u_char *data, size_t count)
|
|||
ssize_t r;
|
||||
size_t result = 0;
|
||||
|
||||
while (result < count) {
|
||||
r = read_func(pcm_handle, audiobuf + result, count - result);
|
||||
if (r == -EAGAIN || (r >= 0 && r < count - result)) {
|
||||
while (count > 0) {
|
||||
r = read_func(pcm_handle, data, count);
|
||||
if (r == -EAGAIN || (r >= 0 && r < count)) {
|
||||
struct pollfd pfd;
|
||||
pfd.fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_CAPTURE);
|
||||
pfd.events = POLLIN | POLLERR;
|
||||
#ifndef FIXED_STREAM_POLL
|
||||
if (mode == SND_PCM_MODE_STREAM)
|
||||
poll(&pfd, 1, 50);
|
||||
else
|
||||
#endif
|
||||
poll(&pfd, 1, 1000);
|
||||
poll(&pfd, 1, 1000);
|
||||
} else if (r == -EPIPE) {
|
||||
capture_read_error();
|
||||
capture_overrun();
|
||||
} else if (r < 0) {
|
||||
fprintf(stderr, "read error: %s\n", snd_strerror(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (r > 0)
|
||||
if (r > 0) {
|
||||
result += r;
|
||||
count -= r;
|
||||
data += r;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t pcm_readv(u_char **data, unsigned int voices, size_t count)
|
||||
{
|
||||
ssize_t r;
|
||||
size_t result = 0;
|
||||
|
||||
while (count > 0) {
|
||||
unsigned int voice;
|
||||
struct iovec vec[voices];
|
||||
size_t offset = result / voices;
|
||||
size_t remaining = count / voices;
|
||||
for (voice = 0; voice < voices; voice++) {
|
||||
vec[voice].iov_base = data[voice] + offset;
|
||||
vec[voice].iov_len = remaining;
|
||||
}
|
||||
r = readv_func(pcm_handle, vec, voices);
|
||||
if (r == -EAGAIN || (r >= 0 && r < count)) {
|
||||
struct pollfd pfd;
|
||||
pfd.fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_CAPTURE);
|
||||
pfd.events = POLLIN | POLLERR;
|
||||
poll(&pfd, 1, 1000);
|
||||
} else if (r == -EPIPE) {
|
||||
capture_overrun();
|
||||
} else if (r < 0) {
|
||||
fprintf(stderr, "readv error: %s\n", snd_strerror(r));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (r > 0) {
|
||||
result += r;
|
||||
count -= r;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -880,18 +950,14 @@ static ssize_t voc_pcm_write(u_char *data, size_t count)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* writing zeros from the zerobuf to simulate silence,
|
||||
* perhaps it's enough to use a long var instead of zerobuf ?
|
||||
*/
|
||||
static void voc_write_zeros(unsigned x)
|
||||
static void voc_write_silence(unsigned x)
|
||||
{
|
||||
unsigned l;
|
||||
char *buf;
|
||||
|
||||
buf = (char *) malloc(buffer_size);
|
||||
if (buf == NULL) {
|
||||
fprintf(stderr, "%s: can allocate buffer for zeros\n", command);
|
||||
fprintf(stderr, "%s: can allocate buffer for silence\n", command);
|
||||
return; /* not fatal error */
|
||||
}
|
||||
snd_pcm_format_set_silence(format.format, buf, buffer_size);
|
||||
|
@ -927,11 +993,11 @@ static void voc_play(int fd, int ofs, char *name)
|
|||
VocBlockType *bp;
|
||||
VocVoiceData *vd;
|
||||
VocExtBlock *eb;
|
||||
u_long nextblock, in_buffer;
|
||||
size_t nextblock, in_buffer;
|
||||
u_char *data, *buf;
|
||||
char was_extended = 0, output = 0;
|
||||
u_short *sp, repeat = 0;
|
||||
u_long silence;
|
||||
size_t silence;
|
||||
int filepos = 0;
|
||||
|
||||
#define COUNT(x) nextblock -= x; in_buffer -= x; data += x
|
||||
|
@ -963,8 +1029,7 @@ static void voc_play(int fd, int ofs, char *name)
|
|||
format.format = SND_PCM_SFMT_U8;
|
||||
format.voices = 1;
|
||||
format.rate = DEFAULT_SPEED;
|
||||
format_change = 1;
|
||||
set_format();
|
||||
set_params();
|
||||
|
||||
in_buffer = nextblock = 0;
|
||||
while (1) {
|
||||
|
@ -1022,8 +1087,7 @@ static void voc_play(int fd, int ofs, char *name)
|
|||
format.voices = 2;
|
||||
was_extended = 0;
|
||||
}
|
||||
format_change = 1;
|
||||
set_format();
|
||||
set_params();
|
||||
break;
|
||||
case 2: /* nothing to do, pure data */
|
||||
#if 0
|
||||
|
@ -1036,13 +1100,12 @@ static void voc_play(int fd, int ofs, char *name)
|
|||
format.rate = (int) (*data);
|
||||
COUNT1(1);
|
||||
format.rate = 1000000 / (256 - format.rate);
|
||||
format_change = 1;
|
||||
set_format();
|
||||
silence = (((u_long) * sp) * 1000) / format.rate;
|
||||
set_params();
|
||||
silence = (((size_t) * sp) * 1000) / format.rate;
|
||||
#if 0
|
||||
d_printf("Silence for %d ms\n", (int) silence);
|
||||
#endif
|
||||
voc_write_zeros(*sp);
|
||||
voc_write_silence(*sp);
|
||||
break;
|
||||
case 4: /* a marker for syncronisation, no effect */
|
||||
sp = (u_short *) data;
|
||||
|
@ -1154,9 +1217,9 @@ static void init_raw_data(void)
|
|||
}
|
||||
|
||||
/* calculate the data count to read from/to dsp */
|
||||
static u_long calc_count(void)
|
||||
static size_t calc_count(void)
|
||||
{
|
||||
u_long count;
|
||||
size_t count;
|
||||
|
||||
if (!timelimit) {
|
||||
count = 0x7fffffff;
|
||||
|
@ -1169,7 +1232,7 @@ static u_long calc_count(void)
|
|||
}
|
||||
|
||||
/* write a .VOC-header */
|
||||
static void begin_voc(int fd, u_long cnt)
|
||||
static void begin_voc(int fd, size_t cnt)
|
||||
{
|
||||
VocHeader vh;
|
||||
VocBlockType bt;
|
||||
|
@ -1221,7 +1284,7 @@ static void begin_voc(int fd, u_long cnt)
|
|||
}
|
||||
|
||||
/* write a WAVE-header */
|
||||
static void begin_wave(int fd, u_long cnt)
|
||||
static void begin_wave(int fd, size_t cnt)
|
||||
{
|
||||
WaveHeader wh;
|
||||
int bits;
|
||||
|
@ -1263,7 +1326,7 @@ static void begin_wave(int fd, u_long cnt)
|
|||
}
|
||||
|
||||
/* write a Au-header */
|
||||
static void begin_au(int fd, u_long cnt)
|
||||
static void begin_au(int fd, size_t cnt)
|
||||
{
|
||||
AuHeader ah;
|
||||
|
||||
|
@ -1331,41 +1394,47 @@ static void header(int rtype, char *name)
|
|||
|
||||
/* playing raw data */
|
||||
|
||||
void playback_go(int fd, int loaded, u_long count, int rtype, char *name)
|
||||
void playback_go(int fd, size_t loaded, size_t count, int rtype, char *name)
|
||||
{
|
||||
int l, r;
|
||||
u_long c;
|
||||
size_t written = 0;
|
||||
size_t c;
|
||||
|
||||
header(rtype, name);
|
||||
format_change = 1;
|
||||
set_format();
|
||||
set_params();
|
||||
|
||||
l = 0;
|
||||
while (loaded > buffer_size) {
|
||||
if (pcm_write(audiobuf + l, buffer_size) <= 0)
|
||||
while (loaded > buffer_size && written < count) {
|
||||
if (pcm_write(audiobuf + written, buffer_size) <= 0)
|
||||
return;
|
||||
l += buffer_size;
|
||||
loaded -= l;
|
||||
written += buffer_size;
|
||||
loaded -= buffer_size;
|
||||
}
|
||||
if (written > 0 && loaded > 0)
|
||||
memmove(audiobuf, audiobuf + written, loaded);
|
||||
|
||||
l = loaded;
|
||||
while (count > 0) {
|
||||
while (written < count) {
|
||||
do {
|
||||
c = count;
|
||||
if (c + l > buffer_size)
|
||||
c = buffer_size - l;
|
||||
|
||||
c = count - written;
|
||||
if (c > buffer_size)
|
||||
c = buffer_size;
|
||||
c -= l;
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
r = read(fd, audiobuf + l, c);
|
||||
if (r <= 0)
|
||||
if (r < 0) {
|
||||
perror(name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
l += r;
|
||||
} while (mode != SND_PCM_MODE_STREAM && l < buffer_size);
|
||||
l = pcm_write(audiobuf, l);
|
||||
if (l <= 0)
|
||||
r = pcm_write(audiobuf, l);
|
||||
if (r != l)
|
||||
break;
|
||||
count -= l;
|
||||
written += r;
|
||||
l = 0;
|
||||
}
|
||||
snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
|
@ -1373,20 +1442,19 @@ void playback_go(int fd, int loaded, u_long count, int rtype, char *name)
|
|||
|
||||
/* captureing raw data, this proc handels WAVE files and .VOCs (as one block) */
|
||||
|
||||
void capture_go(int fd, int loaded, u_long count, int rtype, char *name)
|
||||
void capture_go(int fd, size_t count, int rtype, char *name)
|
||||
{
|
||||
size_t c;
|
||||
ssize_t r;
|
||||
|
||||
header(rtype, name);
|
||||
format_change = 1;
|
||||
set_format();
|
||||
set_params();
|
||||
|
||||
while (count > 0) {
|
||||
c = count;
|
||||
if (c > buffer_size)
|
||||
c = buffer_size;
|
||||
if ((r = pcm_read(audiobuf, c)) <= 0)
|
||||
if ((r = pcm_read(audiobuf, c)) != c)
|
||||
break;
|
||||
if (write(fd, audiobuf, r) != r) {
|
||||
perror(name);
|
||||
|
@ -1459,7 +1527,7 @@ static void capture(char *name)
|
|||
{
|
||||
int fd;
|
||||
|
||||
snd_pcm_capture_flush(pcm_handle);
|
||||
snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_CAPTURE);
|
||||
if (!name || !strcmp(name, "-")) {
|
||||
fd = 1;
|
||||
name = "stdout";
|
||||
|
@ -1476,6 +1544,199 @@ static void capture(char *name)
|
|||
if (fmt_rec_table[active_format].start)
|
||||
fmt_rec_table[active_format].start(fd, count);
|
||||
check_new_format(&rformat);
|
||||
capture_go(fd, 0, count, active_format, name);
|
||||
capture_go(fd, count, active_format, name);
|
||||
fmt_rec_table[active_format].end(fd);
|
||||
}
|
||||
|
||||
void playbackv_go(int* fds, unsigned int voices, size_t loaded, size_t count, int rtype, char **names)
|
||||
{
|
||||
int r;
|
||||
size_t c, expected;
|
||||
size_t vsize;
|
||||
unsigned int voice;
|
||||
u_char *bufs[voices];
|
||||
|
||||
header(rtype, names[0]);
|
||||
set_params();
|
||||
|
||||
vsize = buffer_size / voices;
|
||||
|
||||
// Not yet implemented
|
||||
assert(loaded == 0);
|
||||
|
||||
for (voice = 0; voice < voices; ++voice)
|
||||
bufs[voice] = audiobuf + vsize * voice;
|
||||
|
||||
while (count > 0) {
|
||||
size_t c = 0;
|
||||
size_t expected = count / voices;
|
||||
if (expected > vsize)
|
||||
expected = vsize;
|
||||
do {
|
||||
r = read(fds[0], bufs[0], expected);
|
||||
if (r < 0) {
|
||||
perror(names[voice]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (voice = 1; voice < voices; ++voice) {
|
||||
if (read(fds[voice], bufs[voice], r) != r) {
|
||||
perror(names[voice]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
c += r;
|
||||
} while (mode != SND_PCM_MODE_STREAM && c < expected);
|
||||
r = pcm_writev(bufs, voices, c * voices);
|
||||
if (r != c * voices)
|
||||
break;
|
||||
count -= r;
|
||||
}
|
||||
snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
}
|
||||
|
||||
void capturev_go(int* fds, unsigned int voices, size_t count, int rtype, char **names)
|
||||
{
|
||||
size_t c;
|
||||
ssize_t r;
|
||||
unsigned int voice;
|
||||
size_t vsize;
|
||||
u_char *bufs[voices];
|
||||
|
||||
header(rtype, names[0]);
|
||||
set_params();
|
||||
|
||||
vsize = buffer_size / voices;
|
||||
|
||||
for (voice = 0; voice < voices; ++voice)
|
||||
bufs[voice] = audiobuf + vsize * voice;
|
||||
|
||||
while (count > 0) {
|
||||
size_t rv;
|
||||
c = count;
|
||||
if (c > buffer_size)
|
||||
c = buffer_size;
|
||||
if ((r = pcm_readv(bufs, voices, c)) != c)
|
||||
break;
|
||||
rv = r / voices;
|
||||
for (voice = 0; voice < voices; ++voice) {
|
||||
if (write(fds[voice], bufs[voice], rv) != rv) {
|
||||
perror(names[voice]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
count -= r;
|
||||
}
|
||||
}
|
||||
|
||||
static void playbackv(char **names, unsigned int count)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int voice;
|
||||
unsigned int voices = rformat.voices;
|
||||
int alloced = 0;
|
||||
int fds[voices];
|
||||
for (voice = 0; voice < voices; ++voice)
|
||||
fds[voice] = -1;
|
||||
|
||||
snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
|
||||
if (count == 1) {
|
||||
size_t len = strlen(names[0]);
|
||||
char format[1024];
|
||||
memcpy(format, names[0], len);
|
||||
strcpy(format + len, ".%d");
|
||||
len += 4;
|
||||
names = malloc(sizeof(*names) * voices);
|
||||
for (voice = 0; voice < voices; ++voice) {
|
||||
names[voice] = malloc(len);
|
||||
sprintf(names[voice], format, voice);
|
||||
}
|
||||
alloced = 1;
|
||||
} else if (count != voices) {
|
||||
fprintf(stderr, "You need to specify %d files\n", voices);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (voice = 0; voice < voices; ++voice) {
|
||||
fds[voice] = open(names[voice], O_RDONLY, 0);
|
||||
if (fds[voice] < 0) {
|
||||
perror(names[voice]);
|
||||
ret = EXIT_FAILURE;
|
||||
goto __end;
|
||||
}
|
||||
}
|
||||
/* should be raw data */
|
||||
check_new_format(&rformat);
|
||||
init_raw_data();
|
||||
count = calc_count();
|
||||
playbackv_go(fds, voices, 0, count, FORMAT_RAW, names);
|
||||
|
||||
__end:
|
||||
for (voice = 0; voice < voices; ++voice) {
|
||||
if (fds[voice] >= 0)
|
||||
close(fds[voice]);
|
||||
if (alloced)
|
||||
free(names[voice]);
|
||||
}
|
||||
if (alloced)
|
||||
free(names);
|
||||
if (ret)
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
static void capturev(char **names, unsigned int count)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int voice;
|
||||
unsigned int voices = rformat.voices;
|
||||
int alloced = 0;
|
||||
int fds[voices];
|
||||
for (voice = 0; voice < voices; ++voice)
|
||||
fds[voice] = -1;
|
||||
|
||||
snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_CAPTURE);
|
||||
if (count == 1) {
|
||||
size_t len = strlen(names[0]);
|
||||
char format[1024];
|
||||
memcpy(format, names[0], len);
|
||||
strcpy(format + len, ".%d");
|
||||
len += 4;
|
||||
names = malloc(sizeof(*names) * voices);
|
||||
for (voice = 0; voice < voices; ++voice) {
|
||||
names[voice] = malloc(len);
|
||||
sprintf(names[voice], format, voice);
|
||||
}
|
||||
alloced = 1;
|
||||
} else if (count != voices) {
|
||||
fprintf(stderr, "You need to specify %d files\n", voices);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (voice = 0; voice < voices; ++voice) {
|
||||
fds[voice] = open(names[voice], O_WRONLY + O_CREAT, 0644);
|
||||
if (fds[voice] < 0) {
|
||||
perror(names[voice]);
|
||||
ret = EXIT_FAILURE;
|
||||
goto __end;
|
||||
}
|
||||
}
|
||||
/* should be raw data */
|
||||
check_new_format(&rformat);
|
||||
init_raw_data();
|
||||
count = calc_count();
|
||||
capturev_go(fds, voices, count, FORMAT_RAW, names);
|
||||
|
||||
__end:
|
||||
for (voice = 0; voice < voices; ++voice) {
|
||||
if (fds[voice] >= 0)
|
||||
close(fds[voice]);
|
||||
if (alloced)
|
||||
free(names[voice]);
|
||||
}
|
||||
if (alloced)
|
||||
free(names);
|
||||
if (ret)
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue