14765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev/*
24765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** Copyright 2010, The Android Open-Source Project
34765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
44765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev**
54765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** Licensed under the Apache License, Version 2.0 (the "License");
64765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** you may not use this file except in compliance with the License.
74765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** You may obtain a copy of the License at
84765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev**
94765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev**     http://www.apache.org/licenses/LICENSE-2.0
104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev**
114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** Unless required by applicable law or agreed to in writing, software
124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** distributed under the License is distributed on an "AS IS" BASIS,
134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** See the License for the specific language governing permissions and
154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev** limitations under the License.
164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev*/
174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <stdio.h>
194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <stdlib.h>
204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <fcntl.h>
214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <unistd.h>
224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <stdint.h>
234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <string.h>
244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <signal.h>
254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <errno.h>
264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <sys/poll.h>
274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <sys/ioctl.h>
284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <getopt.h>
294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include <limits.h>
304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#include "alsa_audio.h"
324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ID_RIFF 0x46464952
344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ID_WAVE 0x45564157
354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ID_FMT  0x20746d66
364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define ID_DATA 0x61746164
374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define FORMAT_PCM 1
394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#ifndef ANDROID
414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define strlcat g_strlcat
424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#define strlcpy g_strlcpy
434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev#endif
444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic struct wav_header hdr;
464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic int fd;
474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic struct pcm *pcm;
489746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudanistatic int debug = 0;
499746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudanistatic int pcm_flag = 1;
509746c4758b161e26eec92b1ef1ff1bf0ba0bd268Ajay Dudanistatic int duration = 0;
514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic char *filename;
524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic char *data;
534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic int format = SNDRV_PCM_FORMAT_S16_LE;
544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic int period = 0;
554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic int piped = 0;
564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic struct option long_options[] =
584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"pcm", 0, 0, 'P'},
604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"debug", 0, 0, 'V'},
614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"Mmap", 0, 0, 'M'},
624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"HW", 1, 0, 'D'},
634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"Rate", 1, 0, 'R'},
644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"channel", 1, 0, 'C'},
654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"duration", 1, 0, 'T'},
664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"format", 1, 0, 'F'},
674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {"period", 1, 0, 'B'},
684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    {0, 0, 0, 0}
694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstruct wav_header {
724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t riff_id;
734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t riff_sz;
744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t riff_fmt;
754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t fmt_id;
764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t fmt_sz;
774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint16_t audio_format;
784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint16_t num_channels;
794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t sample_rate;
804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t byte_rate;       /* sample_rate * num_channels * bps / 8 */
814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint16_t block_align;     /* num_channels * bps / 8 */
824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint16_t bits_per_sample;
834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t data_id;
844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t data_sz;
854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev};
864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic int set_params(struct pcm *pcm)
884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     struct snd_pcm_hw_params *params;
904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     struct snd_pcm_sw_params *sparams;
914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     unsigned long periodSize, bufferSize, reqBuffSize;
934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     unsigned int periodTime, bufferTime;
944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     unsigned int requestedRate = pcm->rate;
954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     params = (struct snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     if (!params) {
984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          fprintf(stderr, "Arec:Failed to allocate ALSA hardware parameters!");
994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          return -ENOMEM;
1004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     }
1014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_init(params);
1034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
1054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    (pcm->flags & PCM_MMAP)? SNDRV_PCM_ACCESS_MMAP_INTERLEAVED : SNDRV_PCM_ACCESS_RW_INTERLEAVED);
1064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, pcm->format);
1074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
1084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    SNDRV_PCM_SUBFORMAT_STD);
1094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     if (period)
1104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, period);
1114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     else
1124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 10);
1134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
1144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
1154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    pcm->channels * 16);
1164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
1174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    pcm->channels);
1184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, pcm->rate);
1194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     param_set_hw_refine(pcm, params);
1214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     if (param_set_hw_params(pcm, params)) {
1234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         fprintf(stderr, "Arec:cannot set hw params");
1244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         return -errno;
1254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     }
1264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     if (debug)
1274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          param_dump(params);
1284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     pcm->buffer_size = pcm_buffer_size(params);
1304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     pcm->period_size = pcm_period_size(params);
1314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     pcm->period_cnt = pcm->buffer_size/pcm->period_size;
1324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     if (debug) {
1334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf (stderr,"period_size (%d)", pcm->period_size);
1344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf (stderr," buffer_size (%d)", pcm->buffer_size);
1354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf (stderr," period_cnt  (%d)\n", pcm->period_cnt);
1364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     }
1374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     sparams = (struct snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
1384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     if (!sparams) {
1394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         fprintf(stderr, "Arec:Failed to allocate ALSA software parameters!\n");
1404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         return -ENOMEM;
1414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     }
1424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
1434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sparams->period_step = 1;
1444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (pcm->flags & PCM_MONO) {
1464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->avail_min = pcm->period_size/2;
1474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->xfer_align = pcm->period_size/2;
1484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else if (pcm->flags & PCM_QUAD) {
1494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->avail_min = pcm->period_size/8;
1504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->xfer_align = pcm->period_size/8;
1514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else if (pcm->flags & PCM_5POINT1) {
1524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->avail_min = pcm->period_size/12;
1534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->xfer_align = pcm->period_size/12;
1544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
1554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->avail_min = pcm->period_size/4;
1564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        sparams->xfer_align = pcm->period_size/4;
1574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sparams->start_threshold = 1;
1604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sparams->stop_threshold = INT_MAX;
1614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sparams->silence_size = 0;
1624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sparams->silence_threshold = 0;
1634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (param_set_sw_params(pcm, sparams)) {
1654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         fprintf(stderr, "Arec:cannot set sw params");
1664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         return -errno;
1674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (debug) {
1694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf (stderr,"avail_min (%lu)\n", sparams->avail_min);
1704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf (stderr,"start_threshold (%lu)\n", sparams->start_threshold);
1714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf (stderr,"stop_threshold (%lu)\n", sparams->stop_threshold);
1724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf (stderr,"xfer_align (%lu)\n", sparams->xfer_align);
1734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
1744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return 0;
1754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
1774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevint record_file(unsigned rate, unsigned channels, int fd, unsigned count,  unsigned flags, const char *device)
1794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
1804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    unsigned xfer, bufsize;
1814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int r, avail;
1824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int nfds = 1;
1834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    static int start = 0;
1844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    struct snd_xferi x;
1854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long frames;
1864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    unsigned offset = 0;
1874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int err;
1884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    struct pollfd pfd[1];
1894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int rec_size = 0;
1904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    flags |= PCM_IN;
1924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
1934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (channels == 1)
1944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flags |= PCM_MONO;
1954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    else if (channels == 4)
1964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flags |= PCM_QUAD;
1974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    else if (channels == 6)
1984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flags |= PCM_5POINT1;
1994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    else
2004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flags |= PCM_STEREO;
2014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    pcm = pcm_open(flags, device);
2034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!pcm_ready(pcm)) {
2044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        pcm_close(pcm);
2054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        goto fail;
2064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    pcm->channels = channels;
2084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    pcm->rate = rate;
2094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    pcm->flags = flags;
2104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    pcm->format = format;
2114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (set_params(pcm)) {
2124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf(stderr, "Arec:params setting failed\n");
2134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        pcm_close(pcm);
2144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        return -EINVAL;
2154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
2164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!pcm_flag) {
2184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (pcm_prepare(pcm)) {
2194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            fprintf(stderr, "Arec:Failed in pcm_prepare\n");
2204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            pcm_close(pcm);
2214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return -errno;
2224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
2244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            fprintf(stderr, "Arec: Hostless IOCTL_START Error no %d \n", errno);
2254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            pcm_close(pcm);
2264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return -errno;
2274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	}
2284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        while(1);
2294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev   }
2304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (flags & PCM_MMAP) {
2324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        u_int8_t *dst_addr = NULL;
2334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        struct snd_pcm_sync_ptr *sync_ptr1 = pcm->sync_ptr;
2344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        unsigned int tmp;
2354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (mmap_buffer(pcm)) {
2374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             fprintf(stderr, "Arec:params setting failed\n");
2384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             pcm_close(pcm);
2394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             return -EINVAL;
2404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (debug)
2424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            fprintf(stderr, "Arec:mmap_buffer done\n");
2434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (pcm_prepare(pcm)) {
2454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            fprintf(stderr, "Arec:Failed in pcm_prepare\n");
2464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            pcm_close(pcm);
2474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return -errno;
2484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        bufsize = pcm->period_size;
2514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (debug)
2524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    fprintf(stderr, "Arec:bufsize = %d\n", bufsize);
2534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
2544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		if (errno == EPIPE) {
2554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev			fprintf(stderr, "Arec:Failed in SNDRV_PCM_IOCTL_START\n");
2564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev			/* we failed to make our window -- try to restart */
2574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev			pcm->running = 0;
2584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		} else {
2594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev			fprintf(stderr, "Arec:Error no %d \n", errno);
2604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev			return -errno;
2614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		}
2624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        pfd[0].fd = pcm->fd;
2654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        pfd[0].events = POLLIN;
2664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
2674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        hdr.data_sz = 0;
2684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (pcm->flags & PCM_MONO) {
2694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                frames = bufsize / 2;
2704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        } else if (pcm->flags & PCM_QUAD) {
2714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                frames = bufsize / 8;
2724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        } else if (pcm->flags & PCM_5POINT1) {
2734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                frames = bufsize / 12;
2744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        } else{
2754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                frames = bufsize / 4;
2764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
2774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        x.frames = frames;
2784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        for(;;) {
2794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		if (!pcm->running) {
2804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    if (pcm_prepare(pcm))
2814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        return --errno;
2824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    start = 0;
2834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
2844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                /* Sync the current Application pointer from the kernel */
2854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
2864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                err = sync_ptr(pcm);
2874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (err == EPIPE) {
2884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     fprintf(stderr, "Arec:Failed in sync_ptr \n");
2894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     /* we failed to make our window -- try to restart */
2904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     //pcm->overruns++;
2914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     pcm->running = 0;
2924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     continue;
2934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
2944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev               /*
2954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                * Check for the available data in driver. If available data is
2964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                * less than avail_min we need to wait
2974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                */
2984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                avail = pcm_avail(pcm);
2994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (debug)
3004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     fprintf(stderr, "Arec:avail 1 = %d frames = %ld\n",avail, frames);
3014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (avail < 0)
3024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        return avail;
3034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (avail < pcm->sw_p->avail_min) {
3044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        poll(pfd, nfds, TIMEOUT_INFINITE);
3054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        continue;
3064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
3074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	 	if (x.frames > avail)
3084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                        frames = avail;
3094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev               /*
3104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                * Now that we have data size greater than avail_min available to
3114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                * to be read we need to calcutate the buffer offset where we can
3124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                * start reading from.
3134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                */
3144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                dst_addr = dst_address(pcm);
3154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev               /*
3174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                * Write to the file at the destination address from kernel mmaped buffer
3184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                * This reduces a extra copy of intermediate buffer.
3194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                */
3204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (write(fd, dst_addr, bufsize) != bufsize) {
3214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    fprintf(stderr, "Arec:could not write %d bytes\n", bufsize);
3224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    return -errno;
3234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
3244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                x.frames -= frames;
3254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                pcm->sync_ptr->c.control.appl_ptr += frames;
3264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		pcm->sync_ptr->flags = 0;
3274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                err = sync_ptr(pcm);
3284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (err == EPIPE) {
3294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     fprintf(stderr, "Arec:Failed in sync_ptr \n");
3304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     /* we failed to make our window -- try to restart */
3314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     pcm->running = 0;
3324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                     continue;
3334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
3344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                rec_size += bufsize;
3354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                hdr.data_sz += bufsize;
3364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                hdr.riff_sz = hdr.data_sz + 44 - 8;
3374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (!piped) {
3384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    lseek(fd, 0, SEEK_SET);
3394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    write(fd, &hdr, sizeof(hdr));
3404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    lseek(fd, 0, SEEK_END);
3414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
3424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (rec_size >= count)
3434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                      break;
3444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev           }
3454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
3464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    bufsize = pcm->period_size;
3474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (pcm_prepare(pcm)) {
3484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                fprintf(stderr, "Arec:Failed in pcm_prepare\n");
3494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                pcm_close(pcm);
3504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                return -errno;
3514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
3524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    data = calloc(1, bufsize);
3544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    if (!data) {
3554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		fprintf(stderr, "Arec:could not allocate %d bytes\n", bufsize);
3564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		return -ENOMEM;
3574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    }
3584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    while (!pcm_read(pcm, data, bufsize)) {
3604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		if (write(fd, data, bufsize) != bufsize) {
3614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		    fprintf(stderr, "Arec:could not write %d bytes\n", bufsize);
3624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		    break;
3634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		}
3644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                rec_size += bufsize;
3654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                hdr.data_sz += bufsize;
3664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                hdr.riff_sz = hdr.data_sz + 44 - 8;
3674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (!piped) {
3684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    lseek(fd, 0, SEEK_SET);
3694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    write(fd, &hdr, sizeof(hdr));
3704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    lseek(fd, 0, SEEK_END);
3714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                }
3724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                if (rec_size >= count)
3734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    break;
3744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    }
3754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
3764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    fprintf(stderr, " rec_size =%d count =%d\n", rec_size, count);
3774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    close(fd);
3784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    free(data);
3794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    pcm_close(pcm);
3804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return hdr.data_sz;
3814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevfail:
3834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    fprintf(stderr, "Arec:pcm error: %s\n", pcm_error(pcm));
3844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return -errno;
3854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
3864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevint rec_raw(const char *fg, const char *device, int rate, int ch,
3884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                    const char *fn)
3894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
3904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    unsigned flag = 0;
3914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t rec_max_sz = 2147483648LL;
3924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t count;
3934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int i = 0;
3944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
3954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!fn) {
3964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fd = fileno(stdout);
3974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        piped = 1;
3984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
3994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
4004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        if (fd < 0) {
4014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
4024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            return -EBADFD;
4034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        }
4044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
4054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (duration == 0) {
4064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         count = rec_max_sz;
4074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
4084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         count = rate * ch * 2;
4094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         count *= (uint32_t)duration;
4104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
4114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    count = count < rec_max_sz ? count : rec_max_sz;
4124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (debug)
4134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fprintf(stderr, "arec: %d ch, %d hz, %d bit, format %x\n",
4144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        ch, rate, 16, format);
4154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!strncmp(fg, "M", sizeof("M"))) {
4174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flag = PCM_MMAP;
4184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else if (!strncmp(fg, "N", sizeof("N"))) {
4194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flag = PCM_NMMAP;
4204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
4214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return record_file(rate, ch, fd, count, flag, device);
4224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
4234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevint rec_wav(const char *fg, const char *device, int rate, int ch, const char *fn)
4254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
4264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    unsigned flag = 0;
4274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t rec_max_sz = 2147483648LL;
4284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    uint32_t count = 0;
4294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int i = 0;
4304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (pcm_flag) {
4324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (!fn) {
4334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev              fd = fileno(stdout);
4344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev              piped = 1;
4354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            } else {
4364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	       fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
4374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	       if (fd < 0) {
4384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	            fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
4394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		    return -EBADFD;
4404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	       }
4414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
4424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    memset(&hdr, 0, sizeof(struct wav_header));
4434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.riff_id = ID_RIFF;
4444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.riff_fmt = ID_WAVE;
4454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.fmt_id = ID_FMT;
4464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.fmt_sz = 16;
4474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.audio_format = FORMAT_PCM;
4484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.num_channels = ch;
4494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.sample_rate = rate;
4504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            hdr.bits_per_sample = 16;
4514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8;
4524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            hdr.block_align = ( hdr.bits_per_sample * ch ) / 8;
4534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.data_id = ID_DATA;
4544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    hdr.data_sz = 0;
4554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            if (duration == 0) {
4574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                count = rec_max_sz;
4584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            } else {
4594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                count = rate * ch * 2;
4604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                count *= (uint32_t)duration;
4614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            }
4624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            hdr.riff_sz = hdr.data_sz + 44 - 8;
4634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
4644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		if (debug)
4654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		    fprintf(stderr, "arec: cannot write header\n");
4664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		return -errno;
4674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    }
4684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	    if (debug)
4694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n",
4704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		    hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
4714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		    hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
4724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
4734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            hdr.sample_rate = rate;
4744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            hdr.num_channels = ch;
4754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
4764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (!strncmp(fg, "M", sizeof("M"))) {
4784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flag = PCM_MMAP;
4794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else if (!strncmp(fg, "N", sizeof("N"))) {
4804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        flag = PCM_NMMAP;
4814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
4824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return record_file(hdr.sample_rate, hdr.num_channels, fd, count, flag, device);
4834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
4844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevstatic void signal_handler(int sig)
4864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
4874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    long file_size;
4884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    FILE *fp;
4894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
4904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    fprintf(stderr, "Arec:Aborted by signal %s...\n", strsignal(sig));
4914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    fprintf(stderr, "Arec:lseeked to %d", (int) lseek(fd, 0, SEEK_SET));
4924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    hdr.riff_sz = hdr.data_sz + 44 - 8;
4934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    fprintf(stderr, "Arec: hdr.data_sz =%d\n", hdr.data_sz);
4944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    fprintf(stderr, "Arec: hdr.riff_sz =%d\n", hdr.riff_sz);
4954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
4964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	if (debug)
4974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev            fprintf(stderr, "Arec:arec: cannot write header\n");
4984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else
4994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       fd = -1;
5004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
5014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (fd > 1) {
5024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        close(fd);
5034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        fd = -1;
5044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
5054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    free(filename);
5064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    free(data);
5074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    pcm = NULL;
5084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    raise(sig);
5094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
5104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
5114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchevint main(int argc, char **argv)
5124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev{
5134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int rate = 48000;
5144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int ch = 1;
5154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int i = 0;
5164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int option_index = 0;
5174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int c;
5184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    char *mmap = "N";
5194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    char *device = "hw:0,0";
5204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    struct sigaction sa;
5214765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    int rc = 0;
5224765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
5234765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (argc < 2) {
5244765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          printf("\nUsage: arec [options] <file>\n"
5254765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "options:\n"
5264765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-D <hw:C,D>	-- Alsa PCM by name\n"
5274765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-M		-- Mmap stream\n"
5284765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-P		-- Hostless steam[No PCM]\n"
5294765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-V		-- verbose\n"
5304765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-C		-- Channels\n"
5314765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-R		-- Rate\n"
5324765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-T		-- Time in seconds for recording\n"
5334765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		"-F             -- Format\n"
5344765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-B             -- Period\n"
5354765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "<file> \n");
5364765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev           for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
5374765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev               if (get_format_name(i))
5384765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                   fprintf(stderr, "%s ", get_format_name(i));
5394765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev           fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
5404765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          return 0;
5414765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
5424765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:", long_options, &option_index)) != -1) {
5434765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       switch (c) {
5444765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'P':
5454765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          pcm_flag = 0;
5464765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5474765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'V':
5484765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          debug = 1;
5494765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5504765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'M':
5514765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          mmap = "M";
5524765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5534765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'D':
5544765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          device = optarg;
5554765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5564765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'R':
5574765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          rate = (int)strtol(optarg, NULL, 0);
5584765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5594765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'C':
5604765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          ch  = (int)strtol(optarg, NULL, 0);
5614765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5624765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'T':
5634765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          duration = (int)strtol(optarg, NULL, 0);
5644765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5654765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'F':
5664765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          format = (int)get_format(optarg);
5674765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5684765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       case 'B':
5694765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          period = (int)strtol(optarg, NULL, 0);
5704765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          break;
5714765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       default:
5724765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          printf("\nUsage: arec [options] <file>\n"
5734765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "options:\n"
5744765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-D <hw:C,D>	-- Alsa PCM by name\n"
5754765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-M		-- Mmap stream\n"
5764765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-P		-- Hostless steam[No PCM]\n"
5774765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-V		-- verbose\n"
5784765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-C		-- Channels\n"
5794765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-R		-- Rate\n"
5804765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-T		-- Time in seconds for recording\n"
5814765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev		"-F             -- Format\n"
5824765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "-B             -- Period\n"
5834765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                "<file> \n");
5844765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev           for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
5854765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev               if (get_format_name(i))
5864765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev                   fprintf(stderr, "%s ", get_format_name(i));
5874765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev           fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
5884765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          return -EINVAL;
5894765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev       }
5904765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
5914765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    filename = (char*) calloc(1, 30);
5924765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev     if (!filename) {
5934765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          fprintf(stderr, "Arec:Failed to allocate filename!");
5944765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev          return -ENOMEM;
5954765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
5964765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (optind > argc - 1) {
5974765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        free(filename);
5984765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        filename = NULL;
5994765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
6004765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        strlcpy(filename, argv[optind++], 30);
6014765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
6024765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
6034765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    memset(&sa, 0, sizeof(sa));
6044765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sa.sa_handler = &signal_handler;
6054765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    sigaction(SIGABRT, &sa, NULL);
6064765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
6074765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (pcm_flag) {
6084765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev	 if (format == SNDRV_PCM_FORMAT_S16_LE)
6094765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             rc = rec_wav(mmap, device, rate, ch, filename);
6104765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev         else
6114765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev             rc = rec_raw(mmap, device, rate, ch, filename);
6124765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    } else {
6134765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        rc = rec_wav(mmap, device, rate, ch, "dummy");
6144765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    }
6154765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    if (filename)
6164765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev        free(filename);
6174765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
6184765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev    return rc;
6194765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev}
6204765c439491ddda3de658e62cc4a64d10e726b34Iliyan Malchev
621