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