#include <netinet/in.h>
#include <sys/asoundlib.h>
#include <assert.h>
+#include <sys/poll.h>
#include "aconfig.h"
#include "formats.h"
#include "version.h"
/* global data */
-char *command;
-snd_pcm_t *pcm_handle;
-struct snd_pcm_channel_info cinfo;
-snd_pcm_format_t rformat, format;
-int timelimit = 0;
-int quiet_mode = 0;
-int verbose_mode = 0;
-int format_change = 0;
-int active_format = FORMAT_DEFAULT;
-int mode = SND_PCM_MODE_BLOCK;
-int direction = SND_PCM_OPEN_PLAYBACK;
-int channel = SND_PCM_CHANNEL_PLAYBACK;
-int mmap_flag = 0;
-int noplugin = 0;
-int frag = 0;
-int frags = 0;
-char *audiobuf = NULL;
-snd_pcm_mmap_control_t *mmap_control = NULL;
-char *mmap_data = NULL;
-long mmap_size = 0;
-int buffer_size = -1;
-char silence = 0;
-
-int count;
-int vocmajor, vocminor;
-
-/* functions */
-
-int (*fcn_info)(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
-int (*fcn_params)(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
-int (*fcn_setup)(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
-int (*fcn_prepare)(snd_pcm_t *handle, int channel);
-int (*fcn_status)(snd_pcm_t *handle, snd_pcm_channel_status_t *status);
-int (*fcn_flush)(snd_pcm_t *handle, int channel);
-ssize_t (*fcn_write)(snd_pcm_t *handle, const void *buffer, size_t size);
-ssize_t (*fcn_read)(snd_pcm_t *handle, void *buffer, size_t size);
-int (*fcn_mmap)(snd_pcm_t *handle, int channel, snd_pcm_mmap_control_t **control, void **buffer);
-int (*fcn_munmap)(snd_pcm_t *handle, int channel);
-int (*fcn_go)(snd_pcm_t *handle, int channel);
+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 char *command;
+static snd_pcm_t *pcm_handle;
+static snd_pcm_channel_info_t cinfo;
+static snd_pcm_format_t rformat, format;
+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;
+static int channel = SND_PCM_CHANNEL_PLAYBACK;
+static int mmap_flag = 0;
+static snd_pcm_mmap_control_t *mmap_control = NULL;
+static char *mmap_data = NULL;
+static int noplugin = 0;
+static int nonblock = 0;
+static char *audiobuf = NULL;
+static int align = 1;
+static int buffer_size = -1;
+/* 250 ms */
+static int frag_length = 250;
+static int show_setup = 0;
+static int buffer_pos = 0;
+
+static int count;
+static int vocmajor, vocminor;
/* needed prototypes */
{ begin_au, end_wave, "Sparc Audio" }
};
-struct {
- char *name;
- int format;
-} formats[] = {
- { "s8", SND_PCM_SFMT_S8 },
- { "u8", SND_PCM_SFMT_U8 },
- { "8", SND_PCM_SFMT_U8 },
- { "s16l", SND_PCM_SFMT_S16_LE },
- { "16", SND_PCM_SFMT_S16_LE },
- { "s16b", SND_PCM_SFMT_S16_BE },
- { "u16l", SND_PCM_SFMT_U16_LE },
- { "u16b", SND_PCM_SFMT_U16_BE },
- { "s24l", SND_PCM_SFMT_S24_LE },
- { "s24b", SND_PCM_SFMT_S24_BE },
- { "u24l", SND_PCM_SFMT_U24_LE },
- { "u24b", SND_PCM_SFMT_U24_BE },
- { "s32l", SND_PCM_SFMT_S32_LE },
- { "s32b", SND_PCM_SFMT_S32_BE },
- { "u32l", SND_PCM_SFMT_U32_LE },
- { "u32b", SND_PCM_SFMT_U32_BE },
- { "f32l", SND_PCM_SFMT_FLOAT_LE },
- { "f32b", SND_PCM_SFMT_FLOAT_BE },
- { "f64l", SND_PCM_SFMT_FLOAT64_LE },
- { "f64b", SND_PCM_SFMT_FLOAT64_BE },
- { "iec958l", SND_PCM_SFMT_IEC958_SUBFRAME_LE },
- { "iec958b", SND_PCM_SFMT_IEC958_SUBFRAME_BE },
- { "mulaw", SND_PCM_SFMT_MU_LAW },
- { "alaw", SND_PCM_SFMT_A_LAW },
- { "adpcm", SND_PCM_SFMT_IMA_ADPCM },
- { "mpeg", SND_PCM_SFMT_MPEG },
- { "gsm", SND_PCM_SFMT_GSM },
- { "special", SND_PCM_SFMT_SPECIAL }
-};
+typedef struct {
+ int value;
+ const char* desc;
+} assoc_t;
+
+static const char *assoc(int value, assoc_t *alist)
+{
+ while (alist->desc) {
+ if (value == alist->value)
+ return alist->desc;
+ alist++;
+ }
+ return "UNKNOWN";
+}
-#define NUMFORMATS (sizeof(formats)/sizeof(formats[0]))
+#define CHN(v) { SND_PCM_CHANNEL_##v, #v }
+#define MODE(v) { SND_PCM_MODE_##v, #v }
+#define FMT(v) { SND_PCM_SFMT_##v, #v }
+#define XRUN(v) { SND_PCM_XRUN_##v, #v }
+#define START(v) { SND_PCM_START_##v, #v }
+#define FILL(v) { SND_PCM_FILL_##v, #v }
+#define END { 0, NULL }
+
+static assoc_t chns[] = { CHN(PLAYBACK), CHN(CAPTURE), END };
+static assoc_t modes[] = { MODE(STREAM), MODE(BLOCK), END };
+static assoc_t fmts[] = { FMT(S8), FMT(U8),
+ FMT(S16_LE), FMT(S16_BE), FMT(U16_LE), FMT(U16_BE),
+ FMT(S24_LE), FMT(S24_BE), FMT(U24_LE), FMT(U24_BE),
+ FMT(S32_LE), FMT(S32_BE), FMT(U32_LE), FMT(U32_BE),
+ FMT(FLOAT_LE), FMT(FLOAT_BE), FMT(FLOAT64_LE), FMT(FLOAT64_BE),
+ FMT(IEC958_SUBFRAME_LE), FMT(IEC958_SUBFRAME_BE),
+ FMT(MU_LAW), FMT(A_LAW), FMT(IMA_ADPCM),
+ FMT(MPEG), FMT(GSM), FMT(SPECIAL), END };
+static assoc_t starts[] = { START(GO), START(DATA), START(FULL), END };
+static assoc_t xruns[] = { XRUN(FLUSH), XRUN(DRAIN), END };
+static assoc_t fills[] = { FILL(NONE), FILL(SILENCE_WHOLE), FILL(SILENCE), END };
+static assoc_t onoff[] = { {0, "OFF"}, {1, "ON"}, {-1, "ON"}, END };
static void check_new_format(snd_pcm_format_t * format)
{
- if (cinfo.min_rate > format->rate || cinfo.max_rate < format->rate) {
- fprintf(stderr, "%s: unsupported rate %iHz (valid range is %iHz-%iHz)\n", command, format->rate, cinfo.min_rate, cinfo.max_rate);
- exit(1);
+ if (cinfo.rates & (SND_PCM_RATE_CONTINUOUS|SND_PCM_RATE_KNOT)) {
+ if (format->rate < cinfo.min_rate ||
+ format->rate > cinfo.max_rate) {
+ fprintf(stderr, "%s: unsupported rate %iHz (valid range is %iHz-%iHz)\n", command, format->rate, cinfo.min_rate, cinfo.max_rate);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ unsigned int r;
+ switch (format->rate) {
+ case 8000: r = SND_PCM_RATE_8000; break;
+ case 11025: r = SND_PCM_RATE_11025; break;
+ case 16000: r = SND_PCM_RATE_16000; break;
+ case 22050: r = SND_PCM_RATE_22050; break;
+ case 32000: r = SND_PCM_RATE_32000; break;
+ case 44100: r = SND_PCM_RATE_44100; break;
+ case 48000: r = SND_PCM_RATE_48000; break;
+ case 88200: r = SND_PCM_RATE_88200; break;
+ case 96000: r = SND_PCM_RATE_96000; break;
+ case 176400: r = SND_PCM_RATE_176400; break;
+ case 192000: r = SND_PCM_RATE_192000; break;
+ default: r = 0; break;
+ }
+ if (!(cinfo.rates & r)) {
+ fprintf(stderr, "%s: unsupported rate %iHz\n", command, format->rate);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (cinfo.min_voices > format->voices || cinfo.max_voices < format->voices) {
+ fprintf(stderr, "%s: unsupported number of voices %i (valid range is %i-%i)\n", command, format->voices, cinfo.min_voices, cinfo.max_voices);
+ exit(EXIT_FAILURE);
}
if (!(cinfo.formats & (1 << format->format))) {
- fprintf(stderr, "%s: requested format %s isn't supported with hardware\n", command, snd_pcm_get_format_name(format->format));
- exit(1);
+ fprintf(stderr, "%s: unsupported format %s\n", command, snd_pcm_get_format_name(format->format));
+ exit(EXIT_FAILURE);
+ }
+ if (format->voices > 1) {
+ if (format->interleave) {
+ if (!(cinfo.flags & SND_PCM_CHNINFO_INTERLEAVE)) {
+ fprintf(stderr, "%s: unsupported interleaved format\n", command);
+ exit(EXIT_FAILURE);
+ }
+ } else if (!(cinfo.flags & SND_PCM_CHNINFO_NONINTERLEAVE)) {
+ fprintf(stderr, "%s: unsupported non interleaved format\n", command);
+ exit(EXIT_FAILURE);
+ }
}
}
static void usage(char *command)
{
- int i;
+ assoc_t *f;
fprintf(stderr,
"Usage: %s [switches] [filename] <filename> ...\n"
"Available switches:\n"
" -v file format Voc\n"
" -w file format Wave\n"
" -r file format Raw\n"
- " -S stereo\n"
" -o <voices> voices (1-N)\n"
" -s <Hz> speed (Hz)\n"
" -f <format> data format\n"
+ " -F <msec> fragment length\n"
" -m set CD-ROM quality (44100Hz,stereo,16-bit linear,little endian)\n"
" -M set DAT quality (48000Hz,stereo,16-bit linear,little endian)\n"
" -t <secs> timelimit (seconds)\n"
" -e stream mode\n"
" -E mmap mode\n"
" -N Don't use plugins\n"
+ " -B Nonblocking mode\n"
+ " -S Show setup\n"
,command, snd_cards()-1);
fprintf(stderr, "\nRecognized data formats are:");
- for (i = 0; i < NUMFORMATS; ++i)
- fprintf(stderr, " %s", formats[i].name);
+ for (f = fmts; f->desc; ++f)
+ fprintf(stderr, " %s", f->desc);
fprintf(stderr, " (some of these may not be available on selected hardware)\n");
}
snd_ctl_t *handle;
int card, err, dev, idx;
unsigned int mask;
- struct snd_ctl_hw_info info;
+ snd_ctl_hw_info_t info;
snd_pcm_info_t pcminfo;
snd_pcm_channel_info_t chninfo;
mask = snd_cards_mask();
if (!mask) {
- printf("%s: no soundcards found...\n", command);
+ fprintf(stderr, "%s: no soundcards found...\n", command);
return;
}
for (card = 0; card < SND_CARDS; card++) {
if (!(mask & (1 << card)))
continue;
if ((err = snd_ctl_open(&handle, card)) < 0) {
- printf("Error: control open (%i): %s\n", card, snd_strerror(err));
+ fprintf(stderr, "Error: control open (%i): %s\n", card, snd_strerror(err));
continue;
}
if ((err = snd_ctl_hw_info(handle, &info)) < 0) {
- printf("Error: control hardware info (%i): %s\n", card, snd_strerror(err));
+ fprintf(stderr, "Error: control hardware info (%i): %s\n", card, snd_strerror(err));
snd_ctl_close(handle);
continue;
}
for (dev = 0; dev < info.pcmdevs; dev++) {
if ((err = snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0) {
- printf("Error: control digital audio info (%i): %s\n", card, snd_strerror(err));
+ fprintf(stderr, "Error: control digital audio info (%i): %s\n", card, snd_strerror(err));
continue;
}
- printf("%s: %i [%s] / #%i: %s\n",
+ fprintf(stderr, "%s: %i [%s] / #%i: %s\n",
info.name,
card + 1,
info.id,
dev,
pcminfo.name);
- printf(" Directions: %s%s%s\n",
+ fprintf(stderr, " Directions: %s%s%s\n",
pcminfo.flags & SND_PCM_INFO_PLAYBACK ? "playback " : "",
pcminfo.flags & SND_PCM_INFO_CAPTURE ? "capture " : "",
pcminfo.flags & SND_PCM_INFO_DUPLEX ? "duplex " : "");
- printf(" Playback subdevices: %i\n", pcminfo.playback + 1);
- printf(" Capture subdevices: %i\n", pcminfo.capture + 1);
+ fprintf(stderr, " Playback subdevices: %i\n", pcminfo.playback + 1);
+ fprintf(stderr, " Capture subdevices: %i\n", pcminfo.capture + 1);
if (pcminfo.flags & SND_PCM_INFO_PLAYBACK) {
for (idx = 0; idx <= pcminfo.playback; idx++) {
memset(&chninfo, 0, sizeof(chninfo));
chninfo.channel = SND_PCM_CHANNEL_PLAYBACK;
if ((err = snd_ctl_pcm_channel_info(handle, dev, SND_PCM_CHANNEL_PLAYBACK, idx, &chninfo)) < 0) {
- printf("Error: control digital audio playback info (%i): %s\n", card, snd_strerror(err));
+ fprintf(stderr, "Error: control digital audio playback info (%i): %s\n", card, snd_strerror(err));
} else {
- printf(" Playback subdevice #%i: %s\n", idx, chninfo.subname);
+ fprintf(stderr, " Playback subdevice #%i: %s\n", idx, chninfo.subname);
}
}
}
memset(&chninfo, 0, sizeof(chninfo));
chninfo.channel = SND_PCM_CHANNEL_CAPTURE;
if ((err = snd_ctl_pcm_channel_info(handle, dev, SND_PCM_CHANNEL_CAPTURE, 0, &chninfo)) < 0) {
- printf("Error: control digital audio capture info (%i): %s\n", card, snd_strerror(err));
+ fprintf(stderr, "Error: control digital audio capture info (%i): %s\n", card, snd_strerror(err));
} else {
- printf(" Capture subdevice #%i: %s\n", idx, chninfo.subname);
+ fprintf(stderr, " Capture subdevice #%i: %s\n", idx, chninfo.subname);
}
}
}
version();
return 0;
}
- while ((c = getopt(argc, argv, "hlc:d:qs:So:t:vrwxB:c:p:mMVeEf:N")) != EOF)
+ while ((c = getopt(argc, argv, "hlc:d:qs:o:t:vrwxc:p:mMVeEf:NBF:S")) != EOF)
switch (c) {
case 'h':
usage(command);
return 1;
}
break;
- case 'S':
- rformat.voices = 2;
- break;
case 'o':
tmp = atoi(optarg);
if (tmp < 1 || tmp > 32) {
verbose_mode = 1;
quiet_mode = 0;
break;
- case 'f':
- for (tmp = 0; tmp < NUMFORMATS; ++tmp) {
- if (!strcmp(optarg, formats[tmp].name)) {
- rformat.format = formats[tmp].format;
- active_format = FORMAT_RAW;
+ case 'f': {
+ assoc_t *f;
+ for (f = fmts; f->desc; ++f) {
+ if (!strcasecmp(optarg, f->desc)) {
break;
}
}
- if (tmp == NUMFORMATS) {
+ if (!f->desc) {
fprintf(stderr, "Error: wrong extended format '%s'\n", optarg);
- return 1;
+ exit(EXIT_FAILURE);
}
+ rformat.format = f->value;
+ active_format = FORMAT_RAW;
break;
+ }
case 'm':
case 'M':
rformat.format = SND_PCM_SFMT_S16_LE;
version();
return 0;
case 'e':
- if (!mmap_flag)
- mode = SND_PCM_MODE_STREAM;
+ mode = SND_PCM_MODE_STREAM;
break;
case 'E':
- if (mode == SND_PCM_MODE_BLOCK)
- mmap_flag = 1;
+ mmap_flag = 1;
break;
case 'N':
noplugin = 1;
break;
+ case 'B':
+ nonblock = 1;
+ break;
+ case 'F':
+ frag_length = atoi(optarg);
+ break;
+ case 'S':
+ show_setup = 1;
+ break;
default:
usage(command);
return 1;
if (!quiet_mode)
version();
- if (noplugin) {
- fcn_info = snd_pcm_channel_info;
- fcn_params = snd_pcm_channel_params;
- fcn_setup = snd_pcm_channel_setup;
- fcn_prepare = snd_pcm_channel_prepare;
- fcn_status = snd_pcm_channel_status;
- fcn_flush = snd_pcm_channel_flush;
- fcn_write = snd_pcm_write;
- fcn_read = snd_pcm_read;
- fcn_mmap = snd_pcm_mmap;
- fcn_munmap = snd_pcm_munmap;
- fcn_go = snd_pcm_channel_go;
- } else {
- fcn_info = snd_pcm_plugin_info;
- fcn_params = snd_pcm_plugin_params;
- fcn_setup = snd_pcm_plugin_setup;
- fcn_prepare = snd_pcm_plugin_prepare;
- fcn_status = snd_pcm_plugin_status;
- fcn_flush = snd_pcm_plugin_flush;
- fcn_write = snd_pcm_plugin_write;
- fcn_read = snd_pcm_plugin_read;
- fcn_mmap = snd_pcm_plugin_mmap;
- fcn_munmap = snd_pcm_plugin_munmap;
- fcn_go = snd_pcm_plugin_go;
- }
-
if (!quiet_mode) {
char *cardname;
fprintf(stderr, "Using soundcard '%s'\n", cardname);
free(cardname);
}
- if ((err = snd_pcm_open(&pcm_handle, card, dev, direction)) < 0) {
+
+ if (noplugin)
+ err = snd_pcm_open(&pcm_handle, card, dev, direction);
+ else
+ err = snd_pcm_plug_open(&pcm_handle, card, dev, direction);
+ if (err < 0) {
fprintf(stderr, "Error: audio open error: %s\n", snd_strerror(err));
return 1;
}
+ if (nonblock) {
+ err = snd_pcm_channel_nonblock(pcm_handle, channel, 1);
+ if (err < 0) {
+ fprintf(stderr, "nonblock setting error: %s\n", snd_strerror(err));
+ return 1;
+ }
+ }
memset(&cinfo, 0, sizeof(cinfo));
cinfo.channel = channel;
- if ((err = fcn_info(pcm_handle, &cinfo)) < 0) {
+ if ((err = snd_pcm_channel_info(pcm_handle, &cinfo)) < 0) {
fprintf(stderr, "Error: channel info error: %s\n", snd_strerror(err));
return 1;
}
return 1;
}
+ if (mmap_flag) {
+ write_func = snd_pcm_mmap_write;
+ read_func = snd_pcm_mmap_read;
+ } else {
+ write_func = snd_pcm_write;
+ read_func = snd_pcm_read;
+ }
+
if (optind > argc - 1) {
if (channel == SND_PCM_CHANNEL_PLAYBACK)
playback(NULL);
}
}
snd_pcm_close(pcm_handle);
- return 0;
+ return EXIT_SUCCESS;
}
/*
wp->sub_chunk == WAV_FMT && wp->data_chunk == WAV_DATA) {
if (wp->format != WAV_PCM_CODE) {
fprintf(stderr, "%s: can't play not PCM-coded WAVE-files\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (wp->modus < 1 || wp->modus > 32) {
fprintf(stderr, "%s: can't play WAVE-files with %d tracks\n",
command, wp->modus);
- exit(1);
+ exit(EXIT_FAILURE);
}
format.voices = wp->modus;
switch (wp->bit_p_spl) {
return -1;
if (read(fd, buffer + sizeof(AuHeader), ntohl(ap->hdr_size) - sizeof(AuHeader)) < 0) {
fprintf(stderr, "%s: read error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
check_new_format(&format);
return 0;
}
-/*
- * writing zeros from the zerobuf to simulate silence,
- * perhaps it's enough to use a long var instead of zerobuf ?
- */
-static void write_zeros(unsigned x)
+static void setup_print(snd_pcm_channel_setup_t *setup)
{
- unsigned l;
- char *buf;
-
- buf = (char *) malloc(buffer_size);
- if (!buf) {
- fprintf(stderr, "%s: can allocate buffer for zeros\n", command);
- return; /* not fatal error */
- }
- memset(buf, 128, buffer_size);
- while (x > 0) {
- l = x;
- if (l > buffer_size)
- l = buffer_size;
- if (fcn_write(pcm_handle, buf, l) != l) {
- fprintf(stderr, "%s: write error\n", command);
- exit(1);
- }
- x -= l;
+ fprintf(stderr, "channel: %s\n", assoc(setup->channel, chns));
+ fprintf(stderr, "mode: %s\n", assoc(setup->mode, modes));
+ fprintf(stderr, "format: %s\n", assoc(setup->format.format, fmts));
+ fprintf(stderr, "voices: %d\n", setup->format.voices);
+ fprintf(stderr, "rate: %d\n", setup->format.rate);
+ // digital
+ fprintf(stderr, "start_mode: %s\n", assoc(setup->start_mode, starts));
+ fprintf(stderr, "xrun_mode: %s\n", assoc(setup->xrun_mode, xruns));
+ fprintf(stderr, "time: %s\n", assoc(setup->time, onoff));
+ // ust_time
+ // sync
+ fprintf(stderr, "buffer_size: %d\n", setup->buffer_size);
+ fprintf(stderr, "frag_size: %d\n", setup->frag_size);
+ fprintf(stderr, "frags: %d\n", setup->frags);
+ fprintf(stderr, "frag_boundary: %d\n", setup->frag_boundary);
+ fprintf(stderr, "pos_boundary: %d\n", setup->pos_boundary);
+ fprintf(stderr, "msbits_per_sample: %d\n", setup->msbits_per_sample);
+ if (setup->mode == SND_PCM_MODE_STREAM) {
+ fprintf(stderr, "bytes_min: %d\n", setup->buf.stream.bytes_min);
+ fprintf(stderr, "bytes_align: %d\n", setup->buf.stream.bytes_align);
+ fprintf(stderr, "bytes_xrun_max: %d\n", setup->buf.stream.bytes_xrun_max);
+ fprintf(stderr, "fill: %s\n", assoc(setup->buf.stream.fill, fills));
+ fprintf(stderr, "bytes_fill_max: %d\n", setup->buf.stream.bytes_fill_max);
+ } else if (setup->mode == SND_PCM_MODE_BLOCK) {
+ fprintf(stderr, "frags_min: %d\n", setup->buf.block.frags_min);
+ fprintf(stderr, "frags_xrun_max: %d\n", setup->buf.block.frags_xrun_max);
}
}
static void set_format(void)
{
- unsigned int bps; /* bytes per second */
- unsigned int size; /* fragment size */
- struct snd_pcm_channel_params params;
- struct snd_pcm_channel_setup setup;
+ snd_pcm_channel_params_t params;
if (!format_change)
return;
- bps = format.rate * format.voices;
- silence = 0x00;
- switch (format.format) {
- case SND_PCM_SFMT_U8:
- silence = 0x80;
- break;
- case SND_PCM_SFMT_U16_LE:
- case SND_PCM_SFMT_U16_BE:
- bps <<= 1;
- silence = 0x80;
- break;
- case SND_PCM_SFMT_S8:
- silence = 0x00;
- break;
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_S16_BE:
- bps <<= 1;
- silence = 0x00;
- break;
- case SND_PCM_SFMT_IMA_ADPCM:
- bps >>= 2;
- silence = 0x00;
- break;
- }
- bps >>= 2; /* ok.. this buffer should be 0.25 sec */
- if (bps < 16)
- bps = 16;
- size = 1;
- while ((size << 1) < bps)
- size <<= 1;
+ align = (snd_pcm_format_physical_width(format.format) + 7) / 8;
if (mmap_flag)
- fcn_munmap(pcm_handle, channel);
- fcn_flush(pcm_handle, channel); /* to be in right state */
+ snd_pcm_munmap(pcm_handle, channel);
+ snd_pcm_channel_flush(pcm_handle, channel); /* to be in right state */
+
memset(¶ms, 0, sizeof(params));
params.mode = mode;
params.channel = channel;
} else {
params.start_mode = SND_PCM_START_DATA;
}
- params.stop_mode = SND_PCM_STOP_STOP;
+ params.xrun_mode = SND_PCM_XRUN_FLUSH;
+ params.frag_size = snd_pcm_format_bytes_per_second(&format) / 1000.0 * frag_length;
+ params.buffer_size = params.frag_size * 4;
if (mode == SND_PCM_MODE_BLOCK) {
- params.buf.block.frag_size = size;
- // params.buf.block.frag_size = 128;
- params.buf.block.frags_max = -1; /* little trick (playback only) */
- // params.buf.block.frags_max = 1;
params.buf.block.frags_min = 1;
+ params.buf.block.frags_xrun_max = 0;
} else {
- params.buf.stream.queue_size = 1024 * 1024; /* maximum */
- // params.buf.stream.queue_size = 8192;
params.buf.stream.fill = SND_PCM_FILL_SILENCE;
- params.buf.stream.max_fill = 1024;
+ params.buf.stream.bytes_fill_max = 1024;
+ params.buf.stream.bytes_min = 1024;
+ params.buf.stream.bytes_xrun_max = 0;
}
- if (fcn_params(pcm_handle, ¶ms) < 0) {
+ if (snd_pcm_channel_params(pcm_handle, ¶ms) < 0) {
fprintf(stderr, "%s: unable to set channel params\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (mmap_flag) {
- if (fcn_mmap(pcm_handle, channel, &mmap_control, (void **)&mmap_data)<0) {
+ if (snd_pcm_mmap(pcm_handle, channel, &mmap_control, (void **)&mmap_data)<0) {
fprintf(stderr, "%s: unable to mmap memory\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
- if (fcn_prepare(pcm_handle, channel) < 0) {
+ if (snd_pcm_channel_prepare(pcm_handle, channel) < 0) {
fprintf(stderr, "%s: unable to prepare channel\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
memset(&setup, 0, sizeof(setup));
setup.channel = channel;
- if (fcn_setup(pcm_handle, &setup) < 0) {
+ if (snd_pcm_channel_setup(pcm_handle, &setup) < 0) {
fprintf(stderr, "%s: unable to obtain setup\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
- frags = setup.buf.block.frags;
- buffer_size = mode == SND_PCM_MODE_BLOCK ?
- setup.buf.block.frag_size :
- setup.buf.stream.queue_size;
- audiobuf = (char *)realloc(audiobuf, buffer_size);
+
+ if (show_setup)
+ setup_print(&setup);
+
+ buffer_size = setup.frag_size;
+ audiobuf = (char *)realloc(audiobuf, buffer_size > 1024 ? buffer_size : 1024);
if (audiobuf == NULL) {
fprintf(stderr, "%s: not enough memory\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
- // printf("real buffer_size = %i, frags = %i, total = %i\n", buffer_size, setup.buf.block.frags, setup.buf.block.frags * buffer_size);
+ // 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)
+{
+ snd_pcm_channel_status_t status;
+
+ memset(&status, 0, sizeof(status));
+ status.channel = channel;
+ if (snd_pcm_channel_status(pcm_handle, &status)<0) {
+ fprintf(stderr, "playback channel status error\n");
+ exit(EXIT_FAILURE);
+ }
+ if (status.status == SND_PCM_STATUS_XRUN) {
+ printf("underrun at position %u!!!\n", status.pos_io);
+ if (snd_pcm_channel_prepare(pcm_handle, SND_PCM_CHANNEL_PLAYBACK)<0) {
+ fprintf(stderr, "underrun: playback channel prepare error\n");
+ exit(EXIT_FAILURE);
+ }
+ return; /* ok, data should be accepted again */
+ }
+ fprintf(stderr, "write error\n");
+ exit(EXIT_FAILURE);
+}
+
+/* capture read error hander */
+
+void capture_read_error(void)
+{
+ snd_pcm_channel_status_t status;
+
+ memset(&status, 0, sizeof(status));
+ status.channel = channel;
+ if (snd_pcm_channel_status(pcm_handle, &status)<0) {
+ fprintf(stderr, "capture channel status error\n");
+ exit(EXIT_FAILURE);
+ }
+ if (status.status == SND_PCM_STATUS_RUNNING)
+ return; /* everything is ok, but the driver is waiting for data */
+ if (status.status == SND_PCM_STATUS_XRUN) {
+ printf("overrun at position %u!!!\n", status.pos_io);
+ if (snd_pcm_channel_prepare(pcm_handle, SND_PCM_CHANNEL_CAPTURE)<0) {
+ fprintf(stderr, "overrun: capture channel prepare error\n");
+ exit(EXIT_FAILURE);
+ }
+ return; /* ok, data should be accepted again */
+ }
+ fprintf(stderr, "read error\n");
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * write function
+ */
+
+static ssize_t pcm_write(u_char *data, size_t count)
+{
+ char *buf = data;
+ ssize_t result = count, r;
+
+ 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) {
+ 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;
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ * read function
+ */
+
+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)) {
+ 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);
+ } else if (r == -EPIPE) {
+ capture_read_error();
+ } else if (r < 0) {
+ fprintf(stderr, "read error: %s\n", snd_strerror(r));
+ exit(EXIT_FAILURE);
+ }
+ if (r > 0)
+ result += r;
+ }
+ return result;
+}
+
/*
* ok, let's play a .voc file
*/
+static ssize_t voc_pcm_write(u_char *data, size_t count)
+{
+ ssize_t result = count, r;
+ size_t size;
+
+ while (count > 0) {
+ size = count;
+ if (size > buffer_size - buffer_pos)
+ size = buffer_size - buffer_pos;
+ memcpy(audiobuf + buffer_pos, data, size);
+ data += size;
+ count -= size;
+ buffer_pos += size;
+ if (buffer_pos == buffer_size) {
+ if ((r = pcm_write(audiobuf, buffer_size)) != buffer_size)
+ return r;
+ buffer_pos = 0;
+ }
+ }
+ 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)
+{
+ unsigned l;
+ char *buf;
+
+ buf = (char *) malloc(buffer_size);
+ if (buf == NULL) {
+ fprintf(stderr, "%s: can allocate buffer for zeros\n", command);
+ return; /* not fatal error */
+ }
+ snd_pcm_format_set_silence(format.format, buf, buffer_size);
+ while (x > 0) {
+ l = x;
+ if (l > buffer_size)
+ l = buffer_size;
+ if (voc_pcm_write(buf, l) != l) {
+ fprintf(stderr, "%s: write error\n", command);
+ exit(EXIT_FAILURE);
+ }
+ x -= l;
+ }
+}
+
+static void voc_pcm_flush(void)
+{
+ if (buffer_pos > 0) {
+ if (mode == SND_PCM_MODE_BLOCK) {
+ if (snd_pcm_format_set_silence(format.format, audiobuf + buffer_pos, buffer_size - buffer_pos) < 0)
+ fprintf(stderr, "voc_pcm_flush - silence error\n");
+ buffer_pos = buffer_size;
+ }
+ if (pcm_write(audiobuf, buffer_pos) != buffer_pos)
+ fprintf(stderr, "voc_pcm_flush error\n");
+ }
+ snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
+}
+
static void voc_play(int fd, int ofs, char *name)
{
int l;
VocVoiceData *vd;
VocExtBlock *eb;
u_long nextblock, in_buffer;
- u_char *data = audiobuf;
+ u_char *data, *buf;
char was_extended = 0, output = 0;
u_short *sp, repeat = 0;
u_long silence;
int filepos = 0;
-#define COUNT(x) nextblock -= x; in_buffer -=x ;data += x
-#define COUNT1(x) in_buffer -=x ;data += x
+#define COUNT(x) nextblock -= x; in_buffer -= x; data += x
+#define COUNT1(x) in_buffer -= x; data += x
+ data = buf = (u_char *)malloc(64 * 1024);
+ buffer_pos = 0;
+ if (data == NULL) {
+ fprintf(stderr, "malloc error\n");
+ exit(EXIT_FAILURE);
+ }
if (!quiet_mode) {
fprintf(stderr, "Playing Creative Labs Voice 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, audiobuf, buffer_size) != buffer_size) {
+ if (read(fd, buf, buffer_size) != buffer_size) {
fprintf(stderr, "%s: read error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
ofs -= buffer_size;
}
- if (ofs)
- if (read(fd, audiobuf, ofs) != ofs) {
+ if (ofs) {
+ if (read(fd, buf, ofs) != ofs) {
fprintf(stderr, "%s: read error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
+ }
format.format = SND_PCM_SFMT_U8;
format.voices = 1;
format.rate = DEFAULT_SPEED;
while (1) {
Fill_the_buffer: /* need this for repeat */
if (in_buffer < 32) {
- /* move the rest of buffer to pos 0 and fill the audiobuf up */
+ /* move the rest of buffer to pos 0 and fill the buf up */
if (in_buffer)
- memcpy(audiobuf, data, in_buffer);
- data = audiobuf;
- if ((l = read(fd, audiobuf + in_buffer, buffer_size - in_buffer)) > 0)
+ memcpy(buf, data, in_buffer);
+ data = buf;
+ if ((l = read(fd, buf + in_buffer, buffer_size - in_buffer)) > 0)
in_buffer += l;
else if (!in_buffer) {
/* the file is truncated, so simulate 'Terminator'
- and reduce the datablock for save landing */
- nextblock = audiobuf[0] = 0;
+ and reduce the datablock for safe landing */
+ nextblock = buf[0] = 0;
if (l == -1) {
perror(name);
- exit(-1);
+ exit(EXIT_FAILURE);
}
}
}
while (!nextblock) { /* this is a new block */
if (in_buffer < sizeof(VocBlockType))
- return;
+ goto __end;
bp = (VocBlockType *) data;
COUNT1(sizeof(VocBlockType));
nextblock = VOC_DATALEN(bp);
#if 0
d_printf("Silence for %d ms\n", (int) silence);
#endif
- write_zeros(*sp);
- snd_pcm_playback_flush(pcm_handle);
+ voc_write_zeros(*sp);
break;
case 4: /* a marker for syncronisation, no effect */
sp = (u_short *) data;
if (output && !quiet_mode) {
if (write(2, data, l) != l) { /* to stderr */
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
} else {
- if (fcn_write(pcm_handle, data, l) != l) {
+ if (voc_pcm_write(data, l) != l) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
COUNT(l);
}
} /* while(1) */
+ __end:
+ voc_pcm_flush();
+ free(buf);
}
/* that was a big one, perhaps somebody split it :-) */
{
u_long count;
- if (!timelimit)
+ if (!timelimit) {
count = 0x7fffffff;
- else {
- count = timelimit * format.rate * format.voices;
- switch (format.format) {
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_S16_BE:
- case SND_PCM_SFMT_U16_LE:
- case SND_PCM_SFMT_U16_BE:
- count *= 2;
- break;
- case SND_PCM_SFMT_S24_LE:
- case SND_PCM_SFMT_S24_BE:
- case SND_PCM_SFMT_U24_LE:
- case SND_PCM_SFMT_U24_BE:
- case SND_PCM_SFMT_S32_LE:
- case SND_PCM_SFMT_S32_BE:
- case SND_PCM_SFMT_U32_LE:
- case SND_PCM_SFMT_U32_BE:
- count *= 4;
- break;
- case SND_PCM_SFMT_IMA_ADPCM:
- count /= 4;
- break;
- }
+ } else {
+ count = snd_pcm_format_size(format.format,
+ timelimit * format.rate *
+ format.voices);
}
return count;
}
if (write(fd, &vh, sizeof(VocHeader)) != sizeof(VocHeader)) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (format.voices > 1) {
/* write a extended block */
bt.datalen_m = bt.datalen_h = 0;
if (write(fd, &bt, sizeof(VocBlockType)) != sizeof(VocBlockType)) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
eb.tc = (u_short) (65536 - 256000000L / (format.rate << 1));
eb.pack = 0;
eb.mode = 1;
if (write(fd, &eb, sizeof(VocExtBlock)) != sizeof(VocExtBlock)) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
bt.type = 1;
bt.datalen_h = (u_char) ((cnt & 0xFF0000) >> 16);
if (write(fd, &bt, sizeof(VocBlockType)) != sizeof(VocBlockType)) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
vd.tc = (u_char) (256 - (1000000 / format.rate));
vd.pack = 0;
if (write(fd, &vd, sizeof(VocVoiceData)) != sizeof(VocVoiceData)) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
break;
default:
fprintf(stderr, "%s: Wave doesn't support %s format...\n", command, snd_pcm_get_format_name(format.format));
- exit(1);
+ exit(EXIT_FAILURE);
}
wh.main_chunk = WAV_RIFF;
wh.length = cnt + sizeof(WaveHeader) - 8;
wh.data_length = cnt;
if (write(fd, &wh, sizeof(WaveHeader)) != sizeof(WaveHeader)) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
break;
default:
fprintf(stderr, "%s: Sparc Audio doesn't support %s format...\n", command, snd_pcm_get_format_name(format.format));
- exit(1);
+ exit(EXIT_FAILURE);
}
ah.sample_rate = htonl(format.rate);
ah.channels = htonl(format.voices);
if (write(fd, &ah, sizeof(AuHeader)) != sizeof(AuHeader)) {
fprintf(stderr, "%s: write error\n", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
char dummy = 0; /* Write a Terminator */
if (write(fd, &dummy, 1) != 1) {
fprintf(stderr, "%s: write error", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (fd != 1)
close(fd);
}
}
-/* playback write error hander */
-
-void playback_write_error(void)
-{
- snd_pcm_channel_status_t status;
-
- memset(&status, 0, sizeof(status));
- status.channel = channel;
- if (fcn_status(pcm_handle, &status)<0) {
- fprintf(stderr, "playback channel status error\n");
- exit(1);
- }
- if (status.status == SND_PCM_STATUS_UNDERRUN) {
- printf("underrun at position %u!!!\n", status.scount);
- if (fcn_prepare(pcm_handle, SND_PCM_CHANNEL_PLAYBACK)<0) {
- fprintf(stderr, "underrun: playback channel prepare error\n");
- exit(1);
- }
- frag = 0;
- return; /* ok, data should be accepted again */
- }
- fprintf(stderr, "write error\n");
- exit(1);
-}
-
-/* capture read error hander */
-
-void capture_read_error(void)
-{
- snd_pcm_channel_status_t status;
-
- memset(&status, 0, sizeof(status));
- status.channel = channel;
- if (fcn_status(pcm_handle, &status)<0) {
- fprintf(stderr, "capture channel status error\n");
- exit(1);
- }
- if (status.status == SND_PCM_STATUS_RUNNING)
- return; /* everything is ok, but the driver is waiting for data */
- if (status.status == SND_PCM_STATUS_OVERRUN) {
- printf("overrun at position %u!!!\n", status.scount);
- if (fcn_prepare(pcm_handle, SND_PCM_CHANNEL_CAPTURE)<0) {
- fprintf(stderr, "overrun: capture channel prepare error\n");
- exit(1);
- }
- frag = 0;
- return; /* ok, data should be accepted again */
- }
- fprintf(stderr, "read error\n");
- exit(1);
-}
-
/* playing raw data */
void playback_go(int fd, int loaded, u_long count, int rtype, char *name)
format_change = 1;
set_format();
- assert(loaded < buffer_size);
+ l = 0;
+ while (loaded > buffer_size) {
+ if (pcm_write(audiobuf + l, buffer_size) <= 0)
+ return;
+ l += buffer_size;
+ loaded -= l;
+ }
- while (count) {
- l = loaded;
- loaded = 0;
+ l = loaded;
+ while (count > 0) {
do {
c = count;
-
if (c + l > buffer_size)
c = buffer_size - l;
-
- if ((r = read(fd, audiobuf + l, c)) <= 0)
+
+ if (c == 0)
+ break;
+ r = read(fd, audiobuf + l, c);
+ if (r <= 0)
break;
l += r;
- } while (mode != SND_PCM_MODE_STREAM || l < buffer_size);
- if (l > 0) {
-#if 0
- sleep(1);
-#endif
- if (mmap_flag) {
- if (l != buffer_size)
- memset(audiobuf + l, silence, buffer_size - l);
- while (mmap_control->fragments[frag].data) {
- switch (mmap_control->status.status) {
- case SND_PCM_STATUS_PREPARED:
- if (fcn_go(pcm_handle, SND_PCM_CHANNEL_PLAYBACK)<0) {
- fprintf(stderr, "%s: unable to start playback\n", command);
- exit(1);
- }
- break;
- case SND_PCM_STATUS_RUNNING:
- break;
- case SND_PCM_STATUS_UNDERRUN:
- playback_write_error();
- break;
- default:
- fprintf(stderr, "%s: bad status (mmap) = %i\n", command, mmap_control->status.status);
- }
- usleep(10000);
- }
- /* FIXME: it's better to use snd_pcm_voice_setup data */
- memcpy(mmap_data + buffer_size * frag, audiobuf, buffer_size);
- mmap_control->fragments[frag].data = 1;
- frag++; frag %= frags;
- } else if (mode == SND_PCM_MODE_BLOCK) {
- if (l != buffer_size)
- memset(audiobuf + l, silence, buffer_size - l);
- while (fcn_write(pcm_handle, audiobuf, buffer_size) != buffer_size)
- playback_write_error();
- count -= l;
- } else {
- char *buf = audiobuf;
- while (l > 0) {
- while ((r = fcn_write(pcm_handle, buf, l)) < 0) {
- if (r == -EAGAIN) {
- r = 0;
- break;
- }
- playback_write_error();
- }
-#if 0
- {
- static int x = 1024*1024;
- if (r > 0 && r < x) {
- x = r;
- printf("smallest - %i\n", x);
- }
- }
-#endif
- l -= r;
- count -= r;
- buf += r;
- if (r < 32)
- usleep(10000);
- }
- }
- } else {
- if (l == -1)
- perror(name);
- count = 0; /* Stop */
- }
- } /* while (count) */
- fcn_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
+ } while (mode != SND_PCM_MODE_STREAM && l < buffer_size);
+ l = pcm_write(audiobuf, l);
+ if (l <= 0)
+ break;
+ count -= l;
+ l = 0;
+ }
+ snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
}
/* 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)
{
- int l;
- u_long c;
+ size_t c;
+ ssize_t r;
header(rtype, name);
format_change = 1;
set_format();
- while (count) {
+ while (count > 0) {
c = count;
- if (mmap_flag) {
- while (!mmap_control->fragments[frag].data) {
- switch (mmap_control->status.status) {
- case SND_PCM_STATUS_PREPARED:
- if (fcn_go(pcm_handle, SND_PCM_CHANNEL_CAPTURE)<0) {
- fprintf(stderr, "%s: unable to start capture\n", command);
- exit(1);
- }
- break;
- case SND_PCM_STATUS_RUNNING:
- break;
- case SND_PCM_STATUS_OVERRUN:
- capture_read_error();
- break;
- default:
- fprintf(stderr, "%s: bad status (mmap) = %i\n", command, mmap_control->status.status);
- }
- usleep(10000);
- }
- if (c > buffer_size)
- c = buffer_size;
- /* FIXME: it's better to use snd_pcm_voice_setup data */
- if (write(fd, mmap_data + buffer_size * frag, c) != c) {
- perror(name);
- exit(-1);
- }
- mmap_control->fragments[frag].data = 0;
- frag++; frag %= frags;
- count -= c;
- } else {
- if ((l = fcn_read(pcm_handle, audiobuf, buffer_size)) > 0) {
-#if 0
- {
- static int x = 1024*1024;
- if (l < x) {
- x = l;
- printf("smallest - %i\n", x);
- }
- }
-#endif
- if (c > l)
- c = l;
- if (write(fd, audiobuf, c) != c) {
- perror(name);
- exit(-1);
- }
- count -= c;
- }
- if (l == -EPIPE) {
- capture_read_error();
- l = 0;
- }
- if (l < 0) {
- fprintf(stderr, "read error: %s\n", snd_strerror(l));
- exit(-1);
- }
- if (l == 0)
- usleep(10000);
+ if (c > buffer_size)
+ c = buffer_size;
+ if ((r = pcm_read(audiobuf, c)) <= 0)
+ break;
+ if (write(fd, audiobuf, r) != r) {
+ perror(name);
+ exit(EXIT_FAILURE);
}
+ count -= r;
}
}
{
int fd, ofs;
- fcn_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
+ snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
if (!name || !strcmp(name, "-")) {
fd = 0;
name = "stdin";
} else {
if ((fd = open(name, O_RDONLY, 0)) == -1) {
perror(name);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
/* read the file header */
if (read(fd, audiobuf, sizeof(AuHeader)) != sizeof(AuHeader)) {
fprintf(stderr, "%s: read error", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (test_au(fd, audiobuf) >= 0) {
rformat.format = SND_PCM_SFMT_MU_LAW;
sizeof(VocHeader) - sizeof(AuHeader)) !=
sizeof(VocHeader) - sizeof(AuHeader)) {
fprintf(stderr, "%s: read error", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
if ((ofs = test_vocfile(audiobuf)) >= 0) {
voc_play(fd, ofs, name);
sizeof(WaveHeader) - sizeof(VocHeader)) !=
sizeof(WaveHeader) - sizeof(VocHeader)) {
fprintf(stderr, "%s: read error", command);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (test_wavefile(audiobuf) >= 0) {
playback_go(fd, 0, count, FORMAT_WAVE, name);
remove(name);
if ((fd = open(name, O_WRONLY | O_CREAT, 0644)) == -1) {
perror(name);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
count = calc_count() & 0xFFFFFFFE;