tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

speaker-test.c (35756B)


      1 /*
      2  * Copyright (C) 2000-2004 James Courtier-Dutton
      3  * Copyright (C) 2005 Nathan Hurst
      4  *
      5  * This file is part of the speaker-test tool.
      6  *
      7  * This small program sends a simple sinusoidal wave to your speakers.
      8  *
      9  * speaker-test is free software; you can redistribute it and/or modify
     10  * it under the terms of the GNU General Public License as published by
     11  * the Free Software Foundation; either version 2 of the License, or
     12  * (at your option) any later version.
     13  *
     14  * speaker-test is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  * GNU General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU General Public License
     20  * along with this program; if not, write to the Free Software
     21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
     22  *
     23  *
     24  * Main program by James Courtier-Dutton (including some source code fragments from the alsa project.)
     25  * Some cleanup from Daniel Caujolle-Bert <segfault@club-internet.fr>
     26  * Pink noise option added Nathan Hurst, 
     27  *   based on generator by Phil Burk (pink.c)
     28  *
     29  * Changelog:
     30  *   0.0.8 Added support for pink noise output.
     31  * Changelog:
     32  *   0.0.7 Added support for more than 6 channels.
     33  * Changelog:
     34  *   0.0.6 Added support for different sample formats.
     35  *
     36  * $Id: speaker_test.c,v 1.00 2003/11/26 19:43:38 jcdutton Exp $
     37  */
     38 
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <sched.h>
     43 #include <errno.h>
     44 #include <getopt.h>
     45 #include <inttypes.h>
     46 #include <ctype.h>
     47 #include <byteswap.h>
     48 #include <signal.h>
     49 
     50 #define ALSA_PCM_NEW_HW_PARAMS_API
     51 #define ALSA_PCM_NEW_SW_PARAMS_API
     52 #include <alsa/asoundlib.h>
     53 #include <sys/time.h>
     54 #include <math.h>
     55 #include "pink.h"
     56 #include "aconfig.h"
     57 #include "gettext.h"
     58 #include "version.h"
     59 
     60 #ifdef ENABLE_NLS
     61 #include <locale.h>
     62 #endif
     63 
     64 #ifdef SND_CHMAP_API_VERSION
     65 #define CONFIG_SUPPORT_CHMAP	1
     66 #endif
     67 
     68 enum {
     69   TEST_PINK_NOISE = 1,
     70   TEST_SINE,
     71   TEST_WAV,
     72   TEST_PATTERN,
     73 };
     74 
     75 #define MAX_CHANNELS	16
     76 
     77 #if __BYTE_ORDER == __LITTLE_ENDIAN
     78 #define COMPOSE_ID(a,b,c,d)	((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
     79 #define LE_SHORT(v)		(v)
     80 #define LE_INT(v)		(v)
     81 #define BE_SHORT(v)		bswap_16(v)
     82 #define BE_INT(v)		bswap_32(v)
     83 #else /* __BIG_ENDIAN */
     84 #define COMPOSE_ID(a,b,c,d)	((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
     85 #define LE_SHORT(v)		bswap_16(v)
     86 #define LE_INT(v)		bswap_32(v)
     87 #define BE_SHORT(v)		(v)
     88 #define BE_INT(v)		(v)
     89 #endif
     90 
     91 #define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0]))
     92 
     93 static char              *device      = "default";       /* playback device */
     94 static snd_pcm_format_t   format      = SND_PCM_FORMAT_S16; /* sample format */
     95 static unsigned int       rate        = 48000;	            /* stream rate */
     96 static unsigned int       channels    = 1;	            /* count of channels */
     97 static unsigned int       speaker     = 0;	            /* count of channels */
     98 static unsigned int       buffer_time = 0;	            /* ring buffer length in us */
     99 static unsigned int       period_time = 0;	            /* period time in us */
    100 static unsigned int       nperiods    = 4;                  /* number of periods */
    101 static double             freq        = 440.0;              /* sinusoidal wave frequency in Hz */
    102 static int                test_type   = TEST_PINK_NOISE;    /* Test type. 1 = noise, 2 = sine wave */
    103 static float              generator_scale  = 0.8;           /* Scale to use for sine volume */
    104 static pink_noise_t pink;
    105 static snd_pcm_uframes_t  buffer_size;
    106 static snd_pcm_uframes_t  period_size;
    107 static const char *given_test_wav_file = NULL;
    108 static char *wav_file_dir = SOUNDSDIR;
    109 static int debug = 0;
    110 static int force_frequency = 0;
    111 static int in_aborting = 0;
    112 static snd_pcm_t *pcm_handle = NULL;
    113 
    114 #ifdef CONFIG_SUPPORT_CHMAP
    115 static snd_pcm_chmap_t *channel_map;
    116 static int channel_map_set;
    117 static int *ordered_channels;
    118 #endif
    119 
    120 static const char *const channel_name[MAX_CHANNELS] = {
    121   /*  0 */ N_("Front Left"),
    122   /*  1 */ N_("Front Right"),
    123   /*  2 */ N_("Rear Left"),
    124   /*  3 */ N_("Rear Right"),
    125   /*  4 */ N_("Center"),
    126   /*  5 */ N_("LFE"),
    127   /*  6 */ N_("Side Left"),
    128   /*  7 */ N_("Side Right"),
    129   /*  8 */ N_("Channel 9"),
    130   /*  9 */ N_("Channel 10"),
    131   /* 10 */ N_("Channel 11"),
    132   /* 11 */ N_("Channel 12"),
    133   /* 12 */ N_("Channel 13"),
    134   /* 13 */ N_("Channel 14"),
    135   /* 14 */ N_("Channel 15"),
    136   /* 15 */ N_("Channel 16")
    137 };
    138 
    139 static const int	channels4[] = {
    140   0, /* Front Left  */
    141   1, /* Front Right */
    142   3, /* Rear Right  */
    143   2, /* Rear Left   */
    144 };
    145 static const int	channels6[] = {
    146   0, /* Front Left  */
    147   4, /* Center      */
    148   1, /* Front Right */
    149   3, /* Rear Right  */
    150   2, /* Rear Left   */
    151   5, /* LFE         */
    152 };
    153 static const int	channels8[] = {
    154   0, /* Front Left  */
    155   4, /* Center      */
    156   1, /* Front Right */
    157   7, /* Side Right  */
    158   3, /* Rear Right  */
    159   2, /* Rear Left   */
    160   6, /* Side Left   */
    161   5, /* LFE         */
    162 };
    163 
    164 #ifdef CONFIG_SUPPORT_CHMAP
    165 /* circular clockwise and bottom-to-top order */
    166 static const int channel_order[] = {
    167   [SND_CHMAP_FLW]  =  10,
    168   [SND_CHMAP_FL]   =  20,
    169   [SND_CHMAP_TFL]  =  30,
    170   [SND_CHMAP_FLC]  =  40,
    171   [SND_CHMAP_TFLC] =  50,
    172   [SND_CHMAP_FC]   =  60,
    173   [SND_CHMAP_TFC]  =  70,
    174   [SND_CHMAP_FRC]  =  80,
    175   [SND_CHMAP_TFRC] =  90,
    176   [SND_CHMAP_FR]   = 100,
    177   [SND_CHMAP_TFR]  = 110,
    178   [SND_CHMAP_FRW]  = 120,
    179   [SND_CHMAP_SR]   = 130,
    180   [SND_CHMAP_TSR]  = 140,
    181   [SND_CHMAP_RR]   = 150,
    182   [SND_CHMAP_TRR]  = 160,
    183   [SND_CHMAP_RRC]  = 170,
    184   [SND_CHMAP_RC]   = 180,
    185   [SND_CHMAP_TRC]  = 190,
    186   [SND_CHMAP_RLC]  = 200,
    187   [SND_CHMAP_RL]   = 210,
    188   [SND_CHMAP_TRL]  = 220,
    189   [SND_CHMAP_SL]   = 230,
    190   [SND_CHMAP_TSL]  = 240,
    191   [SND_CHMAP_BC]   = 250,
    192   [SND_CHMAP_TC]   = 260,
    193   [SND_CHMAP_LLFE] = 270,
    194   [SND_CHMAP_LFE]  = 280,
    195   [SND_CHMAP_RLFE] = 290,
    196   /* not in table  = 10000 */
    197   [SND_CHMAP_UNKNOWN] = 20000,
    198   [SND_CHMAP_NA]      = 30000,
    199 };
    200 
    201 static int chpos_cmp(const void *chnum1p, const void *chnum2p)
    202 {
    203   int chnum1 = *(int *)chnum1p;
    204   int chnum2 = *(int *)chnum2p;
    205   int chpos1 = channel_map->pos[chnum1];
    206   int chpos2 = channel_map->pos[chnum2];
    207   int weight1 = 10000;
    208   int weight2 = 10000;
    209 
    210   if (chpos1 < ARRAY_SIZE(channel_order) && channel_order[chpos1])
    211     weight1 = channel_order[chpos1];
    212   if (chpos2 < ARRAY_SIZE(channel_order) && channel_order[chpos2])
    213     weight2 = channel_order[chpos2];
    214 
    215   if (weight1 == weight2) {
    216     /* order by channel number if both have the same position (e.g. UNKNOWN)
    217      * or if neither is in channel_order[] */
    218     return chnum1 - chnum2;
    219   }
    220 
    221   /* order according to channel_order[] */
    222   return weight1 - weight2;
    223 }
    224 
    225 static int *order_channels(void)
    226 {
    227   /* create a (playback order => channel number) table with channels ordered
    228    * according to channel_order[] values */
    229   int i;
    230   int *ordered_chs;
    231 
    232   ordered_chs = calloc(channel_map->channels, sizeof(*ordered_chs));
    233   if (!ordered_chs)
    234     return NULL;
    235 
    236   for (i = 0; i < channel_map->channels; i++)
    237     ordered_chs[i] = i;
    238 
    239   qsort(ordered_chs, channel_map->channels, sizeof(*ordered_chs), chpos_cmp);
    240 
    241   return ordered_chs;
    242 }
    243 #endif
    244 
    245 static int get_speaker_channel(int chn)
    246 {
    247 #ifdef CONFIG_SUPPORT_CHMAP
    248   if (channel_map_set || (ordered_channels && chn >= channel_map->channels))
    249     return chn;
    250   if (ordered_channels)
    251     return ordered_channels[chn];
    252 #endif
    253 
    254   switch (channels) {
    255   case 4:
    256     chn = channels4[chn];
    257     break;
    258   case 6:
    259     chn = channels6[chn];
    260     break;
    261   case 8:
    262     chn = channels8[chn];
    263     break;
    264   }
    265 
    266   return chn;
    267 }
    268 
    269 static const char *get_channel_name(int chn)
    270 {
    271 #ifdef CONFIG_SUPPORT_CHMAP
    272   if (channel_map) {
    273     const char *name = NULL;
    274     if (chn < channel_map->channels)
    275       name = snd_pcm_chmap_long_name(channel_map->pos[chn]);
    276     return name ? name : "Unknown";
    277   }
    278 #endif
    279   return gettext(channel_name[chn]);
    280 }
    281 
    282 static const int	supported_formats[] = {
    283   SND_PCM_FORMAT_S8,
    284   SND_PCM_FORMAT_S16_LE,
    285   SND_PCM_FORMAT_S16_BE,
    286   SND_PCM_FORMAT_FLOAT_LE,
    287   SND_PCM_FORMAT_S32_LE,
    288   SND_PCM_FORMAT_S32_BE,
    289   -1
    290 };
    291 
    292 static void generate_sine(uint8_t *frames, int channel, int count, double *_phase) {
    293   double phase = *_phase;
    294   double max_phase = 1.0 / freq;
    295   double step = 1.0 / (double)rate;
    296   double res;
    297   float fres;
    298   int    chn;
    299   int32_t  ires;
    300   int8_t *samp8 = (int8_t*) frames;
    301   int16_t *samp16 = (int16_t*) frames;
    302   int32_t *samp32 = (int32_t*) frames;
    303   float   *samp_f = (float*) frames;
    304 
    305   while (count-- > 0) {
    306     for(chn=0;chn<channels;chn++) {
    307       switch (format) {
    308       case SND_PCM_FORMAT_S8:
    309         if (chn==channel) {
    310           res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
    311           ires = res;
    312           *samp8++ = ires >> 24;
    313         } else {
    314           *samp8++ = 0;
    315         }
    316         break;
    317       case SND_PCM_FORMAT_S16_LE:
    318         if (chn==channel) {
    319           res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
    320           ires = res;
    321           *samp16++ = LE_SHORT(ires >> 16);
    322         } else {
    323           *samp16++ = 0;
    324         }
    325         break;
    326       case SND_PCM_FORMAT_S16_BE:
    327         if (chn==channel) {
    328           res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
    329           ires = res;
    330           *samp16++ = BE_SHORT(ires >> 16);
    331         } else {
    332           *samp16++ = 0;
    333         }
    334         break;
    335       case SND_PCM_FORMAT_FLOAT_LE:
    336         if (chn==channel) {
    337           res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale;
    338           fres = res;
    339 	  *samp_f++ = fres;
    340         } else {
    341 	  *samp_f++ = 0.0;
    342         }
    343         break;
    344       case SND_PCM_FORMAT_S32_LE:
    345         if (chn==channel) {
    346           res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
    347           ires = res;
    348           *samp32++ = LE_INT(ires);
    349         } else {
    350           *samp32++ = 0;
    351         }
    352         break;
    353       case SND_PCM_FORMAT_S32_BE:
    354         if (chn==channel) {
    355           res = (sin((phase * 2 * M_PI) / max_phase - M_PI)) * generator_scale * 0x7fffffff;
    356           ires = res;
    357           *samp32++ = BE_INT(ires);
    358         } else {
    359           *samp32++ = 0;
    360         }
    361         break;
    362       default:
    363         ;
    364       }
    365     }
    366 
    367     phase += step;
    368     if (phase >= max_phase)
    369       phase -= max_phase;
    370   }
    371 
    372   *_phase = phase;
    373 }
    374 
    375 /* Pink noise is a better test than sine wave because we can tell
    376  * where pink noise is coming from more easily that a sine wave.
    377  */
    378 
    379 
    380 static void generate_pink_noise( uint8_t *frames, int channel, int count) {
    381   double   res;
    382   int      chn;
    383   int32_t  ires;
    384   int8_t  *samp8 = (int8_t*) frames;
    385   int16_t *samp16 = (int16_t*) frames;
    386   int32_t *samp32 = (int32_t*) frames;
    387 
    388   while (count-- > 0) {
    389     for(chn=0;chn<channels;chn++) {
    390       switch (format) {
    391       case SND_PCM_FORMAT_S8:
    392         if (chn==channel) {
    393 	  res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
    394 	  ires = res;
    395 	  *samp8++ = ires >> 24;
    396         } else {
    397 	  *samp8++ = 0;
    398         }
    399         break;
    400       case SND_PCM_FORMAT_S16_LE:
    401         if (chn==channel) {
    402 	  res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
    403 	  ires = res;
    404           *samp16++ = LE_SHORT(ires >> 16);
    405         } else {
    406 	  *samp16++ = 0;
    407         }
    408         break;
    409       case SND_PCM_FORMAT_S16_BE:
    410         if (chn==channel) {
    411           res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
    412           ires = res;
    413           *samp16++ = BE_SHORT(ires >> 16);
    414         } else {
    415           *samp16++ = 0;
    416         }
    417         break;
    418       case SND_PCM_FORMAT_S32_LE:
    419         if (chn==channel) {
    420           res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
    421           ires = res;
    422           *samp32++ = LE_INT(ires);
    423         } else {
    424           *samp32++ = 0;
    425         }
    426         break;
    427       case SND_PCM_FORMAT_S32_BE:
    428         if (chn==channel) {
    429 	  res = generate_pink_noise_sample(&pink) * generator_scale * 0x07fffffff;
    430 	  ires = res;
    431 	  *samp32++ = BE_INT(ires);
    432         } else {
    433 	  *samp32++ = 0;
    434         }
    435         break;
    436       default:
    437         ;
    438       }
    439     }
    440   }
    441 }
    442 
    443 /*
    444  * useful for tests
    445  */
    446 static void generate_pattern(uint8_t *frames, int channel, int count, int *_pattern) {
    447   int pattern = *_pattern;
    448   int    chn;
    449   int8_t *samp8 = (int8_t*) frames;
    450   int16_t *samp16 = (int16_t*) frames;
    451   int32_t *samp32 = (int32_t*) frames;
    452   float   *samp_f = (float*) frames;
    453 
    454   while (count-- > 0) {
    455     for(chn=0;chn<channels;chn++,pattern++) {
    456       switch (format) {
    457       case SND_PCM_FORMAT_S8:
    458         if (chn==channel) {
    459           *samp8++ = pattern & 0xff;
    460         } else {
    461           *samp8++ = 0;
    462         }
    463         break;
    464       case SND_PCM_FORMAT_S16_LE:
    465         if (chn==channel) {
    466           *samp16++ = LE_SHORT(pattern & 0xfffff);
    467         } else {
    468           *samp16++ = 0;
    469         }
    470         break;
    471       case SND_PCM_FORMAT_S16_BE:
    472         if (chn==channel) {
    473           *samp16++ = BE_SHORT(pattern & 0xffff);
    474         } else {
    475           *samp16++ = 0;
    476         }
    477         break;
    478       case SND_PCM_FORMAT_FLOAT_LE:
    479         if (chn==channel) {
    480 	  *samp_f++ = LE_INT(((double)pattern) / INT32_MAX);
    481         } else {
    482 	  *samp_f++ = 0.0;
    483         }
    484         break;
    485       case SND_PCM_FORMAT_S32_LE:
    486         if (chn==channel) {
    487           *samp32++ = LE_INT(pattern);
    488         } else {
    489           *samp32++ = 0;
    490         }
    491         break;
    492       case SND_PCM_FORMAT_S32_BE:
    493         if (chn==channel) {
    494           *samp32++ = BE_INT(pattern);
    495         } else {
    496           *samp32++ = 0;
    497         }
    498         break;
    499       default:
    500         ;
    501       }
    502     }
    503   }
    504 
    505   *_pattern = pattern;
    506 }
    507 
    508 static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access) {
    509   unsigned int rrate;
    510   int          err;
    511   snd_pcm_uframes_t     period_size_min;
    512   snd_pcm_uframes_t     period_size_max;
    513   snd_pcm_uframes_t     buffer_size_min;
    514   snd_pcm_uframes_t     buffer_size_max;
    515 
    516   /* choose all parameters */
    517   err = snd_pcm_hw_params_any(handle, params);
    518   if (err < 0) {
    519     fprintf(stderr, _("Broken configuration for playback: no configurations available: %s\n"), snd_strerror(err));
    520     return err;
    521   }
    522 
    523   /* set the interleaved read/write format */
    524   err = snd_pcm_hw_params_set_access(handle, params, access);
    525   if (err < 0) {
    526     fprintf(stderr, _("Access type not available for playback: %s\n"), snd_strerror(err));
    527     return err;
    528   }
    529 
    530   /* set the sample format */
    531   err = snd_pcm_hw_params_set_format(handle, params, format);
    532   if (err < 0) {
    533     fprintf(stderr, _("Sample format not available for playback: %s\n"), snd_strerror(err));
    534     return err;
    535   }
    536 
    537   /* set the count of channels */
    538   err = snd_pcm_hw_params_set_channels(handle, params, channels);
    539   if (err < 0) {
    540     fprintf(stderr, _("Channels count (%i) not available for playbacks: %s\n"), channels, snd_strerror(err));
    541     return err;
    542   }
    543 
    544   /* set the stream rate */
    545   rrate = rate;
    546   err = snd_pcm_hw_params_set_rate(handle, params, rate, 0);
    547   if (err < 0) {
    548     fprintf(stderr, _("Rate %iHz not available for playback: %s\n"), rate, snd_strerror(err));
    549     return err;
    550   }
    551 
    552   if (rrate != rate) {
    553     fprintf(stderr, _("Rate doesn't match (requested %iHz, get %iHz, err %d)\n"), rate, rrate, err);
    554     return -EINVAL;
    555   }
    556 
    557   printf(_("Rate set to %iHz (requested %iHz)\n"), rrate, rate);
    558   /* set the buffer time */
    559   err = snd_pcm_hw_params_get_buffer_size_min(params, &buffer_size_min);
    560   err = snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size_max);
    561   err = snd_pcm_hw_params_get_period_size_min(params, &period_size_min, NULL);
    562   err = snd_pcm_hw_params_get_period_size_max(params, &period_size_max, NULL);
    563   printf(_("Buffer size range from %lu to %lu\n"),buffer_size_min, buffer_size_max);
    564   printf(_("Period size range from %lu to %lu\n"),period_size_min, period_size_max);
    565   if (period_time > 0) {
    566     printf(_("Requested period time %u us\n"), period_time);
    567     err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, NULL);
    568     if (err < 0) {
    569       fprintf(stderr, _("Unable to set period time %u us for playback: %s\n"),
    570 	     period_time, snd_strerror(err));
    571       return err;
    572     }
    573   }
    574   if (buffer_time > 0) {
    575     printf(_("Requested buffer time %u us\n"), buffer_time);
    576     err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, NULL);
    577     if (err < 0) {
    578       fprintf(stderr, _("Unable to set buffer time %u us for playback: %s\n"),
    579 	     buffer_time, snd_strerror(err));
    580       return err;
    581     }
    582   }
    583   if (! buffer_time && ! period_time) {
    584     buffer_size = buffer_size_max;
    585     if (! period_time)
    586       buffer_size = (buffer_size / nperiods) * nperiods;
    587     printf(_("Using max buffer size %lu\n"), buffer_size);
    588     err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
    589     if (err < 0) {
    590       fprintf(stderr, _("Unable to set buffer size %lu for playback: %s\n"),
    591 	     buffer_size, snd_strerror(err));
    592       return err;
    593     }
    594   }
    595   if (! buffer_time || ! period_time) {
    596     printf(_("Periods = %u\n"), nperiods);
    597     err = snd_pcm_hw_params_set_periods_near(handle, params, &nperiods, NULL);
    598     if (err < 0) {
    599       fprintf(stderr, _("Unable to set nperiods %u for playback: %s\n"),
    600 	     nperiods, snd_strerror(err));
    601       return err;
    602     }
    603   }
    604 
    605   /* write the parameters to device */
    606   err = snd_pcm_hw_params(handle, params);
    607   if (err < 0) {
    608     fprintf(stderr, _("Unable to set hw params for playback: %s\n"), snd_strerror(err));
    609     return err;
    610   }
    611 
    612   snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
    613   snd_pcm_hw_params_get_period_size(params, &period_size, NULL);
    614   printf(_("was set period_size = %lu\n"),period_size);
    615   printf(_("was set buffer_size = %lu\n"),buffer_size);
    616   if (2*period_size > buffer_size) {
    617     fprintf(stderr, _("buffer to small, could not use\n"));
    618     return -EINVAL;
    619   }
    620 
    621   return 0;
    622 }
    623 
    624 static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams) {
    625   int err;
    626 
    627   /* get the current swparams */
    628   err = snd_pcm_sw_params_current(handle, swparams);
    629   if (err < 0) {
    630     fprintf(stderr, _("Unable to determine current swparams for playback: %s\n"), snd_strerror(err));
    631     return err;
    632   }
    633 
    634   /* start the transfer when a buffer is full */
    635   err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size);
    636   if (err < 0) {
    637     fprintf(stderr, _("Unable to set start threshold mode for playback: %s\n"), snd_strerror(err));
    638     return err;
    639   }
    640 
    641   /* allow the transfer when at least period_size frames can be processed */
    642   err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
    643   if (err < 0) {
    644     fprintf(stderr, _("Unable to set avail min for playback: %s\n"), snd_strerror(err));
    645     return err;
    646   }
    647 
    648   /* write the parameters to the playback device */
    649   err = snd_pcm_sw_params(handle, swparams);
    650   if (err < 0) {
    651     fprintf(stderr, _("Unable to set sw params for playback: %s\n"), snd_strerror(err));
    652     return err;
    653   }
    654 
    655   return 0;
    656 }
    657 
    658 #ifdef CONFIG_SUPPORT_CHMAP
    659 static int config_chmap(snd_pcm_t *handle, const char *mapstr)
    660 {
    661   int err;
    662 
    663   if (mapstr) {
    664     channel_map = snd_pcm_chmap_parse_string(mapstr);
    665     if (!channel_map) {
    666       fprintf(stderr, _("Unable to parse channel map string: %s\n"), mapstr);
    667       return -EINVAL;
    668     }
    669     err = snd_pcm_set_chmap(handle, channel_map);
    670     if (err < 0) {
    671       fprintf(stderr, _("Unable to set channel map: %s\n"), mapstr);
    672       return err;
    673     }
    674     channel_map_set = 1;
    675     return 0;
    676   }
    677 
    678   channel_map = snd_pcm_get_chmap(handle);
    679 
    680   /* create a channel order table for default layouts */
    681   if (channel_map)
    682     ordered_channels = order_channels();
    683 
    684   return 0;
    685 }
    686 #endif
    687 
    688 /*
    689  *   Underrun and suspend recovery
    690  */
    691 
    692 static int xrun_recovery(snd_pcm_t *handle, int err) {
    693   if (err == -EPIPE) {	/* under-run */
    694     err = snd_pcm_prepare(handle);
    695     if (err < 0)
    696       fprintf(stderr, _("Can't recovery from underrun, prepare failed: %s\n"), snd_strerror(err));
    697     return 0;
    698   } 
    699   else if (err == -ESTRPIPE) {
    700 
    701     while ((err = snd_pcm_resume(handle)) == -EAGAIN)
    702       sleep(1);	/* wait until the suspend flag is released */
    703 
    704     if (err < 0) {
    705       err = snd_pcm_prepare(handle);
    706       if (err < 0)
    707         fprintf(stderr, _("Can't recovery from suspend, prepare failed: %s\n"), snd_strerror(err));
    708     }
    709 
    710     return 0;
    711   }
    712 
    713   return err;
    714 }
    715 
    716 /*
    717  * Handle WAV files
    718  */
    719 
    720 static const char *wav_file[MAX_CHANNELS];
    721 static int wav_file_size[MAX_CHANNELS];
    722 
    723 struct wave_header {
    724   struct {
    725     uint32_t magic;
    726     uint32_t length;
    727     uint32_t type;
    728   } hdr;
    729   struct {
    730     uint32_t type;
    731     uint32_t length;
    732   } chunk1;
    733   struct {
    734     uint16_t format;
    735     uint16_t channels;
    736     uint32_t rate;
    737     uint32_t bytes_per_sec;
    738     uint16_t sample_size;
    739     uint16_t sample_bits;
    740   } body;
    741   struct {
    742     uint32_t type;
    743     uint32_t length;
    744   } chunk;
    745 };
    746 
    747 #define WAV_RIFF		COMPOSE_ID('R','I','F','F')
    748 #define WAV_WAVE		COMPOSE_ID('W','A','V','E')
    749 #define WAV_FMT			COMPOSE_ID('f','m','t',' ')
    750 #define WAV_DATA		COMPOSE_ID('d','a','t','a')
    751 #define WAV_PCM_CODE		1
    752 
    753 static const char *search_for_file(const char *name)
    754 {
    755   char *file;
    756   if (*name == '/')
    757     return strdup(name);
    758   file = malloc(strlen(wav_file_dir) + strlen(name) + 2);
    759   if (file)
    760     sprintf(file, "%s/%s", wav_file_dir, name);
    761   return file;
    762 }
    763 
    764 static int check_wav_file(int channel, const char *name)
    765 {
    766   struct wave_header header;
    767   int fd;
    768 
    769   wav_file[channel] = search_for_file(name);
    770   if (! wav_file[channel]) {
    771     fprintf(stderr, _("No enough memory\n"));
    772     return -ENOMEM;
    773   }
    774 
    775   if ((fd = open(wav_file[channel], O_RDONLY)) < 0) {
    776     fprintf(stderr, _("Cannot open WAV file %s\n"), wav_file[channel]);
    777     return -EINVAL;
    778   }
    779   if (read(fd, &header, sizeof(header)) < (int)sizeof(header)) {
    780     fprintf(stderr, _("Invalid WAV file %s\n"), wav_file[channel]);
    781     goto error;
    782   }
    783   
    784   if (header.hdr.magic != WAV_RIFF || header.hdr.type != WAV_WAVE) {
    785     fprintf(stderr, _("Not a WAV file: %s\n"), wav_file[channel]);
    786     goto error;
    787   }
    788   if (header.body.format != LE_SHORT(WAV_PCM_CODE)) {
    789     fprintf(stderr, _("Unsupported WAV format %d for %s\n"),
    790 	    LE_SHORT(header.body.format), wav_file[channel]);
    791     goto error;
    792   }
    793   if (header.body.channels != LE_SHORT(1)) {
    794     fprintf(stderr, _("%s is not a mono stream (%d channels)\n"),
    795 	    wav_file[channel], LE_SHORT(header.body.channels)); 
    796     goto error;
    797   }
    798   if (header.body.rate != LE_INT(rate)) {
    799     fprintf(stderr, _("Sample rate doesn't match (%d) for %s\n"),
    800 	    LE_INT(header.body.rate), wav_file[channel]);
    801     goto error;
    802   }
    803   if (header.body.sample_bits != LE_SHORT(16)) {
    804     fprintf(stderr, _("Unsupported sample format bits %d for %s\n"),
    805 	    LE_SHORT(header.body.sample_bits), wav_file[channel]);
    806     goto error;
    807   }
    808   if (header.chunk.type != WAV_DATA) {
    809     fprintf(stderr, _("Invalid WAV file %s\n"), wav_file[channel]);
    810     goto error;
    811   }
    812   wav_file_size[channel] = LE_INT(header.chunk.length);
    813   close(fd);
    814   return 0;
    815 
    816  error:
    817   close(fd);
    818   return -EINVAL;
    819 }
    820 
    821 static int setup_wav_file(int chn)
    822 {
    823   static const char *const wavs[MAX_CHANNELS] = {
    824     "Front_Left.wav",
    825     "Front_Right.wav",
    826     "Rear_Left.wav",
    827     "Rear_Right.wav",
    828     "Front_Center.wav",
    829     "Rear_Center.wav", /* FIXME: should be "Bass" or so */
    830     "Side_Left.wav",
    831     "Side_Right.wav",
    832     "Channel_9.wav",
    833     "Channel_10.wav",
    834     "Channel_11.wav",
    835     "Channel_12.wav",
    836     "Channel_13.wav",
    837     "Channel_14.wav",
    838     "Channel_15.wav",
    839     "Channel_16.wav"
    840   };
    841 
    842   if (given_test_wav_file)
    843     return check_wav_file(chn, given_test_wav_file);
    844 
    845 #ifdef CONFIG_SUPPORT_CHMAP
    846   if (channel_map && chn < channel_map->channels) {
    847     int channel = channel_map->pos[chn] - SND_CHMAP_FL;
    848     if (channel >= 0 && channel < MAX_CHANNELS)
    849       return check_wav_file(chn, wavs[channel]);
    850   }
    851 #endif
    852 
    853   return check_wav_file(chn, wavs[chn]);
    854 }
    855 
    856 static int read_wav(uint16_t *buf, int channel, int offset, int bufsize)
    857 {
    858   static FILE *wavfp = NULL;
    859   int size;
    860 
    861   if (in_aborting)
    862     return -EFAULT;
    863 
    864   if (! wav_file[channel]) {
    865     fprintf(stderr, _("Undefined channel %d\n"), channel);
    866     return -EINVAL;
    867   }
    868 
    869   if (offset >= wav_file_size[channel])
    870    return 0; /* finished */
    871 
    872   if (! offset) {
    873     if (wavfp)
    874       fclose(wavfp);
    875     wavfp = fopen(wav_file[channel], "r");
    876     if (! wavfp)
    877       return -errno;
    878     if (fseek(wavfp, sizeof(struct wave_header), SEEK_SET) < 0)
    879       return -errno;
    880   }
    881   if (offset + bufsize > wav_file_size[channel])
    882     bufsize = wav_file_size[channel] - offset;
    883   bufsize /= channels;
    884   for (size = 0; size < bufsize; size += 2) {
    885     int chn;
    886     for (chn = 0; chn < channels; chn++) {
    887       if (chn == channel) {
    888 	if (fread(buf, 2, 1, wavfp) != 1)
    889 	  return size;
    890       }
    891       else
    892 	*buf = 0;
    893       buf++;
    894     }
    895   }
    896   return size;
    897 }
    898 
    899 
    900 /*
    901  *   Transfer method - write only
    902  */
    903 
    904 static int write_buffer(snd_pcm_t *handle, uint8_t *ptr, int cptr)
    905 {
    906   int err;
    907 
    908   while (cptr > 0 && !in_aborting) {
    909 
    910     err = snd_pcm_writei(handle, ptr, cptr);
    911 
    912     if (err == -EAGAIN)
    913       continue;
    914 
    915     if (err < 0) {
    916       fprintf(stderr, _("Write error: %d,%s\n"), err, snd_strerror(err));
    917       if ((err = xrun_recovery(handle, err)) < 0) {
    918 	fprintf(stderr, _("xrun_recovery failed: %d,%s\n"), err, snd_strerror(err));
    919 	return err;
    920       }
    921       break;	/* skip one period */
    922     }
    923 
    924     ptr += snd_pcm_frames_to_bytes(handle, err);
    925     cptr -= err;
    926   }
    927   return 0;
    928 }
    929 
    930 static int write_loop(snd_pcm_t *handle, int channel, int periods, uint8_t *frames)
    931 {
    932   double phase = 0;
    933   int	 pattern = 0;
    934   int    err, n;
    935 
    936   fflush(stdout);
    937   if (test_type == TEST_WAV) {
    938     int bufsize = snd_pcm_frames_to_bytes(handle, period_size);
    939     n = 0;
    940     while ((err = read_wav((uint16_t *)frames, channel, n, bufsize)) > 0 && !in_aborting) {
    941       n += err;
    942       if ((err = write_buffer(handle, frames,
    943 			      snd_pcm_bytes_to_frames(handle, err * channels))) < 0)
    944 	break;
    945     }
    946     if (buffer_size > n && !in_aborting) {
    947       snd_pcm_drain(handle);
    948       snd_pcm_prepare(handle);
    949     }
    950     return err;
    951   }
    952     
    953 
    954   if (periods <= 0)
    955     periods = 1;
    956 
    957   for(n = 0; n < periods && !in_aborting; n++) {
    958     if (test_type == TEST_PINK_NOISE)
    959       generate_pink_noise(frames, channel, period_size);
    960     else if (test_type == TEST_PATTERN)
    961       generate_pattern(frames, channel, period_size, &pattern);
    962     else
    963       generate_sine(frames, channel, period_size, &phase);
    964 
    965     if ((err = write_buffer(handle, frames, period_size)) < 0)
    966       return err;
    967   }
    968   if (buffer_size > n * period_size && !in_aborting) {
    969     snd_pcm_drain(handle);
    970     snd_pcm_prepare(handle);
    971   }
    972   return 0;
    973 }
    974 
    975 static int prg_exit(int code)
    976 {
    977   if (pcm_handle)
    978     snd_pcm_close(pcm_handle);
    979   exit(code);
    980   return code;
    981 }
    982 
    983 static void signal_handler(int sig)
    984 {
    985   if (in_aborting)
    986     return;
    987 
    988   in_aborting = 1;
    989 
    990   if (pcm_handle)
    991     snd_pcm_abort(pcm_handle);
    992   if (sig == SIGABRT) {
    993     pcm_handle = NULL;
    994     prg_exit(EXIT_FAILURE);
    995   }
    996   signal(sig, signal_handler);
    997 }
    998 
    999 static void help(void)
   1000 {
   1001   const int *fmt;
   1002 
   1003   printf(
   1004 	 _("Usage: speaker-test [OPTION]... \n"
   1005 	   "-h,--help	help\n"
   1006 	   "-D,--device	playback device\n"
   1007 	   "-r,--rate	stream rate in Hz\n"
   1008 	   "-c,--channels	count of channels in stream\n"
   1009 	   "-f,--frequency	sine wave frequency in Hz\n"
   1010 	   "-F,--format	sample format\n"
   1011 	   "-b,--buffer	ring buffer size in us\n"
   1012 	   "-p,--period	period size in us\n"
   1013 	   "-P,--nperiods	number of periods\n"
   1014 	   "-t,--test	pink=use pink noise, sine=use sine wave, wav=WAV file\n"
   1015 	   "-l,--nloops	specify number of loops to test, 0 = infinite\n"
   1016 	   "-s,--speaker	single speaker test. Values 1=Left, 2=right, etc\n"
   1017 	   "-w,--wavfile	Use the given WAV file as a test sound\n"
   1018 	   "-W,--wavdir	Specify the directory containing WAV files\n"
   1019 	   "-m,--chmap	Specify the channel map to override\n"
   1020 	   "-X,--force-frequency	force frequencies outside the 30-8000hz range\n"
   1021 	   "-S,--scale	Scale of generated test tones in percent (default=80)\n"
   1022 	   "\n"));
   1023   printf(_("Recognized sample formats are:"));
   1024   for (fmt = supported_formats; *fmt >= 0; fmt++) {
   1025     const char *s = snd_pcm_format_name(*fmt);
   1026     if (s)
   1027       printf(" %s", s);
   1028   }
   1029 
   1030   printf("\n\n");
   1031 }
   1032 
   1033 int main(int argc, char *argv[]) {
   1034   snd_pcm_t            *handle;
   1035   int                   err, morehelp;
   1036   snd_pcm_hw_params_t  *hwparams;
   1037   snd_pcm_sw_params_t  *swparams;
   1038   uint8_t              *frames;
   1039   int                   chn;
   1040   const int	       *fmt;
   1041   double		time1,time2,time3;
   1042   unsigned int		n, nloops;
   1043   struct   timeval	tv1,tv2;
   1044   int			speakeroptset = 0;
   1045 #ifdef CONFIG_SUPPORT_CHMAP
   1046   const char *chmap = NULL;
   1047 #endif
   1048 
   1049   static const struct option long_option[] = {
   1050     {"help",      0, NULL, 'h'},
   1051     {"device",    1, NULL, 'D'},
   1052     {"rate",      1, NULL, 'r'},
   1053     {"channels",  1, NULL, 'c'},
   1054     {"frequency", 1, NULL, 'f'},
   1055     {"format",    1, NULL, 'F'},
   1056     {"buffer",    1, NULL, 'b'},
   1057     {"period",    1, NULL, 'p'},
   1058     {"nperiods",  1, NULL, 'P'},
   1059     {"test",      1, NULL, 't'},
   1060     {"nloops",    1, NULL, 'l'},
   1061     {"speaker",   1, NULL, 's'},
   1062     {"wavfile",   1, NULL, 'w'},
   1063     {"wavdir",    1, NULL, 'W'},
   1064     {"debug",	  0, NULL, 'd'},
   1065     {"force-frequency",	  0, NULL, 'X'},
   1066     {"scale",	  1, NULL, 'S'},
   1067 #ifdef CONFIG_SUPPORT_CHMAP
   1068     {"chmap",	  1, NULL, 'm'},
   1069 #endif
   1070     {NULL,        0, NULL, 0  },
   1071   };
   1072 
   1073 #ifdef ENABLE_NLS
   1074   setlocale(LC_ALL, "");
   1075   textdomain(PACKAGE);
   1076 #endif
   1077 
   1078   snd_pcm_hw_params_alloca(&hwparams);
   1079   snd_pcm_sw_params_alloca(&swparams);
   1080  
   1081   nloops = 0;
   1082   morehelp = 0;
   1083 
   1084   printf("\nspeaker-test %s\n\n", SND_UTIL_VERSION_STR);
   1085   while (1) {
   1086     int c;
   1087     
   1088     if ((c = getopt_long(argc, argv, "hD:r:c:f:F:b:p:P:t:l:s:w:W:d:XS:"
   1089 #ifdef CONFIG_SUPPORT_CHMAP
   1090 			 "m:"
   1091 #endif
   1092 			 , long_option, NULL)) < 0)
   1093       break;
   1094     
   1095     switch (c) {
   1096     case 'h':
   1097       morehelp++;
   1098       break;
   1099     case 'D':
   1100       device = strdup(optarg);
   1101       break;
   1102     case 'F':
   1103       format = snd_pcm_format_value(optarg);
   1104       for (fmt = supported_formats; *fmt >= 0; fmt++)
   1105         if (*fmt == format)
   1106           break;
   1107       if (*fmt < 0) {
   1108         fprintf(stderr, "Format %s is not supported...\n", snd_pcm_format_name(format));
   1109         exit(EXIT_FAILURE);
   1110       }
   1111       break;
   1112     case 'r':
   1113       rate = atoi(optarg);
   1114       rate = rate < 4000 ? 4000 : rate;
   1115       rate = rate > 384000 ? 384000 : rate;
   1116       break;
   1117     case 'c':
   1118       channels = atoi(optarg);
   1119       channels = channels < 1 ? 1 : channels;
   1120       channels = channels > 1024 ? 1024 : channels;
   1121       break;
   1122     case 'f':
   1123       freq = atof(optarg);
   1124       break;
   1125     case 'b':
   1126       buffer_time = atoi(optarg);
   1127       buffer_time = buffer_time > 1000000 ? 1000000 : buffer_time;
   1128       break;
   1129     case 'p':
   1130       period_time = atoi(optarg);
   1131       period_time = period_time > 1000000 ? 1000000 : period_time;
   1132       break;
   1133     case 'P':
   1134       nperiods = atoi(optarg);
   1135       if (nperiods < 2 || nperiods > 1024) {
   1136 	fprintf(stderr, _("Invalid number of periods %d\n"), nperiods);
   1137 	exit(1);
   1138       }
   1139       break;
   1140     case 't':
   1141       if (*optarg == 'p')
   1142 	test_type = TEST_PINK_NOISE;
   1143       else if (*optarg == 's')
   1144 	test_type = TEST_SINE;
   1145       else if (*optarg == 'w')
   1146 	test_type = TEST_WAV;
   1147       else if (*optarg == 't')
   1148 	test_type = TEST_PATTERN;
   1149       else if (isdigit(*optarg)) {
   1150 	test_type = atoi(optarg);
   1151 	if (test_type < TEST_PINK_NOISE || test_type > TEST_PATTERN) {
   1152 	  fprintf(stderr, _("Invalid test type %s\n"), optarg);
   1153 	  exit(1);
   1154 	}
   1155       } else {
   1156 	fprintf(stderr, _("Invalid test type %s\n"), optarg);
   1157 	exit(1);
   1158       }
   1159       break;
   1160     case 'l':
   1161       nloops = atoi(optarg);
   1162       break;
   1163     case 's':
   1164       speaker = atoi(optarg);
   1165       speaker = speaker < 1 ? 0 : speaker;
   1166       speakeroptset = 1;
   1167       break;
   1168     case 'w':
   1169       given_test_wav_file = optarg;
   1170       break;
   1171     case 'W':
   1172       wav_file_dir = optarg;
   1173       break;
   1174     case 'd':
   1175       debug = 1;
   1176       break;
   1177     case 'X':
   1178       force_frequency = 1;
   1179       break;
   1180 #ifdef CONFIG_SUPPORT_CHMAP
   1181     case 'm':
   1182       chmap = optarg;
   1183       break;
   1184 #endif
   1185     case 'S':
   1186       generator_scale = atoi(optarg) / 100.0;
   1187       break;
   1188     default:
   1189       fprintf(stderr, _("Unknown option '%c'\n"), c);
   1190       exit(EXIT_FAILURE);
   1191       break;
   1192     }
   1193   }
   1194 
   1195   if (morehelp) {
   1196     help();
   1197     exit(EXIT_SUCCESS);
   1198   }
   1199 
   1200   if (speakeroptset) {
   1201     speaker = speaker > channels ? 0 : speaker;
   1202     if (speaker==0) {
   1203       fprintf(stderr, _("Invalid parameter for -s option.\n"));
   1204       exit(EXIT_FAILURE);
   1205     }
   1206   }
   1207 
   1208   if (!force_frequency) {
   1209     freq = freq < 30.0 ? 30.0 : freq;
   1210     freq = freq > 8000.0 ? 8000.0 : freq;
   1211   } else {
   1212     freq = freq < 1.0 ? 1.0 : freq;
   1213   }
   1214 
   1215   if (test_type == TEST_WAV)
   1216     format = SND_PCM_FORMAT_S16_LE; /* fixed format */
   1217 
   1218   printf(_("Playback device is %s\n"), device);
   1219   printf(_("Stream parameters are %iHz, %s, %i channels\n"), rate, snd_pcm_format_name(format), channels);
   1220   switch (test_type) {
   1221   case TEST_PINK_NOISE:
   1222     printf(_("Using 16 octaves of pink noise\n"));
   1223     break;
   1224   case TEST_SINE:
   1225     printf(_("Sine wave rate is %.4fHz\n"), freq);
   1226     break;
   1227   case TEST_WAV:
   1228     printf(_("WAV file(s)\n"));
   1229     break;
   1230 
   1231   }
   1232 
   1233   signal(SIGINT, signal_handler);
   1234   signal(SIGTERM, signal_handler);
   1235   signal(SIGABRT, signal_handler);
   1236 
   1237   if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
   1238     printf(_("Playback open error: %d,%s\n"), err,snd_strerror(err));
   1239     prg_exit(EXIT_FAILURE);
   1240   }
   1241   pcm_handle = handle;
   1242 
   1243   if ((err = set_hwparams(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
   1244     printf(_("Setting of hwparams failed: %s\n"), snd_strerror(err));
   1245     prg_exit(EXIT_FAILURE);
   1246   }
   1247   if ((err = set_swparams(handle, swparams)) < 0) {
   1248     printf(_("Setting of swparams failed: %s\n"), snd_strerror(err));
   1249     prg_exit(EXIT_FAILURE);
   1250   }
   1251 
   1252 #ifdef CONFIG_SUPPORT_CHMAP
   1253   err = config_chmap(handle, chmap);
   1254   if (err < 0)
   1255     prg_exit(EXIT_FAILURE);
   1256 #endif
   1257 
   1258   if (debug) {
   1259     snd_output_t *log;
   1260     err = snd_output_stdio_attach(&log, stderr, 0);
   1261     if (err >= 0) {
   1262       snd_pcm_dump(handle, log);
   1263       snd_output_close(log);
   1264     }
   1265   }
   1266 
   1267   frames = malloc(snd_pcm_frames_to_bytes(handle, period_size));
   1268   if (test_type == TEST_PINK_NOISE)
   1269     initialize_pink_noise(&pink, 16);
   1270   
   1271   if (frames == NULL) {
   1272     fprintf(stderr, _("No enough memory\n"));
   1273     prg_exit(EXIT_FAILURE);
   1274   }
   1275 
   1276   if (speaker==0) {
   1277 
   1278     if (test_type == TEST_WAV) {
   1279       for (chn = 0; chn < channels; chn++) {
   1280 	if (setup_wav_file(get_speaker_channel(chn)) < 0)
   1281 	  prg_exit(EXIT_FAILURE);
   1282       }
   1283     }
   1284 
   1285     for (n = 0; (! nloops || n < nloops) && !in_aborting; n++) {
   1286 
   1287       gettimeofday(&tv1, NULL);
   1288       for(chn = 0; chn < channels; chn++) {
   1289 	int channel = get_speaker_channel(chn);
   1290         printf(" %d - %s\n", channel, get_channel_name(channel));
   1291 
   1292         err = write_loop(handle, channel, ((rate*3)/period_size), frames);
   1293 
   1294         if (err < 0) {
   1295           fprintf(stderr, _("Transfer failed: %s\n"), snd_strerror(err));
   1296           prg_exit(EXIT_SUCCESS);
   1297         }
   1298       }
   1299       gettimeofday(&tv2, NULL);
   1300       time1 = (double)tv1.tv_sec + ((double)tv1.tv_usec / 1000000.0);
   1301       time2 = (double)tv2.tv_sec + ((double)tv2.tv_usec / 1000000.0);
   1302       time3 = time2 - time1;
   1303       printf(_("Time per period = %lf\n"), time3 );
   1304     }
   1305   } else {
   1306     chn = get_speaker_channel(speaker - 1);
   1307 
   1308     if (test_type == TEST_WAV) {
   1309       if (setup_wav_file(chn) < 0)
   1310 	prg_exit(EXIT_FAILURE);
   1311     }
   1312 
   1313     printf("  - %s\n", get_channel_name(chn));
   1314     err = write_loop(handle, chn, ((rate*5)/period_size), frames);
   1315 
   1316     if (err < 0) {
   1317       fprintf(stderr, _("Transfer failed: %s\n"), snd_strerror(err));
   1318     }
   1319   }
   1320 
   1321   snd_pcm_drain(handle);
   1322 
   1323   free(frames);
   1324 #ifdef CONFIG_SUPPORT_CHMAP
   1325   free(ordered_channels);
   1326 #endif
   1327 
   1328   return prg_exit(EXIT_SUCCESS);
   1329 }