1 /*
2  *   pcmplay.c
3  *
4  *   Oliver Fromme  <olli@fromme.com>
5  *
6  *   Copyright (C) 1997,1998,1999
7  *        Oliver Fromme.  All rights reserved.
8  *
9  *   Redistribution and use in source and binary forms, with or without
10  *   modification, are permitted provided that the following conditions
11  *   are met:
12  *   1. Redistributions of source code must retain the above copyright
13  *      notice, this list of conditions and the following disclaimer.
14  *   2. Redistributions in binary form must reproduce the above copyright
15  *      notice, this list of conditions and the following disclaimer in the
16  *      documentation and/or other materials provided with the distribution.
17  *   3. Neither the name of the author nor the names of any co-contributors
18  *      may be used to endorse or promote products derived from this software
19  *      without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY OLIVER FROMME AND CONTRIBUTORS ``AS IS'' AND
22  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  *   ARE DISCLAIMED.  IN NO EVENT SHALL OLIVER FROMME OR CONTRIBUTORS BE LIABLE
25  *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  *   SUCH DAMAGE.
32  *
33  *   @(#)$Id: pcmplay.c,v 1.4 1999/01/01 23:31:55 olli Exp $
34  */
35 
36 static const char cvsid[]
37     = "@(#)$Id: pcmplay.c,v 1.4 1999/01/01 23:31:55 olli Exp $";
38 
39 #include <stdio.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <sys/ioctl.h>
44 #include <sys/types.h>
45 #include <sys/uio.h>
46 #include <unistd.h>
47 #include <sys/soundcard.h>
48 
49 #include "utils.h"
50 #include "getlopt.h"
51 
52 char *audevice = "/dev/dsp";
53 int buffersize = 32;
54 int dsp_samplesize = 16;
55 int dsp_channels = 2;
56 int dsp_speed = 44100;
57 int dsp_unsigned = FALSE;
58 int dsp_network = FALSE;
59 int mix_gain = -1;
60 
61 int
usage(char * notused)62 usage (char *notused)
63 {
64 	fprintf (stderr, "Usage:  %s [options]\n", me);
65 	fprintf (stderr, "Options [defaults] (remarks):\n");
66 	fprintf (stderr, "   -d audio_device      [%s]\n", audevice);
67 	fprintf (stderr, "   -b buffer_size       [%d]   (in Kbytes)\n", buffersize);
68 	fprintf (stderr, "   -s bits_per_sample   [%d]   (must be 8 or 16)\n", dsp_samplesize);
69 	fprintf (stderr, "   -f frequency         [%d]\n", dsp_speed);
70 	fprintf (stderr, "   -c channels          [%d]   (must be 1 or 2)\n", dsp_channels);
71 	fprintf (stderr, "   -g gain              [don't change]   (0 - 255)\n");
72 	fprintf (stderr, "   -u                   (data is unsigned; default is signed)\n");
73 	fprintf (stderr, "   -n                   (data in network byte order; default is intel b.o.)\n");
74 	exit (1);
75 	return 0; /* make compiler happy */
76 }
77 
78 topt opts[] = {
79 	{'d', "device",    GLO_CHAR, 0,     &audevice,       0},
80 	{'b', "buffer",    GLO_NUM,  0,     &buffersize,     0},
81 	{'s', "bits",      GLO_NUM,  0,     &dsp_samplesize, 0},
82 	{'f', "frequency", GLO_NUM,  0,     &dsp_speed,      0},
83 	{'c', "channels",  GLO_NUM,  0,     &dsp_channels,   0},
84 	{'g', "gain",      GLO_NUM,  0,     &mix_gain,       0},
85 	{'u', "unsigned",  0,        0,     &dsp_unsigned,   TRUE},
86 	{'n', "network",   0,        0,     &dsp_network,    TRUE},
87 	{'h', "help",      0,        usage, 0,               0},
88 	{0, NULL, 0, 0, 0, 0}
89 };
90 
audio_open()91 int audio_open ()
92 {
93 	int fmts;
94 	int stereo = (dsp_channels == 2 ? TRUE : FALSE);
95 	int fd;
96 
97 	if (dsp_samplesize == 8)
98 		if (dsp_unsigned)
99 			fmts = AFMT_U8;
100 		else
101 			fmts = AFMT_S8;
102 	else
103 		if (dsp_network)
104 			if (dsp_unsigned)
105 				fmts = AFMT_U16_BE;
106 			else
107 				fmts = AFMT_S16_BE;
108 		else
109 			if (dsp_unsigned)
110 				fmts = AFMT_U16_LE;
111 			else
112 				fmts = AFMT_S16_LE;
113 	if ((fd = open(audevice, O_WRONLY)) < 0)
114 		return (-1);
115 	ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &dsp_samplesize);
116 	ioctl (fd, SNDCTL_DSP_STEREO, &stereo);
117 	ioctl (fd, SNDCTL_DSP_SPEED, &dsp_speed);
118 	ioctl (fd, SNDCTL_DSP_SETFMT, &fmts);
119 	if (mix_gain >= 0) {
120 		int e, mask;
121 		e = ioctl(fd, SOUND_MIXER_READ_DEVMASK, &mask);
122 		if (e < 0)
123 			fprintf (stderr, "audio/gain: Can't get audio device features list.\n");
124 		else if (mask & SOUND_MASK_PCM) {
125 			int gain = (mix_gain << 8) | (mix_gain);
126 			e = ioctl(fd, SOUND_MIXER_WRITE_PCM, &gain);
127 		}
128 		else if (!(mask & SOUND_MASK_VOLUME))
129 			fprintf (stderr, "audio/gain: setable Volume/PCM-Level not supported by your audio device: %#04x\n", mask);
130 		else {
131 			int gain = (mix_gain << 8) | (mix_gain);
132 			e = ioctl(fd, SOUND_MIXER_WRITE_VOLUME, &gain);
133 		}
134 	}
135 	return (fd);
136 }
137 
audio_play(int fd,char * buf,int len)138 int audio_play (int fd, char *buf, int len)
139 {
140 	return (write(fd, buf, len));
141 }
142 
audio_close(int fd)143 int audio_close (int fd)
144 {
145   return (close (fd));
146 }
147 
main(int argc,char * argv[])148 int main (int argc, char *argv[])
149 {
150 	int infd = 0;
151 	int outfd;
152 	int result, bufbytes, numbytes;
153 	char *buf;
154 
155 	utils_init (argv[0]);
156 	while ((result = getlopt(argc, argv, opts)))
157 		switch (result) {
158 			case GLO_UNKNOWN:
159 				fprintf (stderr, "%s: Unknown option \"%s\".\n",
160 					me, loptarg);
161 				exit (1);
162 			case GLO_NOARG:
163 				fprintf (stderr, "%s: Missing argument for option \"%s\".\n",
164 					me, loptarg);
165 				exit (1);
166 		}
167 	if (loptind >= argc)
168 		usage (NULL);
169 
170 	bufbytes = buffersize * 1024;
171 	if (!(buf = malloc(bufbytes)))
172 		die ("malloc()");
173 	if ((outfd = audio_open()) < 0)
174 		die (audevice);
175 	do {
176 		if (!strcmp(argv[loptind], "-"))
177 			infd = 0;
178 		else if ((infd = open(argv[loptind], O_RDONLY, 0)) < 0)
179 			die (argv[loptind]);
180 		do {
181 			numbytes = read(infd, buf, bufbytes);
182 			if (numbytes > 0)
183 				audio_play (outfd, buf, numbytes);
184 		} while (numbytes > 0);
185 		if (infd)
186 			close (infd);
187 	} while (++loptind < argc);
188 	audio_close (outfd);
189 	exit (0);
190 }
191 
192 /* EOF */
193