waverec.c example

This is a sample application that captures (i.e., records) audio data.

This version corresponds to QNX Software Development Platform 6.6 io-audio patch (patch ID 4687).

/*
 * $QNXLicenseC:
 * Copyright 2016, QNX Software Systems. All Rights Reserved.
 *
 * You must obtain a written license from and pay applicable license fees to QNX
 * Software Systems before you may reproduce, modify or distribute this software,
 * or any work that includes all or part of this software.   Free development
 * licenses are available for evaluation and non-commercial purposes.  For more
 * information visit http://licensing.qnx.com or email licensing@qnx.com.
 *
 * This file may contain contributions from others.  Please review this entire
 * file for other proprietary rights or license notices, as well as the QNX
 * Development Suite License Guide at http://licensing.qnx.com/license-guide/
 * for other information.
 * $
 */


#include <errno.h>
#include <fcntl.h>
#include <gulliver.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/termio.h>
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>

#include <sys/asoundlib.h>

#include <audio/audio_manager_routing.h>

/* *INDENT-OFF* */
struct
{
    char        riff_id[4];
    uint32_t    wave_len;
    struct
    {
        char        fmt_id[8];
        uint32_t    fmt_len;
        struct
        {
            uint16_t    format_tag;
            uint16_t    voices;
            uint32_t    rate;
            uint32_t    char_per_sec;
            uint16_t    block_align;
            uint16_t    bits_per_sample;
        }
        fmt;
        struct
        {
            char        data_id[4];
            uint32_t    data_len;
        }
        data;
    }
    wave;
}
riff_hdr =
{
    {'R', 'I', 'F', 'F' },
    sizeof (riff_hdr.wave),
    {
        {'W', 'A', 'V', 'E', 'f', 'm', 't', ' '    },
        sizeof (riff_hdr.wave.fmt),
        {
            1, 0, 0, 0, 0, 0
        },
        {
            {'d', 'a', 't', 'a' },
            0,
        }
    }
};
/* *INDENT-ON* */

static snd_mixer_t *mixer_handle = NULL;
static snd_pcm_t *pcm_handle = NULL;
static char *mSampleBfr1 = NULL;
static FILE *file1 = NULL;
static int stdin_raw = 0;
static int uses_audioman_handle = 0;
static unsigned int audioman_handle;

int
dev_raw (int fd)
{
        struct termios termios_p;

        if (tcgetattr (fd, &termios_p))
                return (-1);

        termios_p.c_cc[VMIN] = 1;
        termios_p.c_cc[VTIME] = 0;
        termios_p.c_lflag &= ~(ICANON | ECHO | ISIG);
        return (tcsetattr (fd, TCSANOW, &termios_p));
}

int
dev_unraw (int fd)
{
        struct termios termios_p;

        if (tcgetattr (fd, &termios_p))
                return (-1);

        termios_p.c_lflag |= (ICANON | ECHO | ISIG);
        return (tcsetattr (fd, TCSAFLUSH, &termios_p));
}

void
cleanup(void)
{
        if (stdin_raw)
                dev_unraw (fileno (stdin));
        if (mSampleBfr1)
                free(mSampleBfr1);
        if (mixer_handle)
                snd_mixer_close (mixer_handle);
        if (file1)
                fclose(file1);
        if (pcm_handle)
                snd_pcm_close (pcm_handle);
        if (uses_audioman_handle)
                audio_manager_free_handle( audioman_handle );
}

void
cleanup_and_exit(int exit_code)
{
        cleanup();
        exit(exit_code);
}

//*****************************************************************************
/* *INDENT-OFF* */
#ifdef __USAGE
%C[Options] *

