]> git.alsa-project.org Git - alsa-utils.git/commitdiff
Merged pcm2 branch.
authorJaroslav Kysela <perex@perex.cz>
Mon, 8 May 2000 18:54:14 +0000 (18:54 +0000)
committerJaroslav Kysela <perex@perex.cz>
Mon, 8 May 2000 18:54:14 +0000 (18:54 +0000)
alsamixer/alsamixer.c
amixer/amixer.c
aplay/aplay.c
configure.in

index c7fe834a9d320d855785c0f6e103ca960d6d206a..676019be2cea85e29bcb99b0730c6792d850312d 100644 (file)
@@ -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);
index e1d7d88ff28f56b34774486cd7889e7d5c9fe381..33d23e96c3869d9ab85f856f779575af67b6dec7 100644 (file)
@@ -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:
index 06a4a3c13c37605876d5c7300ee84a342614e004..149b6aa620cfbd12da9885a1b178a3a47e1e872d 100644 (file)
@@ -38,6 +38,7 @@
 #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 */
 
@@ -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;
+
+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"
@@ -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>   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");
 }
 
@@ -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(&params, 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, &params) < 0) {
+       if (snd_pcm_channel_params(pcm_handle, &params) < 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;
index 554d45588faf08518ac023563f908e0cc4bbe470..3c6e299153df2e3ab2568767e4c355514021a69d 100644 (file)
@@ -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