diff --git a/alsamixer/alsamixer.c b/alsamixer/alsamixer.c index c7fe834..676019b 100644 --- a/alsamixer/alsamixer.c +++ b/alsamixer/alsamixer.c @@ -242,7 +242,7 @@ static char *mixer_help_text = " F1 show Help screen\n" " F2 show /proc info screen\n" " Return return to main screen\n" - " Space toggle Record facility\n" + " Space toggle Capture facility\n" " Tab toggle ExactMode\n" " m M mute both channels\n" " < > mute left/right channel\n" @@ -1575,10 +1575,12 @@ mixer_iteration (void) case KEY_NPAGE: mixer_set_delta(-5); break; +#if 0 case KEY_BEG: case KEY_HOME: mixer_set_delta(100); break; +#endif case KEY_LL: case KEY_END: mixer_set_delta(-100); diff --git a/amixer/amixer.c b/amixer/amixer.c index e1d7d88..33d23e9 100644 --- a/amixer/amixer.c +++ b/amixer/amixer.c @@ -340,8 +340,8 @@ static const char *speaker_position(int position) static char str[32]; switch (position) { - case SND_MIXER_VOICE_UNUSED: - return "Unused"; + case SND_MIXER_VOICE_UNKNOWN: + return "Unknown"; case SND_MIXER_VOICE_MONO: return "Mono"; case SND_MIXER_VOICE_LEFT: @@ -495,6 +495,7 @@ int show_element_info(void *handle, snd_mixer_eid_t *eid, const char *space) error("Mixer %i/%i info error: %s", card, device, snd_strerror(err)); return -1; } + printf("%sInput/output voices: %i/%i\n", space, info.input_voices, info.output_voices); switch (info.eid.type) { case SND_MIXER_ETYPE_INPUT: case SND_MIXER_ETYPE_OUTPUT: @@ -503,17 +504,10 @@ int show_element_info(void *handle, snd_mixer_eid_t *eid, const char *space) info.data.io.attrib & SND_MIXER_EIO_DIGITAL ? " digital" : ""); } for (idx = 0; idx < info.data.io.voices; idx++) { - if (!info.data.io.pvoices[idx].vindex) { - printf("%sVoice %i: %s\n", - space, - idx, - speaker_position(info.data.io.pvoices[idx].voice)); - } else { - printf("%sVoice %i: %i\n", - space, - idx, - info.data.io.pvoices[idx].voice); - } + printf("%sVoice %i: %s\n", + space, + idx, + speaker_position(info.data.io.pvoices[idx].position)); } break; case SND_MIXER_ETYPE_CAPTURE1: @@ -554,14 +548,6 @@ int show_element_info(void *handle, snd_mixer_eid_t *eid, const char *space) default: printf("unknown %i\n", info.data.switch3.type); } - for (idx = 0; idx < info.data.switch3.voices; idx++) { - snd_mixer_voice_t voice = info.data.switch3.pvoices[idx]; - if (voice.vindex) { - printf("%sVoice %i: %i\n", space, idx, voice.voice); - } else { - printf("%sSpeaker %i: %s\n", space, idx, speaker_position(voice.voice)); - } - } break; case SND_MIXER_ETYPE_VOLUME1: for (idx = 0; idx < info.data.volume1.range; idx++) { @@ -698,28 +684,17 @@ int show_element_contents(void *handle, snd_mixer_eid_t *eid, const char *space) printf("%sSwitch is %s\n", space, element.data.switch2.sw ? "ON" : "OFF"); break; case SND_MIXER_ETYPE_SWITCH3: - if (element.data.switch3.rsw != info.data.switch3.voices * info.data.switch3.voices) { + if (element.data.switch3.rsw != info.input_voices * info.output_voices) { error("Switch3 !!!\n"); goto __end; } for (idx = 0; idx < element.data.switch3.rsw; idx++) { - snd_mixer_voice_t input, output; int val = snd_mixer_get_bit(element.data.switch3.prsw, idx); - printf("%sInput <", space); - input = info.data.switch3.pvoices[idx / info.data.switch3.voices]; - output = info.data.switch3.pvoices[idx % info.data.switch3.voices]; - if (input.vindex) { - printf("voice %i", input.voice); - } else { - printf(speaker_position(input.voice)); - } - printf("> Output <"); - if (output.vindex) { - printf("voice %i", output.voice); - } else { - printf(speaker_position(output.voice)); - } - printf(">: Switch is %s\n", val ? "ON" : "OFF"); + printf("%sInput <%i> Output <%i>: Switch is %s\n", + space, + idx / info.input_voices, + idx % info.output_voices, + val ? "ON" : "OFF"); } break; case SND_MIXER_ETYPE_VOLUME1: diff --git a/aplay/aplay.c b/aplay/aplay.c index 06a4a3c..149b6aa 100644 --- a/aplay/aplay.c +++ b/aplay/aplay.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "aconfig.h" #include "formats.h" #include "version.h" @@ -52,45 +53,37 @@ /* 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; +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); -int count; -int vocmajor, vocminor; +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; -/* 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 int count; +static int vocmajor, vocminor; /* needed prototypes */ @@ -114,57 +107,97 @@ struct fmt_capture { { 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; -#define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) +static const char *assoc(int value, assoc_t *alist) +{ + while (alist->desc) { + if (value == alist->value) + return alist->desc; + alist++; + } + return "UNKNOWN"; +} + +#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] ...\n" "Available switches:\n" @@ -178,20 +211,22 @@ static void usage(char *command) " -v file format Voc\n" " -w file format Wave\n" " -r file format Raw\n" - " -S stereo\n" " -o voices (1-N)\n" " -s speed (Hz)\n" " -f data format\n" + " -F 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 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"); } @@ -200,52 +235,52 @@ static void device_list(void) 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); } } } @@ -254,9 +289,9 @@ static void device_list(void) 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); } } } @@ -307,7 +342,7 @@ int main(int argc, char *argv[]) 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); @@ -329,9 +364,6 @@ int main(int argc, char *argv[]) return 1; } break; - case 'S': - rformat.voices = 2; - break; case 'o': tmp = atoi(optarg); if (tmp < 1 || tmp > 32) { @@ -369,19 +401,21 @@ int main(int argc, char *argv[]) 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; @@ -392,16 +426,23 @@ int main(int argc, char *argv[]) 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; @@ -410,32 +451,6 @@ int main(int argc, char *argv[]) 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; @@ -446,13 +461,25 @@ int main(int argc, char *argv[]) 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; } @@ -466,6 +493,14 @@ int main(int argc, char *argv[]) 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); @@ -480,7 +515,7 @@ int main(int argc, char *argv[]) } } snd_pcm_close(pcm_handle); - return 0; + return EXIT_SUCCESS; } /* @@ -513,12 +548,12 @@ static int test_wavefile(void *buffer) 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) { @@ -574,82 +609,55 @@ static int test_au(int fd, void *buffer) 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; @@ -659,56 +667,260 @@ static void set_format(void) } 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; @@ -716,31 +928,38 @@ static void voc_play(int fd, int ofs, char *name) 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; @@ -751,25 +970,25 @@ static void voc_play(int fd, int ofs, char *name) 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); @@ -823,8 +1042,7 @@ static void voc_play(int fd, int ofs, char *name) #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; @@ -912,17 +1130,20 @@ static void voc_play(int fd, int ofs, char *name) 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 :-) */ @@ -937,31 +1158,12 @@ static u_long calc_count(void) { 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; } @@ -982,7 +1184,7 @@ static void begin_voc(int fd, u_long cnt) 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 */ @@ -991,14 +1193,14 @@ static void begin_voc(int fd, u_long cnt) 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; @@ -1008,13 +1210,13 @@ static void begin_voc(int fd, u_long cnt) 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); } } @@ -1034,7 +1236,7 @@ static void begin_wave(int fd, u_long cnt) 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; @@ -1056,7 +1258,7 @@ static void begin_wave(int fd, u_long cnt) wh.data_length = cnt; if (write(fd, &wh, sizeof(WaveHeader)) != sizeof(WaveHeader)) { fprintf(stderr, "%s: write error\n", command); - exit(1); + exit(EXIT_FAILURE); } } @@ -1080,13 +1282,13 @@ static void begin_au(int fd, u_long cnt) 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); } } @@ -1096,7 +1298,7 @@ static void end_voc(int fd) 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); @@ -1127,58 +1329,6 @@ static void header(int rtype, char *name) } } -/* 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) @@ -1190,163 +1340,59 @@ 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; } } @@ -1358,20 +1404,20 @@ static void playback(char *name) { 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; @@ -1382,7 +1428,7 @@ static void playback(char *name) 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); @@ -1393,7 +1439,7 @@ static void playback(char *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); @@ -1421,7 +1467,7 @@ static void capture(char *name) remove(name); if ((fd = open(name, O_WRONLY | O_CREAT, 0644)) == -1) { perror(name); - exit(1); + exit(EXIT_FAILURE); } } count = calc_count() & 0xFFFFFFFE; diff --git a/configure.in b/configure.in index 554d455..3c6e299 100644 --- a/configure.in +++ b/configure.in @@ -10,7 +10,7 @@ AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_YACC AM_PROG_LEX -AM_PATH_ALSA(0.5.5) +AM_PATH_ALSA(0.6.0) dnl Checks for header files. AC_HEADER_STDC