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