Middleware, development tools, realtime operating system
software and services for superior embedded design


Home
QNX Community Resources
QNX Documentation Library
waverec.c example

waverec.c example

QNX Software Systems
Developer Resources
Blogs
Board support packages
Foundry27 projects
Forums
Hardware support listing
Online video tutorials
Product documentation
Technical Articles

Appendix: waverec.c example

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

#include <errno.h>
#include <fcntl.h>
#include <gulliver.h>
#include <stdio.h>
#include <stdlib.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 <sys/asoundlib.h>
/* *INDENT-OFF* */
struct
{
    char    riff_id[4];
    char    wave_len[4];
    struct
    {
        char    fmt_id[8];
        char    fmt_len[4];
        struct
        {
            char    format_tag[2];
            char    voices[2];
            char    rate[4];
            char    char_per_sec[4];
            char    block_align[2];
            char    bits_per_sample[2];
        }
        fmt;
        struct
        {
            char    data_id[4];
            char    data_len[4];
        }
        data;
    }
    wave;
}
riff_hdr =
{
    {'R', 'I', 'F', 'F' },
    {sizeof (riff_hdr.wave), 0, 0, 0 },
    {
        {'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' },
        {sizeof (riff_hdr.wave.fmt), 0, 0, 0 },
        {
            {1, 0 }, 
            {0, 0 },
            {0, 0, 0, 0 },
            {0, 0, 0, 0 },
            {0, 0 },
            {0, 0 }
        },
        {
            {'d', 'a', 't', 'a' },
            {0, 0, 0, 0 }
        }
    }
};
/* *INDENT-ON* */


int
err (char *msg)
{
    perror (msg);
    return -1;
}


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 &= ~(ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);
    termios_p.c_oflag &= ~(OPOST);
    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 |= (ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);
    termios_p.c_oflag |= (OPOST);
    return (tcsetattr (fd, TCSAFLUSH, &termios_p));
}


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

