1 /*
2  *  Library to query / set various sound mixer parameters.
3  *
4  * This code is based on setmixer program by Michal Jaegermann
5  *
6  * Copyright (c) 2000 Sergey Gribov <sergey@sergey.com>
7  * This is free software with ABSOLUTELY NO WARRANTY.
8  * You can redistribute and modify it freely, but please leave
9  * this message attached to this file.
10  *
11  * Subject to terms of GNU General Public License (www.gnu.org)
12  *
13  * Last update: $Date: 2002/04/30 00:48:21 $ by $Author: sergey $
14  * Revision: $Revision: 1.5 $
15  *
16  */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <sys/ioctl.h>
23 #include <sys/soundcard.h>
24 
25 #include "Mix.h"
26 
27 #define BUFSIZE 512
28 
29 const char * dname[] = SOUND_DEVICE_NAMES;
30 
31 static int devmask, stereod, recmask, mixer_fd = -1, init_flag = 0;
32 
33 static char dev_fname[BUFSIZE] = "";
34 
35 int
36 set_mixer_dev(char *fname) {
37 #ifdef DEBUG
38   fprintf(stderr, "set_mixer_dev(%s)\n", fname);
39 #endif
40   strncpy(dev_fname, fname, BUFSIZE-1);
41   return(0);
42 }
43 
44 int
45 open_mixer() {
46 #ifdef DEBUG
47   fprintf(stderr, "open_mixer()\n");
48 #endif
49   if (dev_fname[0] == '\0') {
50     strncpy(dev_fname, MIXER, BUFSIZE-1);
51   }
52   if ((mixer_fd = open(dev_fname, O_RDWR)) < 0) {
53     fprintf(stderr, "Error opening %s.", MIXER);
54     return(-1);
55   }
56   if (ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
57     perror("SOUND_MIXER_READ_DEVMASK");
58     return(-1);
59   }
60   if (ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &stereod) == -1) {
61     perror("SOUND_MIXER_READ_STEREODEVS");
62     return(-1);
63   }
64   if (ioctl(mixer_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
65 	  perror("SOUND_MIXER_READ_RECMASK");
66 	  return(-1);
67   }
68 
69   if (!devmask) {
70     fprintf(stderr, "No device found.");
71     return(-1);
72   }
73   return(0);
74 }
75 
76 int
77 close_mixer() {
78 #ifdef DEBUG
79   fprintf(stderr, "close_mixer()\n");
80 #endif
81   if (mixer_fd < 0) return 0;
82   close(mixer_fd);
83   init_flag = 0;
84   mixer_fd = -1;
85   return(0);
86 }
87 
88 /*
89  * Get parameter value
90  * Parameter:
91  *   cntrl - name of parameter
92  * Returns:
93  *   integer value, which will be constructed as follows:
94  *   lower byte (x & 0xff) - value of the left channel (or whole value)
95  *   next byte  (x & 0xff00) - value of the right channel
96  *   third byte (x & 0xff0000) - flags (if x & 0x10000 then 2 channels exist)
97  */
98 int
99 get_param_val(char *cntrl) {
100   int i, d, len, lcval, ret = 0;
101 
102 #ifdef DEBUG
103   fprintf(stderr, "get_param_val(%s)\n", cntrl);
104 #endif
105 
106   if (!init_flag) {
107     if (open_mixer()) {
108       return(-1);
109     }
110   }
111   len = strlen(cntrl);
112   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
113     d = (1 << i);
114     if ((0 == strncmp(dname[i], cntrl, len)) &&
115 	(0 != (devmask & d))) {
116       if (-1 == ioctl(mixer_fd, MIXER_READ(i), &lcval)) {
117 	perror("MIXER_READ");
118 	if (!init_flag)
119 	  close_mixer();
120 	return(-1);
121       }
122       else {
123 	ret = lcval & 0x7f;
124 	if (d & stereod) {
125 	  ret = ret | 0x10000;
126 	  ret = ret | (lcval & 0x7f00);
127 	  if (!init_flag)
128 	    close_mixer();
129 	  return(ret);
130 	}
131       }
132     }
133   }
134   if (!init_flag)
135     close_mixer();
136   return(-1);
137 }
138 
139 
140 char *
141 get_source()
142 {
143 	int j;
144 	unsigned int source = 0;
145 	if (!init_flag){
146 		if (open_mixer())
147 			return("");
148 	}
149 	if (-1 == ioctl(mixer_fd, SOUND_MIXER_READ_RECSRC, &source)){
150 		perror("MIXER_READ_RECSRC");
151 		if (!init_flag)
152 			close_mixer();
153 		return("");
154 	}
155 	if (!init_flag)
156 		close_mixer();
157 	source &= recmask;
158 	for (j = 0; source; source >>= 1, j++){
159 		if (source & 1)
160 			return((char *) dname[j]);
161 	}
162 	return("");
163 }
164 
165 int
166 set_source(char *cntrl)
167 {
168 	int i, d, len, ret = 0;
169 
170 #ifdef DEBUG
171 	fprintf(stderr, "set_recsrc(%s)\n", cntrl);
172 #endif
173 
174 	if (!init_flag) {
175 		if (open_mixer()) {
176 			return(-1);
177 		}
178 	}
179 	len = strlen(cntrl);
180 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
181 		d = (1 << i);
182 		if ((0 == strncmp(dname[i], cntrl, len)) &&
183 			(0 != (recmask & d))) {
184 			if (-1 == ioctl(mixer_fd, SOUND_MIXER_WRITE_RECSRC, &d)) {
185 				perror("MIXER_WRITE_RECSRC");
186 				if (!init_flag)
187 					close_mixer();
188 				return(-1);
189 			}
190 			else {
191 				if (!init_flag)
192 					close_mixer();
193 				return(0);
194 			}
195 		}
196 	}
197 	d = 0;
198 	if (-1 == ioctl(mixer_fd, SOUND_MIXER_WRITE_RECSRC, &d)) {
199 		perror("MIXER_WRITE_RECSRC");
200 		if (!init_flag)
201 			close_mixer();
202 		return(-1);
203 	}
204 	if (!init_flag)
205 		close_mixer();
206 	return(0);
207 }
208 
209 /*
210  * Set parameter value.
211  * Parameters:
212  *   cntrl - name of parameter
213  *   lcval - left channel value
214  *   rcval - right channel value
215  * Returns 0 if Ok, -1 if failed
216  */
217 int
218 set_param_val(char *cntrl, int lcval, int rcval) {
219   int len, i, d;
220 
221 #ifdef DEBUG
222   fprintf(stderr, "set_param_val(%s, %d, %d)\n", cntrl, lcval, rcval);
223 #endif
224 
225   if (!init_flag) {
226     if (open_mixer()) {
227       return(-1);
228     }
229   }
230   len = strlen(cntrl);
231   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
232     if (0 == strncmp(dname[i], cntrl, len)) {
233       d = (1 << i);
234       if (0 != (devmask & d)) {
235 	lcval = (lcval < 0 ? 0 : (lcval > 100 ? 100 : lcval));
236 	if (d & stereod) {
237 	  rcval = (rcval < 0 ? 0 : (rcval > 100 ? 100 : rcval));
238 	  lcval |= (rcval << 8);
239 	}
240 	if (-1 == ioctl(mixer_fd, MIXER_WRITE(i), &lcval)) {
241 	  perror("MIXER_WRITE");
242 	  if (!init_flag)
243 	    close_mixer();
244 	  return(-1);
245 	}
246       }
247       break;
248     }
249   }
250   if (!init_flag)
251     close_mixer();
252   return(0);
253 }
254 
255 int
256 init_mixer() {
257   if (open_mixer()) {
258     return(-1);
259   }
260   init_flag = 1;
261   return(0);
262 }
263 
264 int
265 get_params_num() {
266   return(SOUND_MIXER_NRDEVICES);
267 }
268 
269 char *
270 get_params_list() {
271   static char buf[BUFSIZE];
272   int i, l, len = 0;
273   buf[0] = '\0';
274   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
275     l = strlen(dname[i]);
276     if ((len >= (BUFSIZE - 2)) || ((len + l + 3) >= BUFSIZE)) {
277       buf[len] = '\0';
278       return(buf);
279     }
280     strcat(buf, dname[i]);
281     strcat(buf, " ");
282     len += l + 1;
283   }
284   buf[len] = '\0';
285   return(buf);
286 }
287 
288