1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1989-2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * This file contains routines to read and write the audio device state.
29 */
30
31 #include <errno.h>
32 #include <stropts.h>
33 #include <sys/types.h>
34 #include <sys/file.h>
35 #include <sys/stat.h>
36 #include <sys/ioctl.h>
37
38 #include <libaudio_impl.h>
39 #include <audio_errno.h>
40 #include <audio_hdr.h>
41 #include <audio_device.h>
42
43
44 /*
45 * Get device information structure.
46 */
47 int
audio_getinfo(int fd,Audio_info * ip)48 audio_getinfo(int fd, Audio_info *ip)
49 {
50 if (ioctl(fd, AUDIO_GETINFO, (char *)ip) < 0) {
51 return (AUDIO_UNIXERROR);
52 } else {
53 return (AUDIO_SUCCESS);
54 }
55 }
56
57 /*
58 * Set device information structure.
59 * The calling routine should use AUDIO_INITINFO prior to setting new values.
60 */
61 int
audio_setinfo(int fd,Audio_info * ip)62 audio_setinfo(int fd, Audio_info *ip)
63 {
64 if (ioctl(fd, AUDIO_SETINFO, (char *)ip) < 0) {
65 return (AUDIO_UNIXERROR);
66 } else {
67 return (AUDIO_SUCCESS);
68 }
69 }
70
71 /*
72 * Return an Audio_hdr corresponding to the encoding configuration
73 * of the audio device on 'fd'.
74 */
75 int
audio__setplayhdr(int fd,Audio_hdr * hdrp,unsigned int which)76 audio__setplayhdr(int fd, Audio_hdr *hdrp, unsigned int which)
77 {
78 Audio_hdr thdr;
79 Audio_info info;
80 struct audio_prinfo *prinfo;
81 int err;
82
83 if (which & AUDIO__PLAY)
84 prinfo = &info.play;
85 else if (which & AUDIO__RECORD)
86 prinfo = &info.record;
87 else
88 return (AUDIO_ERR_BADARG);
89
90 if (which & AUDIO__SET) {
91 thdr = *hdrp; /* save original hdr */
92 AUDIO_INITINFO(&info);
93 prinfo->sample_rate = hdrp->sample_rate;
94 prinfo->channels = hdrp->channels;
95 prinfo->encoding = hdrp->encoding;
96 prinfo->precision = hdrp->bytes_per_unit * 8;
97 err = audio_setinfo(fd, &info);
98 } else {
99 err = audio_getinfo(fd, &info);
100 }
101
102 /* Decode back into the header structure */
103 /* since the I_SMSG is set, upon completion of updating */
104 /* the format, the driver sends the msg so the */
105 /* system call is interrupted. For now, just ignore this */
106 if ((err == AUDIO_SUCCESS) || (errno == EINTR)) {
107 hdrp->sample_rate = prinfo->sample_rate;
108 hdrp->channels = prinfo->channels;
109 hdrp->data_size = AUDIO_UNKNOWN_SIZE;
110 hdrp->encoding = prinfo->encoding;
111 switch (hdrp->encoding) {
112 case AUDIO_ENCODING_ULAW:
113 case AUDIO_ENCODING_ALAW:
114 case AUDIO_ENCODING_LINEAR:
115 case AUDIO_ENCODING_LINEAR8:
116 case AUDIO_ENCODING_FLOAT:
117 hdrp->bytes_per_unit = prinfo->precision / 8;
118 hdrp->samples_per_unit = 1;
119 break;
120 default:
121 return (AUDIO_ERR_ENCODING);
122 }
123 if (which & AUDIO__SET) {
124 /* Check to see if *all* changes took effect */
125 if (audio_cmp_hdr(hdrp, &thdr) != 0)
126 return (AUDIO_ERR_NOEFFECT);
127 }
128 }
129 return (err);
130 }
131
132
133 /*
134 * Attempt to configure the audio device to match a particular encoding.
135 */
136
137 /*
138 * Set and/or set individual state values.
139 * This routine is generally invoked by using the audio_set_*()
140 * and audio_get_*() macros.
141 * The 'valp' argument is always a pointer to an unsigned int.
142 * Conversions to/from (unsigned char) flags are taken care of.
143 */
144 int
audio__setval(int fd,unsigned int * valp,unsigned int which)145 audio__setval(int fd, unsigned int *valp, unsigned int which)
146 {
147 Audio_info info;
148 struct audio_prinfo *prinfo;
149 int err;
150 unsigned *up;
151 unsigned char *cp;
152
153 /* Set a pointer to the value of interest */
154 if (which & AUDIO__PLAY)
155 prinfo = &info.play;
156 else if (which & AUDIO__RECORD)
157 prinfo = &info.record;
158 else if ((which & AUDIO__SETVAL_MASK) != AUDIO__MONGAIN)
159 return (AUDIO_ERR_BADARG);
160
161 up = NULL;
162 switch (which & AUDIO__SETVAL_MASK) {
163 case AUDIO__PORT:
164 up = &prinfo->port; break;
165 case AUDIO__SAMPLES:
166 up = &prinfo->samples; break;
167 case AUDIO__ERROR:
168 cp = &prinfo->error; break;
169 case AUDIO__EOF:
170 up = &prinfo->eof; break;
171 case AUDIO__OPEN:
172 cp = &prinfo->open; break;
173 case AUDIO__ACTIVE:
174 cp = &prinfo->active; break;
175 case AUDIO__WAITING:
176 cp = &prinfo->waiting; break;
177 case AUDIO__GAIN:
178 up = &prinfo->gain; break;
179 case AUDIO__MONGAIN:
180 up = &info.monitor_gain; break;
181 case AUDIO__BALANCE:
182 cp = &prinfo->balance; break;
183 default:
184 return (AUDIO_ERR_BADARG);
185 }
186
187 if (which & AUDIO__SET) {
188 /* Init so that only the value of interest is changed */
189 AUDIO_INITINFO(&info);
190 if (up != NULL) {
191 *up = *valp;
192 } else {
193 *cp = (unsigned char) *valp;
194 }
195 err = audio_setinfo(fd, &info);
196 } else {
197 err = audio_getinfo(fd, &info);
198 }
199 if (err == AUDIO_SUCCESS) {
200 if (up != NULL)
201 *valp = *up;
202 else
203 *valp = (unsigned)*cp;
204 }
205 return (err);
206 }
207
208 /*
209 * Get/set gain value.
210 * NOTE: legal values are floating-point double 0. - 1.
211 */
212 int
audio__setgain(int fd,double * valp,unsigned int which)213 audio__setgain(int fd, double *valp, unsigned int which)
214 {
215 int err;
216 unsigned x;
217
218 if (which & AUDIO__SET) {
219 if ((*valp < 0.) || (*valp > 1.))
220 return (AUDIO_ERR_BADARG);
221
222 /* Map value into legal range */
223 x = ((unsigned)(*valp * (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) +
224 AUDIO_MIN_GAIN;
225 }
226
227 /* Get or set the new value */
228 err = audio__setval(fd, &x, which);
229 if (err == AUDIO_SUCCESS) {
230 /* Map value back to double */
231 *valp = ((double)(x - AUDIO_MIN_GAIN) /
232 (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
233 }
234 return (err);
235 }
236
237 /*
238 * Set Pause/resume flags.
239 * Can set play and record individually or together.
240 */
241 int
audio__setpause(int fd,unsigned int which)242 audio__setpause(int fd, unsigned int which)
243 {
244 Audio_info info;
245 int err;
246 unsigned char x;
247
248 AUDIO_INITINFO(&info);
249
250 if ((which & AUDIO__SETVAL_MASK) == AUDIO__PAUSE) {
251 x = TRUE;
252 } else if ((which & AUDIO__SETVAL_MASK) == AUDIO__RESUME) {
253 x = FALSE;
254 } else {
255 return (AUDIO_ERR_BADARG);
256 }
257
258 if (which & AUDIO__PLAY) {
259 info.play.pause = x;
260 }
261 if (which & AUDIO__RECORD) {
262 info.record.pause = x;
263 }
264
265 /* Set the new value */
266 err = audio_setinfo(fd, &info);
267
268 /* Check to see if this took effect */
269 if (err == AUDIO_SUCCESS) {
270 if (((which & AUDIO__PLAY) && (info.play.pause != x)) ||
271 ((which & AUDIO__RECORD) && (info.record.pause != x)))
272 return (AUDIO_ERR_NOEFFECT);
273 }
274 return (err);
275 }
276
277
278 /*
279 * Flush play and/or record buffers.
280 */
281 int
audio__flush(int fd,unsigned int which)282 audio__flush(int fd, unsigned int which)
283 {
284 int flag;
285
286 flag = (which & AUDIO__PLAY) ? FLUSHW : 0;
287 flag |= (which & AUDIO__RECORD) ? FLUSHR : 0;
288
289 return ((ioctl(fd, I_FLUSH, flag) < 0) ?
290 AUDIO_UNIXERROR : AUDIO_SUCCESS);
291 }
292
293
294 /*
295 * Wait synchronously for output buffers to finish playing.
296 * If 'sig' is TRUE, signals may interrupt the drain.
297 */
298 int
audio_drain(int fd,int sig)299 audio_drain(int fd, int sig)
300 {
301 while (ioctl(fd, AUDIO_DRAIN, 0) < 0) {
302 if (errno != EINTR) {
303 return (AUDIO_UNIXERROR);
304 }
305
306 if (sig) {
307 return (AUDIO_ERR_INTERRUPTED);
308 }
309 }
310 return (AUDIO_SUCCESS);
311 }
312
313 /*
314 * Write an EOF marker to the output audio stream.
315 */
316 int
audio_play_eof(int fd)317 audio_play_eof(int fd)
318 {
319 return (write(fd, (char *)NULL, 0) < 0 ?
320 AUDIO_UNIXERROR : AUDIO_SUCCESS);
321 }
322