char *command;
snd_pcm_t *pcm_handle;
-struct snd_pcm_playback_info pinfo;
-struct snd_pcm_capture_info rinfo;
+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 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_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);
+
/* needed prototypes */
static void playback(char *filename);
{
static char *formats[] =
{
- "Mu-Law",
- "A-Law",
- "Ima-ADPCM",
+ "Signed 8-bit",
"Unsigned 8-bit",
"Signed 16-bit Little Endian",
"Signed 16-bit Big Endian",
- "Signed 8-bit",
"Unsigned 16-bit Little Endian",
"Unsigned 16-bit Big Endian",
+ "Signed 24-bit Little Endian",
+ "Signed 24-bit Big Endian",
+ "Unsigned 24-bit Little Endian",
+ "Unsigned 24-bit Big Endian",
+ "Signed 32-bit Little Endian",
+ "Signed 32-bit Big Endian",
+ "Unsigned 32-bit Little Endian",
+ "Unsigned 32-bit Big Endian",
+ "Float",
+ "Float64",
+ "IEC-958 Little Endian",
+ "IEC-958 Big Endian",
+ "Mu-Law",
+ "A-Law",
+ "Ima-ADPCM",
"MPEG",
"GSM"
};
static void check_new_format(snd_pcm_format_t * format)
{
- if (direction == SND_PCM_OPEN_PLAYBACK) {
- if (pinfo.min_rate > format->rate || pinfo.max_rate < format->rate) {
- fprintf(stderr, "%s: unsupported rate %iHz for playback (valid range is %iHz-%iHz)\n", command, format->rate, pinfo.min_rate, pinfo.max_rate);
- exit(1);
- }
- if (!(pinfo.formats & (1 << format->format))) {
- fprintf(stderr, "%s: requested format %s isn't supported with hardware\n", command, get_format(format->format));
- exit(1);
- }
- } else {
- if (rinfo.min_rate > format->rate || rinfo.max_rate < format->rate) {
- fprintf(stderr, "%s: unsupported rate %iHz for capture (valid range is %iHz-%iHz)\n", command, format->rate, rinfo.min_rate, rinfo.max_rate);
- exit(1);
- }
- if (!(rinfo.formats & (1 << format->format))) {
- fprintf(stderr, "%s: requested format %s isn't supported with hardware\n", command, get_format(rformat.format));
- exit(1);
- }
+ 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.formats & (1 << format->format))) {
+ fprintf(stderr, "%s: requested format %s isn't supported with hardware\n", command, get_format(format->format));
+ exit(1);
}
}
" -m set CD-ROM quality (44100Hz,stereo,16-bit linear)\n"
" -M set DAT quality (48000Hz,stereo,16-bit linear)\n"
" -p <type> compression type (alaw, ulaw, adpcm)\n"
+ " -e stream mode\n"
+ " -E mmap mode\n"
,command, snd_cards()-1);
}
unsigned int mask;
struct snd_ctl_hw_info info;
snd_pcm_info_t pcminfo;
- snd_pcm_playback_info_t playinfo;
- snd_pcm_capture_info_t recinfo;
+ snd_pcm_channel_info_t chninfo;
mask = snd_cards_mask();
if (!mask) {
printf(" Playback subdevices: %i\n", pcminfo.playback + 1);
printf(" Capture subdevices: %i\n", pcminfo.capture + 1);
if (pcminfo.flags & SND_PCM_INFO_PLAYBACK) {
- if ((err = snd_ctl_pcm_playback_info(handle, dev, 0, &playinfo)) < 0) {
- printf("Error: control digital audio playback info (%i): %s\n", card, snd_strerror(err));
- } else {
- printf(" Playback:\n");
- printf(" Rate range: %iHz-%iHz\n", playinfo.min_rate, playinfo.max_rate);
- printf(" Voices range: %i-%i\n", playinfo.min_channels, playinfo.max_channels);
- printf(" Formats:\n");
- for (idx = 0; idx < SND_PCM_SFMT_GSM; idx++) {
- if (playinfo.formats & (1 << idx))
- printf(" %s%s\n", get_format(idx),
- playinfo.hw_formats & (1 << idx) ? " [hardware]" : "");
+ 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, idx, &chninfo)) < 0) {
+ printf("Error: control digital audio playback info (%i): %s\n", card, snd_strerror(err));
+ } else {
+ printf(" Playback subdevice #%i: %s\n", idx, chninfo.subname);
}
}
}
if (pcminfo.flags & SND_PCM_INFO_CAPTURE) {
- if ((err = snd_ctl_pcm_capture_info(handle, dev, 0, &recinfo)) < 0) {
- printf("Error: control digital audio capture info (%i): %s\n", card, snd_strerror(err));
- } else {
- printf(" Record:\n");
- printf(" Rate range: %iHz-%iHz\n", recinfo.min_rate, recinfo.max_rate);
- printf(" Voices range: %i-%i\n", recinfo.min_channels, recinfo.max_channels);
- printf(" Formats:\n");
- for (idx = 0; idx < SND_PCM_SFMT_GSM; idx++) {
- if (recinfo.formats & (1 << idx))
- printf(" %s%s\n", get_format(idx),
- recinfo.hw_formats & (1 << idx) ? " [hardware]" : "");
+ for (idx = 0; idx <= pcminfo.capture; idx++) {
+ memset(&chninfo, 0, sizeof(chninfo));
+ chninfo.channel = SND_PCM_CHANNEL_CAPTURE;
+ if ((err = snd_ctl_pcm_channel_info(handle, dev, 0, &chninfo)) < 0) {
+ printf("Error: control digital audio capture info (%i): %s\n", card, snd_strerror(err));
+ } else {
+ printf(" Capture subdevice #%i: %s\n", idx, chninfo.subname);
}
}
}
static void version(void)
{
- printf("%s: version " SND_UTIL_VERSION_STR " by Jaroslav Kysela <perex@suse.cz>\n", command);
+ fprintf(stderr, "%s: version " SND_UTIL_VERSION_STR " by Jaroslav Kysela <perex@suse.cz>\n", command);
}
int main(int argc, char *argv[])
active_format = FORMAT_DEFAULT;
if (strstr(argv[0], "arecord")) {
direction = SND_PCM_OPEN_CAPTURE;
+ channel = SND_PCM_CHANNEL_CAPTURE;
active_format = FORMAT_WAVE;
command = "Arecord";
} else if (strstr(argv[0], "aplay")) {
direction = SND_PCM_OPEN_PLAYBACK;
+ channel = SND_PCM_CHANNEL_PLAYBACK;
command = "Aplay";
} else {
fprintf(stderr, "Error: command should be named either arecord or aplay\n");
buffer_size = -1;
memset(&rformat, 0, sizeof(rformat));
+ rformat.interleave = 1;
rformat.format = SND_PCM_SFMT_U8;
rformat.rate = DEFAULT_SPEED;
- rformat.channels = 1;
+ rformat.voices = 1;
if (argc > 1 && !strcmp(argv[1], "--help")) {
usage(command);
version();
return 0;
}
- while ((c = getopt(argc, argv, "hlc:d:qs:So:t:b:vrwuxB:c:p:mMV")) != EOF)
+ while ((c = getopt(argc, argv, "hlc:d:qs:So:t:b:vrwuxB:c:p:mMVeE")) != EOF)
switch (c) {
case 'h':
usage(command);
}
break;
case 'S':
- rformat.channels = 2;
+ rformat.voices = 2;
break;
case 'o':
tmp = atoi(optarg);
if (tmp < 1 || tmp > 32) {
- fprintf(stderr, "Error: value %i for channels is invalid\n", tmp);
+ fprintf(stderr, "Error: value %i for voices is invalid\n", tmp);
return 1;
}
break;
case 'M':
rformat.format = SND_PCM_SFMT_S16_LE;
rformat.rate = c == 'M' ? 48000 : 44100;
- rformat.channels = 2;
+ rformat.voices = 2;
break;
case 'V':
version();
return 0;
+ case 'e':
+ if (!mmap_flag) {
+ mode = SND_PCM_MODE_STREAM;
+ if (direction == SND_PCM_OPEN_CAPTURE)
+ direction = SND_PCM_OPEN_STREAM_CAPTURE;
+ if (direction == SND_PCM_OPEN_PLAYBACK)
+ direction = SND_PCM_OPEN_STREAM_PLAYBACK;
+ }
+ break;
+ case 'E':
+ if (mode == SND_PCM_MODE_BLOCK)
+ mmap_flag = 1;
+ break;
default:
usage(command);
return 1;
if (!quiet_mode)
version();
+ fcn_info = snd_pcm_plugin_info;
+ fcn_params = snd_pcm_plugin_params;
+ fcn_setup = snd_pcm_plugin_setup;
+ fcn_status = snd_pcm_plugin_status;
+ fcn_flush = snd_pcm_plugin_flush;
+ fcn_write = snd_pcm_plugin_write;
+ fcn_read = snd_pcm_plugin_read;
+ if (mmap_flag) {
+ fcn_info = snd_pcm_channel_info;
+ fcn_params = snd_pcm_channel_params;
+ fcn_setup = snd_pcm_channel_setup;
+ fcn_status = snd_pcm_channel_status;
+ fcn_flush = snd_pcm_flush_channel;
+ fcn_write = snd_pcm_write;
+ fcn_read = snd_pcm_read;
+ }
+
if ((err = snd_pcm_open(&pcm_handle, card, dev, direction)) < 0) {
fprintf(stderr, "Error: audio open error: %s\n", snd_strerror(err));
return 1;
}
- if (direction == SND_PCM_OPEN_PLAYBACK) {
- if ((err = snd_pcm_playback_info(pcm_handle, &pinfo)) < 0) {
- fprintf(stderr, "Error: playback info error: %s\n", snd_strerror(err));
- return 1;
- }
- tmp = pinfo.buffer_size;
- tmp /= 4; /* 4 fragments are best */
- } else {
- if ((err = snd_pcm_capture_info(pcm_handle, &rinfo)) < 0) {
- fprintf(stderr, "Error: capture info error: %s\n", snd_strerror(err));
- return 1;
- }
- tmp = rinfo.buffer_size;
- tmp /= 8; /* 8 fragments are best */
- }
-
- buffer_size = tmp;
- if (buffer_size < 512 || buffer_size > 16L * 1024L * 1024L) {
- fprintf(stderr, "Error: Invalid audio buffer size %d\n", buffer_size);
+ memset(&cinfo, 0, sizeof(cinfo));
+ cinfo.channel = channel;
+ if ((err = fcn_info(pcm_handle, &cinfo)) < 0) {
+ fprintf(stderr, "Error: channel info error: %s\n", snd_strerror(err));
return 1;
}
- check_new_format(&rformat);
+
+ buffer_size = 1024;
format = rformat;
- if ((audiobuf = malloc(buffer_size)) == NULL) {
- fprintf(stderr, "%s: unable to allocate input/output buffer\n", command);
+ audiobuf = (char *)malloc(1024);
+ if (audiobuf == NULL) {
+ fprintf(stderr, "Error: not enough memory\n");
return 1;
}
+
if (optind > argc - 1) {
- if (direction == SND_PCM_OPEN_PLAYBACK)
+ if (channel == SND_PCM_CHANNEL_PLAYBACK)
playback(NULL);
else
capture(NULL);
} else {
while (optind <= argc - 1) {
- if (direction == SND_PCM_OPEN_PLAYBACK)
+ if (channel == SND_PCM_CHANNEL_PLAYBACK)
playback(argv[optind++]);
else
capture(argv[optind++]);
command, wp->modus);
exit(1);
}
- format.channels = wp->modus;
+ format.voices = wp->modus;
switch (wp->bit_p_spl) {
case 8:
format.format = SND_PCM_SFMT_U8;
format.rate = ntohl(ap->sample_rate);
if (format.rate < 2000 || format.rate > 256000)
return -1;
- format.channels = ntohl(ap->channels);
- if (format.channels < 1 || format.channels > 128)
+ format.voices = ntohl(ap->channels);
+ if (format.voices < 1 || format.voices > 128)
return -1;
if (read(fd, buffer + sizeof(AuHeader), ntohl(ap->hdr_size) - sizeof(AuHeader)) < 0) {
fprintf(stderr, "%s: read error\n", command);
l = x;
if (l > buffer_size)
l = buffer_size;
- if (snd_pcm_write(pcm_handle, buf, l) != l) {
+ if (fcn_write(pcm_handle, buf, l) != l) {
fprintf(stderr, "%s: write error\n", command);
exit(1);
}
{
unsigned int bps; /* bytes per second */
unsigned int size; /* fragment size */
- struct snd_pcm_playback_params pparams;
- struct snd_pcm_capture_params rparams;
+ struct snd_pcm_channel_params params;
+ struct snd_pcm_channel_setup setup;
- bps = format.rate * format.channels;
+ 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 = buffer_size;
- while (size > bps)
- size >>= 1;
- if (size < 16)
- size = 16;
-
- if (direction == SND_PCM_OPEN_PLAYBACK) {
- if (snd_pcm_playback_format(pcm_handle, &format) < 0) {
- fprintf(stderr, "%s: unable to set playback format %s, %iHz, %i voices\n", command, get_format(format.format), format.rate, format.channels);
- exit(1);
- }
- memset(&pparams, 0, sizeof(pparams));
- pparams.fragment_size = size;
- pparams.fragments_max = -1; /* little trick */
- pparams.fragments_room = 1;
- if (snd_pcm_playback_params(pcm_handle, &pparams) < 0) {
- fprintf(stderr, "%s: unable to set playback params\n", command);
- exit(1);
- }
+ size = 1;
+ while ((size << 1) < bps)
+ size <<= 1;
+
+ if (mmap_flag)
+ snd_pcm_munmap(pcm_handle, channel);
+ fcn_flush(pcm_handle, channel); /* to be in right state */
+ memset(¶ms, 0, sizeof(params));
+ params.mode = mode;
+ params.channel = channel;
+ memcpy(¶ms.format, &format, sizeof(format));
+ if (channel == SND_PCM_CHANNEL_PLAYBACK) {
+ params.start_mode = SND_PCM_START_FULL;
} else {
- if (snd_pcm_capture_format(pcm_handle, &format) < 0) {
- fprintf(stderr, "%s: unable to set capture format %s, %iHz, %i voices\n", command, get_format(format.format), format.rate, format.channels);
- exit(1);
- }
- memset(&rparams, 0, sizeof(rparams));
- rparams.fragment_size = size;
- rparams.fragments_min = 1;
- if (snd_pcm_capture_params(pcm_handle, &rparams) < 0) {
- fprintf(stderr, "%s: unable to set capture params\n", command);
+ params.start_mode = SND_PCM_START_DATA;
+ }
+ params.stop_mode = SND_PCM_STOP_STOP;
+ 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;
+ } 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;
+ }
+ if (fcn_params(pcm_handle, ¶ms) < 0) {
+ fprintf(stderr, "%s: unable to set channel params\n", command);
+ exit(1);
+ }
+ if (mmap_flag) {
+ if (snd_pcm_mmap(pcm_handle, channel, &mmap_control, (void **)&mmap_data)<0) {
+ fprintf(stderr, "%s: unable to mmap memory\n", command);
exit(1);
}
}
+ if (snd_pcm_channel_prepare(pcm_handle, channel) < 0) {
+ fprintf(stderr, "%s: unable to prepare channel\n", command);
+ exit(1);
+ }
+ memset(&setup, 0, sizeof(setup));
+ setup.mode = mode;
+ setup.channel = channel;
+ if (fcn_setup(pcm_handle, &setup) < 0) {
+ fprintf(stderr, "%s: unable to obtain setup\n", command);
+ exit(1);
+ }
+ 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 (audiobuf == NULL) {
+ fprintf(stderr, "%s: not enough memory\n", command);
+ exit(1);
+ }
+ // printf("real buffer_size = %i, frags = %i, total = %i\n", buffer_size, setup.buf.block.frags, setup.buf.block.frags * buffer_size);
+ format_change = 0;
}
/*
exit(1);
}
format.format = SND_PCM_SFMT_U8;
- format.channels = 1;
+ format.voices = 1;
format.rate = DEFAULT_SPEED;
+ format_change = 1;
set_format();
in_buffer = nextblock = 0;
fprintf(stderr, "%s: can't play packed .voc files\n", command);
return;
}
- if (format.channels == 2) { /* if we are in Stereo-Mode, switch back */
- format.channels = 1;
- set_format();
- }
+ if (format.voices == 2) /* if we are in Stereo-Mode, switch back */
+ format.voices = 1;
} else { /* there was extended block */
- format.channels = 2;
+ format.voices = 2;
was_extended = 0;
}
+ format_change = 1;
set_format();
break;
case 2: /* nothing to do, pure data */
format.rate = (int) (*data);
COUNT1(1);
format.rate = 1000000 / (256 - format.rate);
+ format_change = 1;
set_format();
silence = (((u_long) * sp) * 1000) / format.rate;
#if 0
COUNT1(sizeof(VocExtBlock));
format.rate = (int) (eb->tc);
format.rate = 256000000L / (65536 - format.rate);
- format.channels = eb->mode == VOC_MODE_STEREO ? 2 : 1;
- if (format.channels == 2)
+ format.voices = eb->mode == VOC_MODE_STEREO ? 2 : 1;
+ if (format.voices == 2)
format.rate = format.rate >> 1;
if (eb->pack) { /* /dev/dsp can't it */
fprintf(stderr, "%s: can't play packed .voc files\n", command);
exit(1);
}
} else {
- if (snd_pcm_write(pcm_handle, data, l) != l) {
+ if (fcn_write(pcm_handle, data, l) != l) {
fprintf(stderr, "%s: write error\n", command);
exit(1);
}
if (!timelimit)
count = 0x7fffffff;
else {
- count = timelimit * format.rate * format.channels;
+ count = timelimit * format.rate * format.voices;
switch (format.format) {
case SND_PCM_SFMT_S16_LE:
case SND_PCM_SFMT_S16_BE:
fprintf(stderr, "%s: write error\n", command);
exit(1);
}
- if (format.channels > 1) {
+ if (format.voices > 1) {
/* write a extended block */
bt.type = 8;
bt.datalen = 4;
wh.sub_chunk = WAV_FMT;
wh.sc_len = 16;
wh.format = WAV_PCM_CODE;
- wh.modus = format.channels;
+ wh.modus = format.voices;
wh.sample_fq = format.rate;
#if 0
wh.byte_p_spl = (samplesize == 8) ? 1 : 2;
case SND_PCM_SFMT_U8:
ah.encoding = htonl(AU_FMT_LIN8);
break;
- case SND_PCM_SFMT_U16_LE:
+ case SND_PCM_SFMT_S16_LE:
ah.encoding = htonl(AU_FMT_LIN16);
break;
default:
exit(1);
}
ah.sample_rate = htonl(format.rate);
- ah.channels = htonl(format.channels);
+ ah.channels = htonl(format.voices);
if (write(fd, &ah, sizeof(AuHeader)) != sizeof(AuHeader)) {
fprintf(stderr, "%s: write error\n", command);
exit(1);
{
if (!quiet_mode) {
fprintf(stderr, "%s %s '%s' : ",
- (direction == SND_PCM_OPEN_PLAYBACK) ? "Playing" : "Recording",
+ (channel == SND_PCM_CHANNEL_PLAYBACK) ? "Playing" : "Recording",
fmt_rec_table[rtype].what,
name);
fprintf(stderr, "%s, ", get_format(format.format));
fprintf(stderr, "Rate %d Hz, ", format.rate);
- if (format.channels == 1)
+ if (format.voices == 1)
fprintf(stderr, "Mono");
- else if (format.channels == 2)
+ else if (format.voices == 2)
fprintf(stderr, "Stereo");
else
- fprintf(stderr, "Voices %i", format.channels);
+ fprintf(stderr, "Voices %i", format.voices);
fprintf(stderr, "\n");
}
}
+/* 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 (snd_pcm_channel_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_OVERRUN) {
+ printf("overrun at position %u!!!\n", status.scount);
+ if (snd_pcm_channel_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)
{
- int l;
+ int l, r;
u_long c;
header(rtype, name);
+ format_change = 1;
set_format();
while (count) {
- c = count;
-
- if (c > buffer_size)
- c = buffer_size;
-
- if ((l = read(fd, audiobuf + loaded, c - loaded)) > 0) {
- l += loaded;
- loaded = 0; /* correct the count; ugly but ... */
+ l = loaded;
+ loaded = 0;
+ do {
+ c = count;
+
+ if (c + l > buffer_size)
+ c = buffer_size - l;
+
+ if ((r = read(fd, audiobuf + l, c)) <= 0)
+ break;
+ l += r;
+ } while (mode != SND_PCM_MODE_STREAM || l < buffer_size);
+ if (l > 0) {
#if 0
sleep(1);
#endif
- if (snd_pcm_write(pcm_handle, audiobuf, l) != l) {
- fprintf(stderr, "write error\n");
- exit(1);
+ 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 (snd_pcm_channel_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);
+ }
+ memcpy(mmap_data + mmap_control->fragments[frag].addr, 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) {
+ 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);
+ }
}
- count -= l;
} else {
- if (l == -1) {
+ if (l == -1)
perror(name);
- exit(-1);
- }
count = 0; /* Stop */
}
} /* while (count) */
+ fcn_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
}
/* captureing raw data, this proc handels WAVE files and .VOCs (as one block) */
u_long c;
header(rtype, name);
+ format_change = 1;
set_format();
while (count) {
c = count;
- if (c > buffer_size)
- c = buffer_size;
-
- if ((l = snd_pcm_read(pcm_handle, audiobuf, c)) > 0) {
- if (write(fd, audiobuf, l) != l) {
+ if (mmap_flag) {
+ while (!mmap_control->fragments[frag].data) {
+ switch (mmap_control->status.status) {
+ case SND_PCM_STATUS_PREPARED:
+ if (snd_pcm_channel_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;
+ if (write(fd, mmap_data + mmap_control->fragments[frag].addr, c) != c) {
perror(name);
exit(-1);
}
- count -= l;
- }
- if (l == -1) {
- fprintf(stderr, "read error\n");
- 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 < -1) {
+ fprintf(stderr, "write error\n");
+ exit(-1);
+ }
+ if (l == 0)
+ usleep(10000);
}
}
}
{
int fd, ofs;
- snd_pcm_flush_playback(pcm_handle);
+ fcn_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
if (!name || !strcmp(name, "-")) {
fd = 0;
name = "stdin";
exit(1);
}
if (test_au(fd, audiobuf) >= 0) {
+ rformat.format = SND_PCM_SFMT_MU_LAW;
playback_go(fd, 0, count, FORMAT_AU, name);
goto __end;
}
if (read(fd, audiobuf + sizeof(AuHeader),
sizeof(VocHeader) - sizeof(AuHeader)) !=
- sizeof(VocHeader) - sizeof(AuHeader)) {
+ sizeof(VocHeader) - sizeof(AuHeader)) {
fprintf(stderr, "%s: read error", command);
exit(1);
}
playback_go(fd, 0, count, FORMAT_WAVE, name);
} else {
/* should be raw data */
+ check_new_format(&rformat);
init_raw_data();
count = calc_count();
playback_go(fd, sizeof(WaveHeader), count, FORMAT_RAW, name);
isn't a problem (this can only be in 8 bit mono) */
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);
fmt_rec_table[active_format].end(fd);
}