OSDN Git Service

Changes to show the different transfer methods
authorJaroslav Kysela <perex@perex.cz>
Wed, 17 Oct 2001 17:50:16 +0000 (17:50 +0000)
committerJaroslav Kysela <perex@perex.cz>
Wed, 17 Oct 2001 17:50:16 +0000 (17:50 +0000)
test/pcm.c

index 998a8b8..f2c6b4c 100644 (file)
@@ -22,7 +22,6 @@ double freq = 440;                             /* sinus wave frequency in Hz */
 
 snd_pcm_sframes_t buffer_size;
 snd_pcm_sframes_t period_size;
-signed short *samples;
 snd_output_t *output = NULL;
 
 static void generate_sine(signed short *samples, int count, double *_phase)
@@ -145,6 +144,155 @@ static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams)
        return 0;
 }
 
+/*
+ *   Underrun and suspend recovery
+ */
+static int xrun_recovery(snd_pcm_t *handle, int err)
+{
+       if (err = -EPIPE) {     /* underrun */
+               err = snd_pcm_prepare(handle);
+               if (err < 0)
+                       printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
+               return 0;
+       } else if (err = -ESTRPIPE) {
+               while ((err = snd_pcm_resume(handle)) == -EAGAIN)
+                       sleep(1);       /* wait until suspend flag is released */
+               if (err < 0) {
+                       err = snd_pcm_prepare(handle);
+                       if (err < 0)
+                               printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
+               }
+               return 0;
+       }
+       return err;
+}
+
+/*
+ *   Transfer method - write only
+ */
+
+static int write_loop(snd_pcm_t *handle, signed short *samples)
+{
+       int ufds_count;
+       struct pollfd *ufds;
+       double phase = 0;
+       signed short *ptr;
+       int err, count, cptr;
+
+       while (1) {
+               generate_sine(ptr = samples, cptr = period_size, &phase);
+               while (cptr > 0) {
+                       err = snd_pcm_writei(handle, ptr, cptr);
+                       if (err == -EAGAIN)
+                               continue;
+                       if (err < 0) {
+                               if (xrun_recovery(handle, err) < 0) {
+                                       printf("Write error: %s\n", snd_strerror(err));
+                                       exit(EXIT_FAILURE);
+                               }
+                               break;  /* skip one period */
+                       }
+                       ptr += err * channels;
+                       cptr -= err;
+               }
+       }
+}
+/*
+ *   Transfer method - write and wait for room in buffer using poll
+ */
+
+static int wait_for_poll(struct pollfd *ufds, int count)
+{
+       int i;
+       unsigned int events;
+
+       while (1) {
+               poll(ufds, count, -1);
+               for (i = 0; i < count; i++) {
+                       events = ufds[i].revents;
+                       if (events & POLLERR) {
+                               printf("Poll - POLLERR detected\n");
+                               return -EIO;
+                       }
+                       if (events & POLLOUT)
+                               return 0;
+               }
+       }
+}
+
+static int write_and_poll_loop(snd_pcm_t *handle, signed short *samples)
+{
+       int ufds_count;
+       struct pollfd *ufds;
+       double phase = 0;
+       signed short *ptr;
+       int err, count, cptr;
+
+       count = snd_pcm_poll_descriptors_count (handle);
+       if (count <= 0) {
+               printf("Invalid poll descriptors count\n");
+               return count;
+       }
+
+       ufds = malloc(sizeof(struct pollfd) * count);
+       if (ufds == NULL) {
+               printf("No enough memory\n");
+               return err;;
+       }
+       if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) {
+               printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err));
+               return err;
+       }
+
+       while (1) {
+               err = wait_for_poll(ufds, count);
+               if (err < 0) {
+                       printf("Wait for poll failed\n");
+                       return err;
+               }
+
+               generate_sine(ptr = samples, cptr = period_size, &phase);
+               while (cptr > 0) {
+                       err = snd_pcm_writei(handle, ptr, cptr);
+                       if (err < 0) {
+                               if (xrun_recovery(handle, err) < 0) {
+                                       printf("Write error: %s\n", snd_strerror(err));
+                                       exit(EXIT_FAILURE);
+                               }
+                               break;  /* skip one period */
+                       }
+                       ptr += err * channels;
+                       cptr -= err;
+                       if (cptr == 0)
+                               break;
+                       /* it is possible, that initial buffer cannot store */
+                       /* all data from last period, so wait awhile */
+                       err = wait_for_poll(ufds, count);
+                       if (err < 0) {
+                               printf("Wait for poll failed\n");
+                               return err;
+                       }
+               }
+       }
+}
+
+/*
+ *
+ */
+
+struct transfer_method {
+       const char *name;
+       int (*transfer_loop)(snd_pcm_t *handle, signed short *samples);
+};
+
+static struct transfer_method transfer_methods[] = {
+       { "write", write_loop },
+       { "write_and_poll", write_and_poll_loop },
+       { NULL, NULL }
+};
+
 static void help(void)
 {
        int k;
@@ -157,6 +305,8 @@ Usage: latency [OPTION]... [FILE]...
 -f,--frequency  sine wave frequency in Hz
 -b,--buffer     ring buffer size in samples
 -p,--period     period size in us
+-m,--method     tranfer method
+
 ");
         printf("Recognized sample formats are:");
         for (k = 0; k < SND_PCM_FORMAT_LAST; ++(unsigned long) k) {
@@ -165,6 +315,10 @@ Usage: latency [OPTION]... [FILE]...
                         printf(" %s", s);
         }
         printf("\n");
+        printf("Recognized tranfer methods are:");
+        for (k = 0; transfer_methods[k].name; k++)
+               printf(" %s", transfer_methods[k].name);
+       printf("\n");
 }
 
 int main(int argc, char *argv[])
