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 
set_params(struct pcm * pcm)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 
play_file(unsigned rate,unsigned channels,int fd,unsigned flags,const char * device,unsigned data_sz)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 
play_raw(const char * fg,int rate,int ch,const char * device,const char * fn)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 
play_wav(const char * fg,int rate,int ch,const char * device,const char * fn)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 
main(int argc,char ** argv)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