Options:
    -a[card#:]<dev#>   the card & device number to record from
                       OR
    -a[name]           the symbolic name of the device to record from

    -8                 use 8 bit mode (16 bit default)
    -b <size>          Sample size (8, 16, 32)
    -m                 record in mono (stereo default)
    -n <voices>        the number of voices to record (2 voices default, stereo)
    -r <rate>          record at rate (44100 default | 48000 44100 22050 11025)
    -t <sec>           seconds to record (5 seconds default)
    -f <frag_size>     requested fragment size
    -v                 verbosity
    -c <args>[,args ...] voice matrix configuration
    -o <audioman type> Specifies an audioman type for the capture stream.
    -x                 use mmap interface
    -i <0|1>           Interleave samples (default: 1)
    -R <value>         SRC rate method
                       (0 = linear interpolation, 1 = 7-pt kaiser windowed, 2 = 20-pt remez)
    -z<num_frags>      requested number of fragments
    -y                 Nonblocking mode

Note:
    If both 'm' and 'n' are specified in commandline, the one specified later will be used

Args:
    1=<hw_channel_bitmask> hardware channel bitmask for application voice 1
    2=<hw_channel_bitmask> hardware channel bitmask for application voice 2
    3=<hw_channel_bitmask> hardware channel bitmask for application voice 3
    4=<hw_channel_bitmask> hardware channel bitmask for application voice 4
#endif
/* *INDENT-ON* */
//*****************************************************************************

volatile int end = 0;

void sig_handler( int sig_no )
{
        end = 1;
        return;
}

const char *
why_failed ( int why_failed )
{
        switch (why_failed)
        {
                case SND_PCM_PARAMS_BAD_MODE:
                        return ("Bad Mode Parameter");
                case SND_PCM_PARAMS_BAD_START:
                        return ("Bad Start Parameter");
                case SND_PCM_PARAMS_BAD_STOP:
                        return ("Bad Stop Parameter");
                case SND_PCM_PARAMS_BAD_FORMAT:
                        return ("Bad Format Parameter");
                case SND_PCM_PARAMS_BAD_RATE:
                        return ("Bad Rate Parameter");
                case SND_PCM_PARAMS_BAD_VOICES:
                        return ("Bad Vocies Parameter");
                case SND_PCM_PARAMS_NO_CHANNEL:
                        return ("No Channel Available");
                default:
                        return ("Unknown Error");
        }

        return ("No Error");
}

int
main (int argc, char **argv)
{
        int     card = -1;
        int     dev = 0;
        int     ret;

        unsigned int mSamples;
        int     mSampleRate;
        int     mSampleChannels;
        int     mSampleBits;
        int     mSampleTime;
        int     fragsize = -1;
        int     num_frags = -1;
        int     verbose = 0;
        int     mode = SND_PCM_OPEN_CAPTURE;

        int     rtn;
        int     mixer_fd = 0;
        int     pcm_fd;

        snd_pcm_channel_info_t pi;
        snd_mixer_group_t group;
        snd_pcm_channel_params_t pp;
        snd_pcm_channel_setup_t setup;
        int     bsize, N = 0, c;
        uint32_t voice_mask[] = { 0, 0, 0, 0 };
        snd_pcm_voice_conversion_t voice_conversion;
        int     voice_override = 0;
        char   *sub_opts, *sub_opts_copy, *value;
        char   *dev_opts[] = {
#define CHN1 0
                "1",
#define CHN2 1
                "2",
#define CHN3 2
                "3",
#define CHN4 3
                "4",
                NULL
        };
        char    name[_POSIX_PATH_MAX] = { 0 };
        char    *type = NULL;
        audio_manager_audio_type_t audioman_type;
        int interleave = 1;
        fd_set  rfds;
        int use_mmap = 0;
        int rate_method = 0;

        mSampleRate = 44100;
        mSampleChannels = 2;
        mSampleBits = 16;
        mSampleTime = 5;

        while ((c = getopt (argc, argv, "8b:a:f:mn:r:t:vc:o:xi:R:z:y")) != EOF)
        {
                switch (c)
                {
                case '8':
                        mSampleBits = 8;
                        break;
                case 'b':
                        mSampleBits = atoi (optarg);
                        if (mSampleBits != 8 && mSampleBits != 16 && mSampleBits != 24 && mSampleBits != 32)
                        {
                                fprintf(stderr, "Invalid sample size, must be one of 8, 16, 24, 32\n");
                                return (EXIT_FAILURE);
                        }
                        break;
                case 'a':
                        if (strchr (optarg, ':'))
                        {
                                card = atoi (optarg);
                                dev = atoi (strchr (optarg, ':') + 1);
                        }
                        else if (isalpha (optarg[0]) || optarg[0] == '/')
                                strcpy (name, optarg);
                        else
                                dev = atoi (optarg);

                        if (name[0] != '\0')
                                printf ("Using device /dev/snd/%s\n", name);
                        else
                                printf ("Using card %d device %d \n", card, dev);
                        break;
                case 'f':
                        fragsize = atoi (optarg);
                        break;
                case 'i':
                        interleave = atoi(optarg);
                        if (interleave <= 0)
                                interleave = 0;
                        else
                                interleave = 1;
                        break;
                case 'm':
                        mSampleChannels = 1;
                        break;
                case 'n':
                        mSampleChannels = atoi (optarg);
                        break;
                case 'r':
                        mSampleRate = atoi (optarg);
                        break;
                case 't':
                        mSampleTime = atoi (optarg);
                        break;
                case 'v':
                        verbose = 1;
                        break;
                case 'c':
                        sub_opts = sub_opts_copy = strdup (optarg);
                        if (sub_opts == NULL) {
                                perror("Cannot allocate sub_opts");
                                return (EXIT_FAILURE);
                        }
                        while (*sub_opts != '\0')
                        {
                                int channel = getsubopt (&sub_opts, dev_opts, &value);
                                if( channel >= 0 && channel < sizeof(voice_mask)/sizeof(voice_mask[0]) && value ) {
                                        voice_mask[channel] = strtoul (value, NULL, 0);
                                } else {
                                        fprintf (stderr, "Invalid channel map specified\n");
                                        free(sub_opts_copy);
                                        return (EXIT_FAILURE);
                                }
                        }
                        free(sub_opts_copy);
                        voice_override = 1;
                        break;
                case 'o':
                        type = optarg;
                        uses_audioman_handle = 1;
                        break;
                case 'x':
                        use_mmap = 1;
                        break;
                case 'R':
                        rate_method = atoi(optarg);
                        if (rate_method < 0 || rate_method > 2)
                        {
                                rate_method = 0;
                                printf("Invalid rate method, using method 0\n");
                        }
                        break;
                case 'z':
                        num_frags = atoi (optarg) - 1;
                        break;
                case 'y':
                        mode |= SND_PCM_OPEN_NONBLOCK;
                        break;
                default:
                        fprintf(stderr, "Invalid option -%c\n", c);
                        return (EXIT_FAILURE);
                }
        }

        if (optind >= argc)
        {
                fprintf(stderr, "no file specified\n");
                return (EXIT_FAILURE);
        }

        if (name[0] != '\0')
        {
                snd_pcm_info_t info;

                if ((rtn = snd_pcm_open_name (&pcm_handle, name, mode)) < 0)
                {
                        fprintf(stderr, "snd_pcm_open_name failed - %s\n", snd_strerror(rtn));
                        return (EXIT_FAILURE);
                }
                rtn = snd_pcm_info (pcm_handle, &info);
                card = info.card;
        }
        else
        {
                if (card == -1)
                {
                        if ((rtn = snd_pcm_open_preferred (&pcm_handle, &card, &dev, mode)) < 0)
                        {
                                fprintf(stderr, "snd_pcm_open_preferred failed - %s\n", snd_strerror(rtn));
                                return (EXIT_FAILURE);
                        }
                }
                else
                {
                        if ((rtn = snd_pcm_open (&pcm_handle, card, dev, mode)) < 0)
                        {
                                fprintf(stderr, "snd_pcm_open failed - %s\n", snd_strerror(rtn));
                                return (EXIT_FAILURE);
                        }
                }
        }

        if (uses_audioman_handle) {
                audioman_type = audio_manager_get_type_from_name( type );
                if ( audio_manager_get_handle( audioman_type,
                                               getpid(),
                                               false,
                                               &audioman_handle ) >= 0) {
                        snd_pcm_set_audioman_handle( pcm_handle, audioman_handle );
                        if(type) {
                                printf("Audio Manager Type: %s\n", type);
                        }
                } else {
                        // Return an error because the user wanted to use audioman.
                        perror("Audio Manager is not available");
                        cleanup_and_exit(EXIT_FAILURE);
                }
        }

        if ((file1 = fopen (argv[optind], "w")) == 0)
        {
                perror("file open failed");
                cleanup_and_exit(EXIT_FAILURE);
        }

        if( mSampleTime == 0 ) {
                mSamples = 0xFFFFFFFF - sizeof(riff_hdr) + 8;
        } else {
                mSamples = mSampleRate * mSampleChannels * mSampleBits / 8 * mSampleTime;
        }

        riff_hdr.wave.fmt.voices = ENDIAN_LE16 (mSampleChannels);
        riff_hdr.wave.fmt.rate = ENDIAN_LE32 (mSampleRate);
        riff_hdr.wave.fmt.char_per_sec =
                ENDIAN_LE32 (mSampleRate * mSampleChannels * mSampleBits / 8);
        riff_hdr.wave.fmt.block_align = ENDIAN_LE16 (mSampleChannels * mSampleBits / 8);
        riff_hdr.wave.fmt.bits_per_sample = ENDIAN_LE16 (mSampleBits);
        riff_hdr.wave.data.data_len = ENDIAN_LE32 (mSamples);
        riff_hdr.wave_len = ENDIAN_LE32 (mSamples + sizeof (riff_hdr) - 8);
        fwrite (&riff_hdr, 1, sizeof (riff_hdr), file1);

        printf ("SampleRate = %d, Channels = %d, SampleBits = %d\n", mSampleRate, mSampleChannels,
                mSampleBits);

        if (!use_mmap)
        {
                /* disabling mmap is not actually required in this example but it is included to
                 * demonstrate how it is used when it is required.
                 */
                snd_pcm_plugin_set_disable (pcm_handle, PLUGIN_DISABLE_MMAP);
        }

        memset (&pi, 0, sizeof (pi));
        pi.channel = SND_PCM_CHANNEL_CAPTURE;
        if ((rtn = snd_pcm_plugin_info (pcm_handle, &pi)) < 0)
        {
                fprintf (stderr, "snd_pcm_plugin_info failed: %s\n", snd_strerror (rtn));
                cleanup_and_exit(EXIT_FAILURE);
        }

        memset (&pp, 0, sizeof (pp));

        pp.mode = SND_PCM_MODE_BLOCK;
        pp.channel = SND_PCM_CHANNEL_CAPTURE;
        pp.start_mode = SND_PCM_START_DATA;
        pp.stop_mode = SND_PCM_STOP_STOP;
        pp.time = 1;

        pp.buf.block.frag_size = pi.max_fragment_size;
        if (fragsize != -1)
                pp.buf.block.frag_size = fragsize;
        pp.buf.block.frags_max = num_frags;
        pp.buf.block.frags_min = 1;

        pp.format.interleave = interleave;
        pp.format.rate = mSampleRate;
        pp.format.voices = mSampleChannels;

        switch (mSampleBits)
        {
                case 8:
                        pp.format.format = SND_PCM_SFMT_U8;
                        break;
                case 16:
                default:
                        pp.format.format = SND_PCM_SFMT_S16_LE;
                        break;
                case 24:
                        pp.format.format = SND_PCM_SFMT_S24_LE;
                        break;
                case 32:
                        pp.format.format = SND_PCM_SFMT_S32_LE;
                        break;
        }

        if ((rtn = snd_pcm_plugin_set_src_method(pcm_handle, rate_method)) != rate_method)
        {
                fprintf(stderr, "Failed to apply rate_method %d, using %d\n", rate_method, rtn);
        }

        if ((rtn = snd_pcm_plugin_params (pcm_handle, &pp)) < 0)
        {
                fprintf (stderr, "snd_pcm_plugin_params failed: %s - %s\n", snd_strerror (rtn), why_failed(pp.why_failed));
                cleanup_and_exit(EXIT_FAILURE);
        }

        if (voice_override)
        {
                snd_pcm_plugin_get_voice_conversion (pcm_handle, SND_PCM_CHANNEL_CAPTURE,
                        &voice_conversion);
                voice_conversion.matrix[0] = voice_mask[0];
                voice_conversion.matrix[1] = voice_mask[1];
                voice_conversion.matrix[2] = voice_mask[2];
                voice_conversion.matrix[3] = voice_mask[3];
                snd_pcm_plugin_set_voice_conversion (pcm_handle, SND_PCM_CHANNEL_CAPTURE,
                        &voice_conversion);
        }

        memset (&setup, 0, sizeof (setup));
        memset (&group, 0, sizeof (group));
        setup.channel = SND_PCM_CHANNEL_CAPTURE;
        setup.mixer_gid = &group.gid;
        if ((rtn = snd_pcm_plugin_setup (pcm_handle, &setup)) < 0)
        {
                fprintf (stderr, "snd_pcm_plugin_setup failed: %s\n", snd_strerror (rtn));
                cleanup_and_exit(EXIT_FAILURE);
        }
        printf ("Format %s \n", snd_pcm_get_format_name (setup.format.format));
        printf ("Frag Size %d \n", setup.buf.block.frag_size);
        printf ("Total Frags %d \n", setup.buf.block.frags);
        printf ("Rate %d \n", setup.format.rate);
        bsize = setup.buf.block.frag_size;

        if (group.gid.name[0] == 0)
        {
                printf ("Mixer Pcm Group [%s] Not Set \n", group.gid.name);
                printf ("***>>>> Input Gain Controls Disabled <<<<*** \n");
        }
        else
        {
                printf ("Mixer Pcm Group [%s]\n", group.gid.name);
                if ((rtn = snd_mixer_open (&mixer_handle, setup.mixer_card, setup.mixer_device)) < 0)
                {
                        fprintf (stderr, "snd_mixer_open failed: %s\n", snd_strerror (rtn));
                        cleanup_and_exit(EXIT_FAILURE);
                }
        }

        if (tcgetpgrp (0) == getpid ()) {
                stdin_raw = 1;
                dev_raw (fileno (stdin));
        }

        mSampleBfr1 = malloc (bsize);
        if ( mSampleBfr1 == NULL ) {
                perror("Failed to allocate pcm buffer");
                cleanup_and_exit(EXIT_FAILURE);
        }

        if ((rtn = snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_CAPTURE)) < 0)
        {
                fprintf (stderr, "snd_pcm_plugin_prepare failed: %s\n", snd_strerror (rtn));
                cleanup_and_exit(EXIT_FAILURE);
        }

        FD_ZERO (&rfds);
        signal(SIGINT, sig_handler);
        signal(SIGTERM, sig_handler);
        while (!end && N < mSamples)
        {
                /* If we are the foreground process group associated with STDIN then include
                 * STDIN in the fdset to handle key presses.
                 */
                if (stdin_raw)
                        FD_SET (STDIN_FILENO, &rfds);
                if (mixer_handle)
                {
                        /* Include the mixer_handle descriptor in the fdset to handle
                         * mixer events.
                         */
                        mixer_fd = snd_mixer_file_descriptor (mixer_handle);
                        FD_SET (mixer_fd, &rfds);
                }
                rtn = pcm_fd = snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_CAPTURE);
                FD_SET (pcm_fd, &rfds);

                if (mixer_handle)
                        rtn = max (mixer_fd, pcm_fd);

                if (select (rtn + 1, &rfds, NULL, NULL, NULL) == -1)
                {
                        perror("select");
                        break; /* break loop to exit cleanly */
                }

                if (FD_ISSET (STDIN_FILENO, &rfds))
                {
                        c = getc (stdin);
                        if (c != EOF)
                        {
                                /* Only handle volume key presses if there is a mixer group */
                                if (group.gid.name[0] != 0)
                                {
                                        if ((rtn = snd_mixer_group_read (mixer_handle, &group)) < 0)
                                                fprintf (stderr, "snd_mixer_group_read failed: %s\n", snd_strerror (rtn));
                                        switch (c)
                                        {
                                        case 'q':
                                                group.volume.names.front_left += 1;
                                                break;
                                        case 'a':
                                                group.volume.names.front_left -= 1;
                                                break;
                                        case 'w':
                                                group.volume.names.front_left += 1;
                                                group.volume.names.front_right += 1;
                                                break;
                                        case 's':
                                                group.volume.names.front_left -= 1;
                                                group.volume.names.front_right -= 1;
                                                break;
                                        case 'e':
                                                group.volume.names.front_right += 1;
                                                break;
                                        case 'd':
                                                group.volume.names.front_right -= 1;
                                                break;
                                        default:
                                                break;
                                        }

                                        if (group.volume.names.front_left > group.max)
                                                group.volume.names.front_left = group.max;
                                        if (group.volume.names.front_left < group.min)
                                                group.volume.names.front_left = group.min;
                                        if (group.volume.names.front_right > group.max)
                                                group.volume.names.front_right = group.max;
                                        if (group.volume.names.front_right < group.min)
                                                group.volume.names.front_right = group.min;
                                        if ((rtn = snd_mixer_group_write (mixer_handle, &group)) < 0)
                                                fprintf (stderr, "snd_mixer_group_write failed: %s\n", snd_strerror (rtn));

                                        if (group.max==group.min)
                                                printf ("Volume Now at %d:%d\n", group.max, group.max);
                                        else
                                                printf ("Volume Now at %d:%d \n",
                                                                100 * (group.volume.names.front_left - group.min) / (group.max - group.min),
                                                                100 * (group.volume.names.front_right - group.min) / (group.max - group.min));
                                }

                                switch (c)
                                {
                                case 'o':
                                        sleep(5);
                                        break;
                                case 'f':
                                        if( (ret = snd_pcm_plugin_flush( pcm_handle, SND_PCM_CHANNEL_CAPTURE )) == 0 ) {
                                                printf("Flushing\n");
                                        } else {
                                                fprintf(stderr, "Flush failed: %d\n", ret);
                                        }
                                        break;
                                case 'g':
                                        if( (ret = snd_pcm_plugin_prepare( pcm_handle, SND_PCM_CHANNEL_CAPTURE )) == 0 ) {
                                                printf("Preparing\n");
                                        } else {
                                                fprintf(stderr, "Preparing failed: %d\n", ret);
                                        }
                                        break;
                                case 'p':
                                        if( (ret = snd_pcm_capture_pause( pcm_handle )) == 0 ) {
                                                printf("Pausing\n");
                                        } else {
                                                fprintf(stderr, "Pause failed: %d\n", ret);
                                        }
                                        break;
                                case 'r':
                                        if( (ret = snd_pcm_capture_resume( pcm_handle )) == 0 ) {
                                                printf("Resuming\n");
                                        } else {
                                                fprintf(stderr, "Resume failed: %d\n", ret);
                                        }
                                        break;
                                case 3: //Ctrl-C
                                case 27: // Escape
                                        end = 1;
                                        break;
                                case 'z':
                                        printf("delaying 500ms\n");
                                        delay(500);
                                        break;
                                default:
                                        break;
                                }
                        }
                        else {
                                cleanup_and_exit(EXIT_SUCCESS);
                        }
                }

                if (mixer_handle && FD_ISSET (mixer_fd, &rfds))
                {
                        snd_mixer_callbacks_t callbacks = {
                                0, 0, 0, 0
                        };

                        snd_mixer_read (mixer_handle, &callbacks);
                }

                if (FD_ISSET (pcm_fd, &rfds))
                {
                        snd_pcm_channel_status_t status;
                        int     read = 0;

                        read = snd_pcm_plugin_read (pcm_handle, mSampleBfr1, bsize);
                        if (verbose)
                                printf ("bytes read = %d, bsize = %d \n", read, bsize);
                        if (read < bsize)
                        {
                                memset (&status, 0, sizeof (status));
                                status.channel = SND_PCM_CHANNEL_CAPTURE;
                                if (snd_pcm_plugin_status (pcm_handle, &status) < 0)
                                {
                                        fprintf (stderr, "Capture channel status error\n");
                                        cleanup_and_exit(EXIT_FAILURE);
                                }

                                if (status.status == SND_PCM_STATUS_READY ||
                                        status.status == SND_PCM_STATUS_OVERRUN)
                                {
                                        if (status.status == SND_PCM_STATUS_OVERRUN)
                                                fprintf(stderr, "overrun: capture channel\n");

                                        if (snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0)
                                        {
                                                fprintf (stderr, "Capture channel prepare error\n");
                                                cleanup_and_exit(EXIT_FAILURE);
                                        }
                                }
                                else if (status.status == SND_PCM_STATUS_ERROR)
                                {
                                        fprintf(stderr, "error: capture channel failure\n");
                                        cleanup_and_exit(EXIT_FAILURE);
                                }
                                else if (status.status == SND_PCM_STATUS_CHANGE)
                                {
                                        fprintf(stderr, "change: capture channel capability change\n");
                                        cleanup_and_exit(EXIT_FAILURE);
                                }
                                else if (status.status == SND_PCM_STATUS_PREEMPTED)
                                {
                                        fprintf(stderr, "error: capture channel preempted\n");
                                        cleanup_and_exit(EXIT_FAILURE);
                                }
                        } else {
                                fwrite (mSampleBfr1, 1, read, file1);
                                N += read;
                        }
                }
        }

        printf("Exiting...\n");

        /* Update wave header with actual length of audio captured */
        riff_hdr.wave.data.data_len = ENDIAN_LE32 (N);
        riff_hdr.wave_len = ENDIAN_LE32 (N + sizeof (riff_hdr) - 8);
        fseek(file1, 0, SEEK_SET);
        fwrite (&riff_hdr, 1, sizeof (riff_hdr), file1);

        snd_pcm_plugin_flush (pcm_handle, SND_PCM_CHANNEL_CAPTURE);
        cleanup();
        return(EXIT_SUCCESS);
}

#if defined(__QNXNTO__) && defined(__USESRCVERSION)
#include <sys/srcversion.h>
__SRCVERSION("$URL$ $Rev$")
#endif