@@ -178,18 +332,17 @@ int main(int argc, char *argv[])
                {"frequency", 1, NULL, 'f'},
                {"buffer", 1, NULL, 'b'},
                {"period", 1, NULL, 'p'},
+               {"method", 1, NULL, 'm'},
                {NULL, 0, NULL, 0},
        };
        snd_pcm_t *handle;
        char *buffer;
-       int err, morehelp, i, count;
+       int err, morehelp;
        snd_pcm_hw_params_t *hwparams;
        snd_pcm_sw_params_t *swparams;
-       struct pollfd *ufds;
-       unsigned int events;
        double phase;
-       signed short *ptr;
-       int cptr;
+       int method = 0;
+       signed short *samples;
 
        snd_pcm_hw_params_alloca(&hwparams);
        snd_pcm_sw_params_alloca(&swparams);
@@ -197,7 +350,7 @@ int main(int argc, char *argv[])
        morehelp = 0;
        while (1) {
                int c;
-               if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:", long_option, NULL)) < 0)
+               if ((c = getopt_long(argc, argv, "hD:r:c:f:b:p:m:", long_option, NULL)) < 0)
                        break;
                switch (c) {
                case 'h':
@@ -231,6 +384,13 @@ int main(int argc, char *argv[])
                        period_time = period_time < 1000 ? 1000 : period_time;
                        period_time = period_time > 1000000 ? 1000000 : period_time;
                        break;
+               case 'm':
+                       for (method = 0; transfer_methods[method].name; method++)
+                               if (!strcasecmp(transfer_methods[method].name, optarg))
+                                       break;
+                       if (transfer_methods[method].name == NULL)
+                               method = 0;
+                       break;
                }
        }
 
@@ -248,6 +408,7 @@ int main(int argc, char *argv[])
        printf("Playback device is %s\n", device);
        printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
        printf("Sine wave rate is %.4fHz\n", freq);
+       printf("Using transfer method: %s\n", transfer_methods[method].name);
 
        if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
                printf("Playback open error: %s\n", snd_strerror(err));
@@ -263,59 +424,15 @@ int main(int argc, char *argv[])
                exit(EXIT_FAILURE);
        }
 
-       count = snd_pcm_poll_descriptors_count (handle);
-       if (count <= 0) {
-               printf("Invalid poll descriptors count\n");
-               exit(EXIT_FAILURE);
-       }
-       ufds = malloc(sizeof(struct pollfd) * count);
-       if (ufds == NULL) {
-               printf("No enough memory\n");
-               exit(EXIT_FAILURE);
-       }
-       if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) {
-               printf("Unable to obtain poll descriptors for playback: %s\n", snd_strerror(err));
-               exit(EXIT_FAILURE);
-       }
-       
        samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8);
        if (samples == NULL) {
                printf("No enough memory\n");
                exit(EXIT_FAILURE);
        }
 
-       phase = 0;
-
-       while (1) {
-               poll(ufds, count, -1);
-               for (i = 0; i < count; i++) {
-                       events = ufds[i].revents;
-                       if (events & POLLOUT)
-                               goto __write;
-               }
-               continue;
-
-             __write:
-               generate_sine(ptr = samples, cptr = period_size, &phase);
-               while (cptr > 0) {
-                       err = snd_pcm_writei(handle, ptr, cptr);
-                       if (err < 0) {
-                               printf("Write error: %s\n", snd_strerror(err));
-                               exit(EXIT_FAILURE);
-                       }
-                       ptr += err * channels;
-                       cptr -= err;
-                       while (1) {
-                               poll(ufds, count, -1);
-                               for (i = 0; i < count; i++) {
-                                       events = ufds[i].revents;
-                                       if (events & POLLOUT)
-                                               goto __write1;
-                               }
-                       }
-                     __write1:
-               }
-       }
+       err = transfer_methods[method].transfer_loop(handle, samples);
+       if (err < 0)
+               printf("Transfer failed: %s\n", snd_strerror(err));
 
        snd_pcm_close(handle);
        return 0;