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 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 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 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 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 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 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 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 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 317 audio_play_eof(int fd) 318 { 319 return (write(fd, (char *)NULL, 0) < 0 ? 320 AUDIO_UNIXERROR : AUDIO_SUCCESS); 321 } 322