Home | History | Annotate | Download | only in libalsa-intf
      1 /*
      2 ** Copyright 2010, The Android Open-Source Project
      3 ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <fcntl.h>
     21 #include <unistd.h>
     22 #include <stdint.h>
     23 #include <string.h>
     24 #include <errno.h>
     25 #include <sys/poll.h>
     26 #include <sys/ioctl.h>
     27 #include <getopt.h>
     28 
     29 #include <sound/asound.h>
     30 #include "alsa_audio.h"
     31 
     32 #ifndef ANDROID
     33 #define strlcat g_strlcat
     34 #define strlcpy g_strlcpy
     35 #endif
     36 
     37 #define ID_RIFF 0x46464952
     38 #define ID_WAVE 0x45564157
     39 #define ID_FMT  0x20746d66
     40 #define ID_DATA 0x61746164
     41 
     42 #define FORMAT_PCM 1
     43 #define LOG_NDEBUG 1
     44 static pcm_flag = 1;
     45 static debug = 0;
     46 static uint32_t play_max_sz = 2147483648LL;
     47 static int format = SNDRV_PCM_FORMAT_S16_LE;
     48 static int period = 0;
     49 static int compressed = 0;
     50 static char *compr_codec;
     51 static int piped = 0;
     52 
     53 static struct option long_options[] =
     54 {
     55     {"pcm", 0, 0, 'P'},
     56     {"debug", 0, 0, 'V'},
     57     {"Mmap", 0, 0, 'M'},
     58     {"HW", 1, 0, 'D'},
     59     {"Rate", 1, 0, 'R'},
     60     {"channel", 1, 0, 'C'},
     61     {"format", 1, 0, 'F'},
     62     {"period", 1, 0, 'B'},
     63     {"compressed", 0, 0, 'T'},
     64     {0, 0, 0, 0}
     65 };
     66 
     67 struct wav_header {
     68     uint32_t riff_id;
     69     uint32_t riff_sz;
     70     uint32_t riff_fmt;
     71     uint32_t fmt_id;
     72     uint32_t fmt_sz;
     73     uint16_t audio_format;
     74     uint16_t num_channels;
     75     uint32_t sample_rate;
     76     uint32_t byte_rate;       /* sample_rate * num_channels * bps / 8 */
     77     uint16_t block_align;     /* num_channels * bps / 8 */
     78     uint16_t bits_per_sample;
     79     uint32_t data_id;
     80     uint32_t data_sz;
     81 };
     82 
     83 static int set_params(struct pcm *pcm)
     84 {
     85      struct snd_pcm_hw_params *params;
     86      struct snd_pcm_sw_params *sparams;
     87 
     88      unsigned long periodSize, bufferSize, reqBuffSize;
     89      unsigned int periodTime, bufferTime;
     90      unsigned int requestedRate = pcm->rate;
     91      int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 );
     92 
     93      params = (struct snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
     94      if (!params) {
     95           fprintf(stderr, "Aplay:Failed to allocate ALSA hardware parameters!");
     96           return -ENOMEM;
     97      }
     98 
     99      param_init(params);
    100 
    101      param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
    102                     (pcm->flags & PCM_MMAP)? SNDRV_PCM_ACCESS_MMAP_INTERLEAVED : SNDRV_PCM_ACCESS_RW_INTERLEAVED);
    103      param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, pcm->format);
    104      param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
    105                     SNDRV_PCM_SUBFORMAT_STD);
    106      if (period)
    107          param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, period);
    108      else
    109          param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 10);
    110      param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
    111      param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
    112                     pcm->channels * 16);
    113      param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
    114                     pcm->channels);
    115      param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, pcm->rate);
    116      param_set_hw_refine(pcm, params);
    117 
    118      if (param_set_hw_params(pcm, params)) {
    119          fprintf(stderr, "Aplay:cannot set hw params\n");
    120          return -errno;
    121      }
    122      if (debug)
    123          param_dump(params);
    124 
    125      pcm->buffer_size = pcm_buffer_size(params);
    126      pcm->period_size = pcm_period_size(params);
    127      pcm->period_cnt = pcm->buffer_size/pcm->period_size;
    128      if (debug) {
    129         fprintf (stderr,"period_cnt = %d\n", pcm->period_cnt);
    130         fprintf (stderr,"period_size = %d\n", pcm->period_size);
    131         fprintf (stderr,"buffer_size = %d\n", pcm->buffer_size);
    132      }
    133      sparams = (struct snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
    134      if (!sparams) {
    135          fprintf(stderr, "Aplay:Failed to allocate ALSA software parameters!\n");
    136          return -ENOMEM;
    137      }
    138      // Get the current software parameters
    139     sparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
    140     sparams->period_step = 1;
    141 
    142     sparams->avail_min = pcm->period_size/(channels * 2) ;
    143     sparams->start_threshold =  pcm->period_size/(channels * 2) ;
    144     sparams->stop_threshold =  pcm->buffer_size ;
    145     sparams->xfer_align =  pcm->period_size/(channels * 2) ; /* needed for old kernels */
    146 
    147     sparams->silence_size = 0;
    148     sparams->silence_threshold = 0;
    149 
    150     if (param_set_sw_params(pcm, sparams)) {
    151         fprintf(stderr, "Aplay:cannot set sw params");
    152         return -errno;
    153     }
    154     if (debug) {
    155        fprintf (stderr,"sparams->avail_min= %lu\n", sparams->avail_min);
    156        fprintf (stderr," sparams->start_threshold= %lu\n", sparams->start_threshold);
    157        fprintf (stderr," sparams->stop_threshold= %lu\n", sparams->stop_threshold);
    158        fprintf (stderr," sparams->xfer_align= %lu\n", sparams->xfer_align);
    159        fprintf (stderr," sparams->boundary= %lu\n", sparams->boundary);
    160     }
    161     return 0;
    162 }
    163 
    164 static int play_file(unsigned rate, unsigned channels, int fd,
    165               unsigned flags, const char *device, unsigned data_sz)
    166 {
    167     struct pcm *pcm;
    168     struct mixer *mixer;
    169     struct pcm_ctl *ctl = NULL;
    170     unsigned bufsize;
    171     char *data;
    172     long avail;
    173     long frames;
    174     int nfds = 1;
    175     struct snd_xferi x;
    176     unsigned offset = 0;
    177     int err;
    178     static int start = 0;
    179     struct pollfd pfd[1];
    180     int remainingData = 0;
    181 
    182     flags |= PCM_OUT;
    183 
    184     if (channels == 1)
    185         flags |= PCM_MONO;
    186     else if (channels == 6)
    187 	flags |= PCM_5POINT1;
    188     else
    189         flags |= PCM_STEREO;
    190 
    191     if (debug)
    192         flags |= DEBUG_ON;
    193     else
    194         flags |= DEBUG_OFF;
    195 
    196     pcm = pcm_open(flags, device);
    197     if (pcm < 0)
    198         return pcm;
    199 
    200     if (!pcm_ready(pcm)) {
    201         pcm_close(pcm);
    202         return -EBADFD;
    203     }
    204 
    205 #ifdef QCOM_COMPRESSED_AUDIO_ENABLED
    206     if (compressed) {
    207        struct snd_compr_caps compr_cap;
    208        struct snd_compr_params compr_params;
    209        if (ioctl(pcm->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
    210           fprintf(stderr, "Aplay: SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
    211           pcm_close(pcm);
    212           return -errno;
    213        }
    214        if (!period)
    215            period = compr_cap.min_fragment_size;
    216            switch (get_compressed_format(compr_codec)) {
    217            case FORMAT_MP3:
    218                compr_params.codec.id = compr_cap.codecs[FORMAT_MP3];
    219                break;
    220            case FORMAT_AC3_PASS_THROUGH:
    221                compr_params.codec.id = compr_cap.codecs[FORMAT_AC3_PASS_THROUGH];
    222                printf("codec -d = %x\n", compr_params.codec.id);
    223                break;
    224            default:
    225                break;
    226            }
    227        if (ioctl(pcm->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
    228           fprintf(stderr, "Aplay: SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
    229           pcm_close(pcm);
    230           return -errno;
    231        }
    232     }
    233 #endif
    234     pcm->channels = channels;
    235     pcm->rate = rate;
    236     pcm->flags = flags;
    237     pcm->format = format;
    238     if (set_params(pcm)) {
    239         fprintf(stderr, "Aplay:params setting failed\n");
    240         pcm_close(pcm);
    241         return -errno;
    242     }
    243 
    244     if (!pcm_flag) {
    245        if (pcm_prepare(pcm)) {
    246           fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
    247           pcm_close(pcm);
    248           return -errno;
    249        }
    250        if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
    251           fprintf(stderr, "Aplay: Hostless IOCTL_START Error no %d \n", errno);
    252           pcm_close(pcm);
    253           return -errno;
    254        }
    255         while(1);
    256     }
    257 
    258     remainingData = data_sz;
    259 
    260     if (flags & PCM_MMAP) {
    261         u_int8_t *dst_addr = NULL;
    262         struct snd_pcm_sync_ptr *sync_ptr1 = pcm->sync_ptr;
    263         if (mmap_buffer(pcm)) {
    264              fprintf(stderr, "Aplay:params setting failed\n");
    265              pcm_close(pcm);
    266              return -errno;
    267         }
    268         if (pcm_prepare(pcm)) {
    269           fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
    270           pcm_close(pcm);
    271           return -errno;
    272         }
    273 
    274         bufsize = pcm->period_size;
    275         if (debug)
    276           fprintf(stderr, "Aplay:bufsize = %d\n", bufsize);
    277 
    278         pfd[0].fd = pcm->timer_fd;
    279         pfd[0].events = POLLIN;
    280 
    281         frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
    282         for (;;) {
    283              if (!pcm->running) {
    284                   if (pcm_prepare(pcm)) {
    285                       fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
    286                       pcm_close(pcm);
    287                       return -errno;
    288                   }
    289                   pcm->running = 1;
    290                   start = 0;
    291              }
    292              /* Sync the current Application pointer from the kernel */
    293              pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
    294              err = sync_ptr(pcm);
    295              if (err == EPIPE) {
    296                  fprintf(stderr, "Aplay:Failed in sync_ptr \n");
    297                  /* we failed to make our window -- try to restart */
    298                  pcm->underruns++;
    299                  pcm->running = 0;
    300                  continue;
    301              }
    302              /*
    303               * Check for the available buffer in driver. If available buffer is
    304               * less than avail_min we need to wait
    305               */
    306              avail = pcm_avail(pcm);
    307              if (avail < 0) {
    308                  fprintf(stderr, "Aplay:Failed in pcm_avail\n");
    309                  pcm_close(pcm);
    310                  return avail;
    311              }
    312              if (avail < pcm->sw_p->avail_min) {
    313                  poll(pfd, nfds, TIMEOUT_INFINITE);
    314                  continue;
    315              }
    316              /*
    317               * Now that we have buffer size greater than avail_min available to
    318               * to be written we need to calcutate the buffer offset where we can
    319               * start writting.
    320               */
    321              dst_addr = dst_address(pcm);
    322 
    323              if (debug) {
    324                  fprintf(stderr, "dst_addr = 0x%08x\n", dst_addr);
    325                  fprintf(stderr, "Aplay:avail = %d frames = %d\n",avail, frames);
    326                  fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  pcm->buffer_size %d  sync_ptr->c.control.appl_ptr %ld\n",
    327                             pcm->sync_ptr->s.status.hw_ptr,
    328                             pcm->buffer_size,
    329                             pcm->sync_ptr->c.control.appl_ptr);
    330              }
    331 
    332              /*
    333               * Read from the file to the destination buffer in kernel mmaped buffer
    334               * This reduces a extra copy of intermediate buffer.
    335               */
    336              memset(dst_addr, 0x0, bufsize);
    337 
    338              if (data_sz && !piped) {
    339                  if (remainingData < bufsize) {
    340                      bufsize = remainingData;
    341                      frames = (pcm->flags & PCM_MONO) ? (remainingData / 2) : (remainingData / 4);
    342                  }
    343              }
    344 
    345              err = read(fd, dst_addr , bufsize);
    346              if (debug)
    347                  fprintf(stderr, "read %d bytes from file\n", err);
    348              if (err <= 0)
    349                  break;
    350 
    351              if (data_sz && !piped) {
    352                  remainingData -= bufsize;
    353                  if (remainingData <= 0)
    354                      break;
    355              }
    356 
    357              /*
    358               * Increment the application pointer with data written to kernel.
    359               * Update kernel with the new sync pointer.
    360               */
    361              pcm->sync_ptr->c.control.appl_ptr += frames;
    362              pcm->sync_ptr->flags = 0;
    363 
    364              err = sync_ptr(pcm);
    365              if (err == EPIPE) {
    366                  fprintf(stderr, "Aplay:Failed in sync_ptr 2 \n");
    367                  /* we failed to make our window -- try to restart */
    368                  pcm->underruns++;
    369                  pcm->running = 0;
    370                  continue;
    371              }
    372 
    373              if (debug) {
    374                  fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
    375                             pcm->sync_ptr->s.status.hw_ptr,
    376                             pcm->sync_ptr->c.control.appl_ptr);
    377 #ifdef QCOM_COMPRESSED_AUDIO_ENABLED
    378                  if (compressed && start) {
    379                     struct snd_compr_tstamp tstamp;
    380 		    if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp))
    381 			fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n");
    382                     else
    383 	                fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp);
    384 		}
    385 #endif
    386              }
    387              /*
    388               * If we have reached start threshold of buffer prefill,
    389               * its time to start the driver.
    390               */
    391                  if(start)
    392                      goto start_done;
    393                  if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
    394                      err = -errno;
    395                      if (errno == EPIPE) {
    396                          fprintf(stderr, "Aplay:Failed in SNDRV_PCM_IOCTL_START\n");
    397                          /* we failed to make our window -- try to restart */
    398                          pcm->underruns++;
    399                          pcm->running = 0;
    400                          continue;
    401                     } else {
    402                         fprintf(stderr, "Aplay:Error no %d \n", errno);
    403                         pcm_close(pcm);
    404                         return -errno;
    405                     }
    406                 } else
    407                     start = 1;
    408 
    409 start_done:
    410                 offset += frames;
    411         }
    412         while(1) {
    413             pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
    414             sync_ptr(pcm);
    415             /*
    416              * Check for the available buffer in driver. If available buffer is
    417              * less than avail_min we need to wait
    418              */
    419             if (pcm->sync_ptr->s.status.hw_ptr >= pcm->sync_ptr->c.control.appl_ptr) {
    420                 fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
    421                            pcm->sync_ptr->s.status.hw_ptr,
    422                            pcm->sync_ptr->c.control.appl_ptr);
    423                 break;
    424             } else
    425                 poll(pfd, nfds, TIMEOUT_INFINITE);
    426         }
    427     } else {
    428         if (pcm_prepare(pcm)) {
    429             fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
    430             pcm_close(pcm);
    431             return -errno;
    432         }
    433 
    434         bufsize = pcm->period_size;
    435 
    436         data = calloc(1, bufsize);
    437         if (!data) {
    438             fprintf(stderr, "Aplay:could not allocate %d bytes\n", bufsize);
    439             pcm_close(pcm);
    440             return -ENOMEM;
    441         }
    442 
    443         if (data_sz && !piped) {
    444             if (remainingData < bufsize)
    445                 bufsize = remainingData;
    446         }
    447 
    448         while (read(fd, data, bufsize) > 0) {
    449             if (pcm_write(pcm, data, bufsize)){
    450                 fprintf(stderr, "Aplay: pcm_write failed\n");
    451                 free(data);
    452                 pcm_close(pcm);
    453                 return -errno;
    454             }
    455             memset(data, 0, bufsize);
    456 
    457             if (data_sz && !piped) {
    458                 remainingData -= bufsize;
    459                 if (remainingData <= 0)
    460                     break;
    461                 if (remainingData < bufsize)
    462                        bufsize = remainingData;
    463             }
    464         }
    465         free(data);
    466     }
    467     fprintf(stderr, "Aplay: Done playing\n");
    468     pcm_close(pcm);
    469     return 0;
    470 }
    471 
    472 int play_raw(const char *fg, int rate, int ch, const char *device, const char *fn)
    473 {
    474     int fd;
    475     unsigned flag = 0;
    476 
    477     if(!fn) {
    478         fd = fileno(stdin);
    479         piped = 1;
    480     } else {
    481         fd = open(fn, O_RDONLY);
    482         if (fd < 0) {
    483             fprintf(stderr, "Aplay:aplay: cannot open '%s'\n", fn);
    484             return fd;
    485         }
    486     }
    487 
    488     if (!strncmp(fg, "M", sizeof("M")))
    489         flag = PCM_MMAP;
    490     else if (!strncmp(fg, "N", sizeof("N")))
    491         flag = PCM_NMMAP;
    492 
    493     fprintf(stderr, "aplay: Playing '%s': format %s ch = %d\n",
    494 		    fn, get_format_desc(format), ch );
    495     return play_file(rate, ch, fd, flag, device, 0);
    496 }
    497 
    498 int play_wav(const char *fg, int rate, int ch, const char *device, const char *fn)
    499 {
    500     struct wav_header hdr;
    501     int fd;
    502     unsigned flag = 0;
    503 
    504     if (pcm_flag) {
    505         if(!fn) {
    506             fd = fileno(stdin);
    507             piped = 1;
    508         } else {
    509             fd = open(fn, O_RDONLY);
    510             if (fd < 0) {
    511                 fprintf(stderr, "Aplay:aplay: cannot open '%s'\n", fn);
    512                 return fd;
    513             }
    514         }
    515         if (compressed) {
    516             hdr.sample_rate = rate;
    517             hdr.num_channels = ch;
    518             hdr.data_sz = 0;
    519             goto ignore_header;
    520         }
    521 
    522         if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
    523             fprintf(stderr, "Aplay:aplay: cannot read header\n");
    524             return -errno;
    525         }
    526 
    527         if ((hdr.riff_id != ID_RIFF) ||
    528             (hdr.riff_fmt != ID_WAVE) ||
    529             (hdr.fmt_id != ID_FMT)) {
    530             fprintf(stderr, "Aplay:aplay: '%s' is not a riff/wave file\n", fn);
    531             return -EINVAL;
    532         }
    533         if ((hdr.audio_format != FORMAT_PCM) ||
    534             (hdr.fmt_sz != 16)) {
    535             fprintf(stderr, "Aplay:aplay: '%s' is not pcm format\n", fn);
    536             return -EINVAL;
    537         }
    538         if (hdr.bits_per_sample != 16) {
    539             fprintf(stderr, "Aplay:aplay: '%s' is not 16bit per sample\n", fn);
    540             return -EINVAL;
    541         }
    542     } else {
    543         fd = -EBADFD;
    544         hdr.sample_rate = rate;
    545         hdr.num_channels = ch;
    546         hdr.data_sz = 0;
    547     }
    548 
    549 ignore_header:
    550     if (!strncmp(fg, "M", sizeof("M")))
    551         flag = PCM_MMAP;
    552     else if (!strncmp(fg, "N", sizeof("N")))
    553         flag = PCM_NMMAP;
    554     fprintf(stderr, "aplay: Playing '%s':%s\n", fn, get_format_desc(format) );
    555 
    556     return play_file(hdr.sample_rate, hdr.num_channels, fd, flag, device, hdr.data_sz);
    557 }
    558 
    559 int main(int argc, char **argv)
    560 {
    561     int option_index = 0;
    562     int c,i;
    563     int ch = 2;
    564     int rate = 44100;
    565     char *mmap = "N";
    566     char *device = "hw:0,0";
    567     char *filename;
    568     int rc = 0;
    569 
    570     if (argc <2) {
    571           printf("\nUsage: aplay [options] <file>\n"
    572                 "options:\n"
    573                 "-D <hw:C,D>	-- Alsa PCM by name\n"
    574                 "-M		-- Mmap stream\n"
    575                 "-P		-- Hostless steam[No PCM]\n"
    576 		"-C             -- Channels\n"
    577 		"-R             -- Rate\n"
    578                 "-V		-- verbose\n"
    579 		"-F             -- Format\n"
    580                 "-B             -- Period\n"
    581                 "-T <MP3, AAC, AC3_PASS_THROUGH>  -- Compressed\n"
    582                 "<file> \n");
    583            fprintf(stderr, "Formats Supported:\n");
    584            for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; ++i)
    585                if (get_format_name(i))
    586                    fprintf(stderr, "%s ", get_format_name(i));
    587            fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
    588            return 0;
    589      }
    590      while ((c = getopt_long(argc, argv, "PVMD:R:C:F:B:T:", long_options, &option_index)) != -1) {
    591        switch (c) {
    592        case 'P':
    593           pcm_flag = 0;
    594           break;
    595        case 'V':
    596           debug = 1;
    597           break;
    598        case 'M':
    599           mmap = "M";
    600           break;
    601        case 'D':
    602           device = optarg;
    603           break;
    604        case 'R':
    605           rate = (int)strtol(optarg, NULL, 0);
    606           break;
    607        case 'C':
    608           ch = (int)strtol(optarg, NULL, 0);
    609           break;
    610        case 'F':
    611           printf("optarg = %s\n", optarg);
    612           format = get_format(optarg);
    613           break;
    614        case 'B':
    615           period = (int)strtol(optarg, NULL, 0);
    616           break;
    617        case 'T':
    618           compressed = 1;
    619           printf("compressed codec type requested = %s\n", optarg);
    620           compr_codec = optarg;
    621           break;
    622        default:
    623           printf("\nUsage: aplay [options] <file>\n"
    624                 "options:\n"
    625                 "-D <hw:C,D>	-- Alsa PCM by name\n"
    626                 "-M		-- Mmap stream\n"
    627                 "-P		-- Hostless steam[No PCM]\n"
    628                 "-V		-- verbose\n"
    629                 "-C		-- Channels\n"
    630 		"-R             -- Rate\n"
    631 		"-F             -- Format\n"
    632                 "-B             -- Period\n"
    633                 "-T             -- Compressed\n"
    634                 "<file> \n");
    635            fprintf(stderr, "Formats Supported:\n");
    636            for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
    637                if (get_format_name(i))
    638                    fprintf(stderr, "%s ", get_format_name(i));
    639            fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
    640           return -EINVAL;
    641        }
    642 
    643     }
    644     filename = (char*) calloc(1, 30);
    645     if (!filename) {
    646           fprintf(stderr, "Aplay:Failed to allocate filename!");
    647           return -ENOMEM;
    648     }
    649     if (optind > argc - 1) {
    650        free(filename);
    651        filename = NULL;
    652     } else {
    653        strlcpy(filename, argv[optind++], 30);
    654     }
    655 
    656     if (pcm_flag) {
    657 	 if (format == SNDRV_PCM_FORMAT_S16_LE)
    658              rc = play_wav(mmap, rate, ch, device, filename);
    659          else
    660              rc = play_raw(mmap, rate, ch, device, filename);
    661     } else {
    662         rc = play_wav(mmap, rate, ch, device, "dummy");
    663     }
    664     if (filename)
    665         free(filename);
    666 
    667     return rc;
    668 }
    669 
    670