This is a sample application that plays back 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 <sys/slogcodes.h> #include <ctype.h> #include <limits.h> #include <sys/asoundlib.h> const char *kRiffId = "RIFF"; const char *kWaveId = "WAVE"; typedef struct { char tag[4]; long length; } RiffTag; typedef struct { char Riff[4]; long Size; char Wave[4]; } RiffHdr; typedef struct { short FormatTag; short Channels; long SamplesPerSec; long AvgBytesPerSec; short BlockAlign; short BitsPerSample; } WaveHdr; int err (char *msg) { perror (msg); return -1; } int FindTag (FILE * fp, const char *tag) { int retVal; RiffTag tagBfr = { "", 0 }; retVal = 0; // Keep reading until we find the tag or hit the EOF. while (fread ((unsigned char *) &tagBfr, sizeof (tagBfr), 1, fp)) { // If this is our tag, set the length and break. if (strncmp (tag, tagBfr.tag, sizeof tagBfr.tag) == 0) { retVal = ENDIAN_LE32 (tagBfr.length); break; } // Skip ahead the specified number of bytes in the stream fseek (fp, tagBfr.length, SEEK_CUR); } // Return the result of our operation return (retVal); } int CheckHdr (FILE * fp) { RiffHdr riffHdr = { "", 0 }; // Read the header and, if successful, play the file // file or WAVE file. if (fread ((unsigned char *) &riffHdr, sizeof (RiffHdr), 1, fp) == 0) return 0; if (strncmp (riffHdr.Riff, kRiffId, strlen (kRiffId)) || strncmp (riffHdr.Wave, kWaveId, strlen (kWaveId))) return -1; return 0; } 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: -a[card#:]<dev#> the card & device number to play out on -f<frag_size> requested fragment size -v verbose -c<args>[,args ..] voice matrix configuration -n<num_frags> requested number of fragments 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; WaveHdr wavHdr1; int mSamples; int mSampleRate; int mSampleChannels; int mSampleBits; 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; fd_set rfds, wfds; uint32_t voice_mask[] = { 0, 0, 0, 0 }; snd_pcm_voice_conversion_t voice_conversion; int voice_override = 0; int num_frags = -1; 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 }; while ((c = getopt (argc, argv, "a:f:vc:n:")) != EOF) { switch (c) { 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 '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; case 'n': num_frags = atoi (optarg) - 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_PLAYBACK)) < 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_PLAYBACK)) < 0) return err ("device open"); } else { if ((rtn = snd_pcm_open (&pcm_handle, card, dev, SND_PCM_OPEN_PLAYBACK)) < 0) return err ("device open"); } } if (argc < 2) return err ("no file specified"); if ((file1 = fopen (argv[optind], "r")) == 0) return err ("file open #1"); if (CheckHdr (file1) == -1) return err ("CheckHdr #1"); mSamples = FindTag (file1, "fmt "); fread (&wavHdr1, sizeof (wavHdr1), 1, file1); fseek (file1, (mSamples - sizeof (WaveHdr)), SEEK_CUR); mSampleRate = ENDIAN_LE32 (wavHdr1.SamplesPerSec); mSampleChannels = ENDIAN_LE16 (wavHdr1.Channels); mSampleBits = ENDIAN_LE16 (wavHdr1.BitsPerSample); 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_PLAYBACK; 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_PLAYBACK; pp.start_mode = SND_PCM_START_FULL; 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 = num_frags; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.rate = mSampleRate; pp.format.voices = mSampleChannels; if (ENDIAN_LE16 (wavHdr1.FormatTag) == 6) pp.format.format = SND_PCM_SFMT_A_LAW; else if (ENDIAN_LE16 (wavHdr1.FormatTag) == 7) pp.format.format = SND_PCM_SFMT_MU_LAW; else if (mSampleBits == 8) pp.format.format = SND_PCM_SFMT_U8; else if (mSampleBits == 24) pp.format.format = SND_PCM_SFMT_S24; else pp.format.format = SND_PCM_SFMT_S16_LE; strcpy (pp.sw_mixer_subchn_name, "Wave playback channel"); 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_PLAYBACK)) < 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_PLAYBACK, &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_PLAYBACK, &voice_conversion); } memset (&setup, 0, sizeof (setup)); memset (&group, 0, sizeof (group)); setup.channel = SND_PCM_CHANNEL_PLAYBACK; 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 ("Total Frags %d \n", setup.buf.block.frags); printf ("Rate %d \n", setup.format.rate); printf ("Voices %d \n", setup.format.voices); bsize = setup.buf.block.frag_size; if (group.gid.name[0] == 0) { printf ("Mixer Pcm Group [%s] Not Set \n", group.gid.name); exit (-1); } 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; } mSamples = FindTag (file1, "data"); mSampleBfr1 = malloc (bsize); FD_ZERO (&rfds); FD_ZERO (&wfds); n = 1; while (N < mSamples && n > 0) { if (tcgetpgrp (0) == getpid ()) 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_PLAYBACK), &wfds); rtn = max (snd_mixer_file_descriptor (mixer_handle), snd_pcm_file_descriptor (pcm_handle, SND_PCM_CHANNEL_PLAYBACK)); if (select (rtn + 1, &rfds, &wfds, NULL, NULL) == -1) return err ("select"); if (FD_ISSET (STDIN_FILENO, &rfds)) { if ((rtn = snd_mixer_group_read (mixer_handle, &group)) < 0) fprintf (stderr, "snd_mixer_group_read failed: %s\n", snd_strerror (rtn)); dev_raw (fileno (stdin)); c = getc (stdin); dev_unraw (fileno (stdin)); if (c != EOF) { switch (c) { case 'q': if (group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT) group.volume.names.front_left += 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_LEFT) group.volume.names.rear_left += 10; if (group.channels & SND_MIXER_CHN_MASK_WOOFER) group.volume.names.woofer += 10; break; case 'a': if (group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT) group.volume.names.front_left -= 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_LEFT) group.volume.names.rear_left -= 10; if (group.channels & SND_MIXER_CHN_MASK_WOOFER) group.volume.names.woofer -= 10; break; case 'w': if (group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT) group.volume.names.front_left += 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_LEFT) group.volume.names.rear_left += 10; if (group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER) group.volume.names.front_center += 10; if (group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT) group.volume.names.front_right += 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT) group.volume.names.rear_right += 10; if (group.channels & SND_MIXER_CHN_MASK_WOOFER) group.volume.names.woofer += 10; break; case 's': if (group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT) group.volume.names.front_left -= 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_LEFT) group.volume.names.rear_left -= 10; if (group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER) group.volume.names.front_center -= 10; if (group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT) group.volume.names.front_right -= 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT) group.volume.names.rear_right -= 10; if (group.channels & SND_MIXER_CHN_MASK_WOOFER) group.volume.names.woofer -= 10; break; case 'e': if (group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT) group.volume.names.front_right += 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT) group.volume.names.rear_right += 10; if (group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER) group.volume.names.front_center += 10; break; case 'd': if (group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT) group.volume.names.front_right -= 10; if (group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT) group.volume.names.rear_right -= 10; if (group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER) group.volume.names.front_center -= 10; break; } if (group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT) { 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.channels & SND_MIXER_CHN_MASK_REAR_LEFT) { if (group.volume.names.rear_left > group.max) group.volume.names.rear_left = group.max; if (group.volume.names.rear_left < group.min) group.volume.names.rear_left = group.min; } if (group.channels & SND_MIXER_CHN_MASK_FRONT_CENTER) { if (group.volume.names.front_center > group.max) group.volume.names.front_center = group.max; if (group.volume.names.front_center < group.min) group.volume.names.front_center = group.min; } if (group.channels & SND_MIXER_CHN_MASK_FRONT_RIGHT) { 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 (group.channels & SND_MIXER_CHN_MASK_REAR_RIGHT) { if (group.volume.names.rear_right > group.max) group.volume.names.rear_right = group.max; if (group.volume.names.rear_right < group.min) group.volume.names.rear_right = group.min; } if (group.channels & SND_MIXER_CHN_MASK_WOOFER) { if (group.volume.names.woofer > group.max) group.volume.names.woofer = group.max; if (group.volume.names.woofer < group.min) group.volume.names.woofer = group.min; } if ((rtn = snd_mixer_group_write (mixer_handle, &group)) < 0) fprintf (stderr, "snd_mixer_group_write failed: %s\n", snd_strerror (rtn)); } else exit (0); if (group.channels & SND_MIXER_CHN_MASK_FRONT_LEFT) { 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 if (group.channels & SND_MIXER_CHN_MASK_REAR_LEFT) { printf ("Volume Now at %d:%d \n", 100 * (group.volume.names.rear_left - group.min) / (group.max - group.min), 100 * (group.volume.names.rear_right - group.min) / (group.max - group.min)); } else if (group.channels & SND_MIXER_CHN_MASK_WOOFER) { printf ("Volume Now at %d:%d \n", 100 * (group.volume.names.woofer - group.min) / (group.max - group.min), 100 * (group.volume.names.front_center - group.min) / (group.max - group.min)); } 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)); } } 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_PLAYBACK), &wfds)) { snd_pcm_channel_status_t status; int written = 0; if ((n = fread (mSampleBfr1, 1, min (mSamples - N, bsize), file1)) <= 0) continue; written = snd_pcm_plugin_write (pcm_handle, mSampleBfr1, n); if (verbose) printf ("bytes written = %d \n", written); if (written < n) { memset (&status, 0, sizeof (status)); status.channel = SND_PCM_CHANNEL_PLAYBACK; if (snd_pcm_plugin_status (pcm_handle, &status) < 0) { fprintf (stderr, "underrun: playback channel status error\n"); exit (1); } if (status.status == SND_PCM_STATUS_READY || status.status == SND_PCM_STATUS_UNDERRUN) { if (snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_PLAYBACK) < 0) { fprintf (stderr, "underrun: playback channel prepare error\n"); exit (1); } } if (written < 0) written = 0; written += snd_pcm_plugin_write (pcm_handle, mSampleBfr1 + written, n - written); } N += written; } } n = snd_pcm_plugin_flush (pcm_handle, SND_PCM_CHANNEL_PLAYBACK); rtn = snd_mixer_close (mixer_handle); rtn = snd_pcm_close (pcm_handle); fclose (file1); return (0); }