Options:
    -8                use 8 bit mode (16 bit default)
    -a[card#:]<dev#>  the card & device number to record from
    -m                record in mono (stereo default)
    -r <rate>         record at rate (44100 default | 48000 44100 22050 11025)
    -t <sec>          seconds to record (5 seconds default)
#endif
/* *INDENT-ON* */
//*****************************************************************************


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

    snd_pcm_t *pcm_handle;
    FILE   *file1;
    int     mSamples;
    int     mSampleRate;
    int     mSampleChannels;
    int     mSampleBits;
    int     mSampleTime;
    char   *mSampleBfr1;

    int     rtn;

    snd_pcm_channel_info_t pi;
    snd_mixer_t *mixer_handle;
    snd_mixer_group_t group;
    snd_pcm_channel_params_t pp;
    snd_pcm_channel_setup_t setup;
    int     bsize, n, N = 0, c;

    fd_set  rfds;

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

    while ((c = getopt (argc, argv, "8a:mr:t:")) != EOF)
    {
        switch (c)
        {
        case '8':
            mSampleBits = 8;
            break;
        case 'a':
            if (strchr (optarg, ':'))
            {
                card = atoi (optarg);
                dev = atoi (strchr (optarg, ':') + 1);
            }
            else
                dev = atoi (optarg);
            printf ("Using card %d device %d \n", card, dev);
            break;
        case 'm':
            mSampleChannels = 1;
            break;
        case 'r':
            mSampleRate = atoi (optarg);
            break;
        case 't':
            mSampleTime = atoi (optarg);
            break;
        default:
            return 1;
        }
    }

    setvbuf (stdin, NULL, _IONBF, 0);
    if (card == -1)
    {
        if ((rtn = snd_pcm_open_preferred (&pcm_handle, &card, &dev, SND_PCM_OPEN_CAPTURE)) < 0)
            return err ("device open");
    }
    else
    {
        if ((rtn = snd_pcm_open (&pcm_handle, card, dev, SND_PCM_OPEN_CAPTURE)) < 0)
            return err ("device open");
    }

    if (argc < 2)
        return err ("no file specified");

    if ((file1 = fopen (argv[optind], "w")) == 0)
        return err ("file open #1");

    mSamples = mSampleRate * mSampleChannels * mSampleBits / 8 * mSampleTime;

    *(short *) riff_hdr.wave.fmt.voices = ENDIAN_LE16 (mSampleChannels);
    *(long *) riff_hdr.wave.fmt.rate = ENDIAN_LE32 (mSampleRate);
    *(long *) riff_hdr.wave.fmt.char_per_sec =
        ENDIAN_LE32 (mSampleRate * mSampleChannels * mSampleBits / 8);
    *(short *) riff_hdr.wave.fmt.block_align = ENDIAN_LE16 (mSampleChannels * mSampleBits / 8);
    *(short *) riff_hdr.wave.fmt.bits_per_sample = ENDIAN_LE16 (mSampleBits);
    *(long *) riff_hdr.wave.data.data_len = ENDIAN_LE32 (mSamples);
    *(long *) 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);

    /* disabling mmap is not actually required in this example but it is included to 
     * demonstrate how it is used when it is required.
     */
    if ((rtn = snd_pcm_plugin_set_disable (pcm_handle, PLUGIN_DISABLE_MMAP)) < 0)
    {
        fprintf (stderr, "snd_pcm_plugin_set_disable failed: %s\n", snd_strerror (rtn));
        return -1;
    }

    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));
        return -1;
    }

    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.buf.block.frag_size = pi.max_fragment_size;
    pp.buf.block.frags_max = -1;
    pp.buf.block.frags_min = 1;

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

    if (mSampleBits == 8)
        pp.format.format = SND_PCM_SFMT_U8;
    else
        pp.format.format = SND_PCM_SFMT_S16_LE;

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

    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));


    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));
        return -1;
    }
    printf ("Format %s \n", snd_pcm_get_format_name (setup.format.format));
    printf ("Frag Size %d \n", setup.buf.block.frag_size);
    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, card, setup.mixer_device)) < 0)
    {
        fprintf (stderr, "snd_mixer_open failed: %s\n", snd_strerror (rtn));
        return -1;
    }

    mSampleBfr1 = malloc (bsize);
    FD_ZERO (&rfds);
    n = 1;
    while (N < mSamples && n > 0)
    {
        FD_SET (STDIN_FILENO, &rfds);
        FD_SET (snd_mixer_file_descriptor (mixer_handle), &rfds);
        FD_SET (snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_CAPTURE), &rfds);

        rtn = max (snd_mixer_file_descriptor (mixer_handle),
            snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_CAPTURE));

        if (select (rtn + 1, &rfds, NULL, NULL, NULL) == -1)
            return err ("select");


        if (FD_ISSET (STDIN_FILENO, &rfds))
        {
            dev_raw (fileno (stdin));
            c = getc (stdin);
            dev_unraw (fileno (stdin));
            if (c != EOF)
            {
                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;
                    }
                    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));

                    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));
                }
            }
            else
                exit (0);
        }

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

            snd_mixer_read (mixer_handle, &callbacks);
        }

        if (FD_ISSET (snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_CAPTURE), &rfds))
        {
            snd_pcm_channel_status_t status;
            int     read = 0;

            read = snd_pcm_plugin_read (pcm_handle, mSampleBfr1, bsize);
            if (read < n)
            {
                memset (&status, 0, sizeof (status));
                status.channel = SND_PCM_CHANNEL_CAPTURE;
                if (snd_pcm_plugin_status (pcm_handle, &status) < 0)
                {
                    fprintf (stderr, "overrun: capture channel status error\n");
                    exit (1);
                }

                if (status.status == SND_PCM_STATUS_READY ||
                    status.status == SND_PCM_STATUS_OVERRUN)
                {
                    if (snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_CAPTURE) < 0)
                    {
                        fprintf (stderr, "overrun: capture channel prepare error\n");
                        exit (1);
                    }
                }
            }
            fwrite (mSampleBfr1, 1, read, file1);
            N += read;
        }
    }

    n = snd_pcm_plugin_flush (pcm_handle, SND_PCM_CHANNEL_CAPTURE);

    rtn = snd_mixer_close (mixer_handle);
    rtn = snd_pcm_close (pcm_handle);
    fclose (file1);
    return (0);
}