This is a sample application that captures (i.e. records) audio data:
/*
* $QNXLicenseC:
* Copyright 2007, 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 <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>
/* *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)
-f <frag_size> requested fragment size
-v verbosity
-c <args>[,args ...] voice matrix configuration
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* */
//*****************************************************************************
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 fragsize = -1;
int verbose = 0;
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;
uint32_t voice_mask[] = { 0, 0, 0, 0 };
snd_pcm_voice_conversion_t voice_conversion;
int voice_override = 0;
char *sub_opts, *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 };
fd_set rfds;
mSampleRate = 44100;
mSampleChannels = 2;
mSampleBits = 16;
mSampleTime = 5;
while ((c = getopt (argc, argv, "8a:f:mr:t:vc:")) != EOF)
{
switch (c)
{
case '8':
mSampleBits = 8;
break;
case 'a':
if (strchr (optarg, ':'))
{
card = atoi (optarg);
dev = atoi (strchr (optarg, ':') + 1);
}
else if (isalpha (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 'm':
mSampleChannels = 1;
break;
case 'r':
mSampleRate = atoi (optarg);
break;
case 't':
mSampleTime = atoi (optarg);
break;
case 'v':
verbose = 1;
break;
case 'c':
sub_opts = strdup (optarg);
while (*sub_opts != '\0')
{
switch (getsubopt (&sub_opts, dev_opts, &value))
{
case CHN1:
voice_mask[0] = strtoul (value, NULL, 0);
break;
case CHN2:
voice_mask[1] = strtoul (value, NULL, 0);
break;
case CHN3:
voice_mask[2] = strtoul (value, NULL, 0);
break;
case CHN4:
voice_mask[3] = strtoul (value, NULL, 0);
break;
default:
break;
}
}
voice_override = 1;
break;
default:
return 1;
}
}
setvbuf (stdin, NULL, _IONBF, 0);
if (name[0] != '\0')
{
snd_pcm_info_t info;
if ((rtn = snd_pcm_open_name (&pcm_handle, name, SND_PCM_OPEN_CAPTURE)) < 0)
{
return err ("open_name");
}
rtn = snd_pcm_info (pcm_handle, &info);
card = info.card;
}
else
{
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;
if (fragsize != -1)
pp.buf.block.frag_size = fragsize;
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));
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));
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 (verbose)
printf ("bytes read = %d \n", read);
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);
}