1*eabc0478Schristos /* $NetBSD: audio.c,v 1.14 2024/08/18 20:47:13 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * audio.c - audio interface for reference clock audio drivers 5abb0f93cSkardel */ 6abb0f93cSkardel #ifdef HAVE_CONFIG_H 7abb0f93cSkardel # include <config.h> 8abb0f93cSkardel #endif 9abb0f93cSkardel 10abb0f93cSkardel #if defined(HAVE_SYS_AUDIOIO_H) || defined(HAVE_SUN_AUDIOIO_H) || \ 11abb0f93cSkardel defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_MACHINE_SOUNDCARD_H) 12abb0f93cSkardel 13abb0f93cSkardel #include "audio.h" 14abb0f93cSkardel #include "ntp_stdlib.h" 15abb0f93cSkardel #include "ntp_syslog.h" 16abb0f93cSkardel #ifdef HAVE_UNISTD_H 17abb0f93cSkardel # include <unistd.h> 18abb0f93cSkardel #endif 19abb0f93cSkardel #include <stdio.h> 20abb0f93cSkardel #include "ntp_string.h" 21abb0f93cSkardel 22abb0f93cSkardel #ifdef HAVE_SYS_AUDIOIO_H 23abb0f93cSkardel # include <sys/audioio.h> 24abb0f93cSkardel #endif /* HAVE_SYS_AUDIOIO_H */ 25abb0f93cSkardel 26abb0f93cSkardel #ifdef HAVE_SUN_AUDIOIO_H 27abb0f93cSkardel # include <sys/ioccom.h> 28abb0f93cSkardel # include <sun/audioio.h> 29abb0f93cSkardel #endif /* HAVE_SUN_AUDIOIO_H */ 30abb0f93cSkardel 31abb0f93cSkardel #ifdef HAVE_SYS_IOCTL_H 32abb0f93cSkardel # include <sys/ioctl.h> 33abb0f93cSkardel #endif /* HAVE_SYS_IOCTL_H */ 34abb0f93cSkardel 35abb0f93cSkardel #include <fcntl.h> 36abb0f93cSkardel 37abb0f93cSkardel #ifdef HAVE_MACHINE_SOUNDCARD_H 38abb0f93cSkardel # include <machine/soundcard.h> 39abb0f93cSkardel # define PCM_STYLE_SOUND 40abb0f93cSkardel #else 41abb0f93cSkardel # ifdef HAVE_SYS_SOUNDCARD_H 42abb0f93cSkardel # include <sys/soundcard.h> 43abb0f93cSkardel # define PCM_STYLE_SOUND 44abb0f93cSkardel # endif 45abb0f93cSkardel #endif 46abb0f93cSkardel 47abb0f93cSkardel #ifdef PCM_STYLE_SOUND 48abb0f93cSkardel # include <ctype.h> 49abb0f93cSkardel #endif 50abb0f93cSkardel 51ccc794f0Schristos 52ccc794f0Schristos /* 53ccc794f0Schristos * 4.4BSD-Lite switched to an unsigned long ioctl arg. Detect common 54ccc794f0Schristos * derivatives here, and apply that type. To make the following code 55ccc794f0Schristos * less verbose we make a proper typedef. 56ccc794f0Schristos * The joy of IOCTL programming... 57ccc794f0Schristos */ 58ccc794f0Schristos # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined __OpenBSD__ 59ccc794f0Schristos typedef unsigned long ioctl_arg_T; 60ccc794f0Schristos #else 61ccc794f0Schristos typedef int ioctl_arg_T; 62ccc794f0Schristos #endif 63ccc794f0Schristos 64abb0f93cSkardel /* 65abb0f93cSkardel * Global variables 66abb0f93cSkardel */ 67abb0f93cSkardel #ifdef HAVE_SYS_AUDIOIO_H 68abb0f93cSkardel static struct audio_device device; /* audio device ident */ 69abb0f93cSkardel #endif /* HAVE_SYS_AUDIOIO_H */ 70abb0f93cSkardel #ifdef PCM_STYLE_SOUND 71abb0f93cSkardel # define INIT_FILE "/etc/ntp.audio" 72abb0f93cSkardel 73ccc794f0Schristos static ioctl_arg_T agc = SOUND_MIXER_WRITE_RECLEV; /* or IGAIN or LINE */ 74ccc794f0Schristos static ioctl_arg_T audiomonitor = SOUND_MIXER_WRITE_VOLUME; /* or OGAIN */ 75ccc794f0Schristos static int devmask = 0; 76ccc794f0Schristos static int recmask = 0; 77ccc794f0Schristos static char cf_c_dev[100], cf_i_dev[100], cf_agc[100], cf_monitor[100]; 78ccc794f0Schristos 79ccc794f0Schristos static const char *m_names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 80abb0f93cSkardel #else /* not PCM_STYLE_SOUND */ 81abb0f93cSkardel static struct audio_info info; /* audio device info */ 82abb0f93cSkardel #endif /* not PCM_STYLE_SOUND */ 83abb0f93cSkardel static int ctl_fd; /* audio control file descriptor */ 84abb0f93cSkardel 85abb0f93cSkardel #ifdef PCM_STYLE_SOUND 867476e6e4Schristos static void audio_config_read (int, const char **, const char **); 87abb0f93cSkardel static int mixer_name (const char *, int); 88abb0f93cSkardel 89abb0f93cSkardel 90abb0f93cSkardel int 91abb0f93cSkardel mixer_name( 92abb0f93cSkardel const char *m_name, 93abb0f93cSkardel int m_mask 94abb0f93cSkardel ) 95abb0f93cSkardel { 96abb0f93cSkardel int i; 97abb0f93cSkardel 98abb0f93cSkardel for (i = 0; i < SOUND_MIXER_NRDEVICES; ++i) 99abb0f93cSkardel if (((1 << i) & m_mask) 100abb0f93cSkardel && !strcmp(m_names[i], m_name)) 101abb0f93cSkardel break; 102abb0f93cSkardel 103abb0f93cSkardel return (SOUND_MIXER_NRDEVICES == i) 104abb0f93cSkardel ? -1 105abb0f93cSkardel : i 106abb0f93cSkardel ; 107abb0f93cSkardel } 108abb0f93cSkardel 109abb0f93cSkardel 110abb0f93cSkardel /* 111abb0f93cSkardel * Check: 112abb0f93cSkardel * 113abb0f93cSkardel * /etc/ntp.audio# where # is the unit number 114abb0f93cSkardel * /etc/ntp.audio.# where # is the unit number 115abb0f93cSkardel * /etc/ntp.audio 116abb0f93cSkardel * 117abb0f93cSkardel * for contents of the form: 118abb0f93cSkardel * 119abb0f93cSkardel * idev /dev/input_device 120abb0f93cSkardel * cdev /dev/control_device 121abb0f93cSkardel * agc pcm_input_device {igain,line,line1,...} 122abb0f93cSkardel * monitor pcm_monitor_device {ogain,...} 123abb0f93cSkardel * 124abb0f93cSkardel * The device names for the "agc" and "monitor" keywords 125abb0f93cSkardel * can be found by running either the "mixer" program or the 126abb0f93cSkardel * util/audio-pcm program. 127abb0f93cSkardel * 128abb0f93cSkardel * Great hunks of this subroutine were swiped from refclock_oncore.c 129abb0f93cSkardel */ 130abb0f93cSkardel static void 131abb0f93cSkardel audio_config_read( 132abb0f93cSkardel int unit, 1337476e6e4Schristos const char **c_dev, /* Control device */ 1347476e6e4Schristos const char **i_dev /* input device */ 135abb0f93cSkardel ) 136abb0f93cSkardel { 137abb0f93cSkardel FILE *fd; 138abb0f93cSkardel char device[20], line[100], ab[100]; 139abb0f93cSkardel 1403123f114Skardel snprintf(device, sizeof(device), "%s%d", INIT_FILE, unit); 141abb0f93cSkardel if ((fd = fopen(device, "r")) == NULL) { 142abb0f93cSkardel printf("audio_config_read: <%s> NO\n", device); 1433123f114Skardel snprintf(device, sizeof(device), "%s.%d", INIT_FILE, 1443123f114Skardel unit); 145abb0f93cSkardel if ((fd = fopen(device, "r")) == NULL) { 146abb0f93cSkardel printf("audio_config_read: <%s> NO\n", device); 1473123f114Skardel snprintf(device, sizeof(device), "%s", 1483123f114Skardel INIT_FILE); 149abb0f93cSkardel if ((fd = fopen(device, "r")) == NULL) { 1503123f114Skardel printf("audio_config_read: <%s> NO\n", 1513123f114Skardel device); 152abb0f93cSkardel return; 153abb0f93cSkardel } 154abb0f93cSkardel } 155abb0f93cSkardel } 156abb0f93cSkardel printf("audio_config_read: reading <%s>\n", device); 157abb0f93cSkardel while (fgets(line, sizeof line, fd)) { 158abb0f93cSkardel char *cp, *cc, *ca; 159abb0f93cSkardel int i; 160abb0f93cSkardel 161abb0f93cSkardel /* Remove comments */ 162abb0f93cSkardel if ((cp = strchr(line, '#'))) 163abb0f93cSkardel *cp = '\0'; 164abb0f93cSkardel 165abb0f93cSkardel /* Remove any trailing spaces */ 166abb0f93cSkardel for (i = strlen(line); 167ed38567fSchristos i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]); 168abb0f93cSkardel ) 169abb0f93cSkardel line[--i] = '\0'; 170abb0f93cSkardel 171abb0f93cSkardel /* Remove leading space */ 172ed38567fSchristos for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++) 173abb0f93cSkardel continue; 174abb0f93cSkardel 175abb0f93cSkardel /* Stop if nothing left */ 176abb0f93cSkardel if (!*cc) 177abb0f93cSkardel continue; 178abb0f93cSkardel 179abb0f93cSkardel /* Uppercase the command and find the arg */ 180abb0f93cSkardel for (ca = cc; *ca; ca++) { 181ed38567fSchristos if (isascii((unsigned char)*ca)) { 182ed38567fSchristos if (islower((unsigned char)*ca)) { 183ed38567fSchristos *ca = toupper((unsigned char)*ca); 184ed38567fSchristos } else if (isspace((unsigned char)*ca) || (*ca == '=')) 185abb0f93cSkardel break; 186abb0f93cSkardel } 187abb0f93cSkardel } 188abb0f93cSkardel 189abb0f93cSkardel /* Remove space (and possible =) leading the arg */ 190ed38567fSchristos for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++) 191abb0f93cSkardel continue; 192abb0f93cSkardel 1933123f114Skardel if (!strncmp(cc, "IDEV", 4) && 1943123f114Skardel 1 == sscanf(ca, "%99s", ab)) { 1952950cc38Schristos strlcpy(cf_i_dev, ab, sizeof(cf_i_dev)); 196abb0f93cSkardel printf("idev <%s>\n", ab); 1973123f114Skardel } else if (!strncmp(cc, "CDEV", 4) && 1983123f114Skardel 1 == sscanf(ca, "%99s", ab)) { 1992950cc38Schristos strlcpy(cf_c_dev, ab, sizeof(cf_c_dev)); 200abb0f93cSkardel printf("cdev <%s>\n", ab); 2013123f114Skardel } else if (!strncmp(cc, "AGC", 3) && 2023123f114Skardel 1 == sscanf(ca, "%99s", ab)) { 2032950cc38Schristos strlcpy(cf_agc, ab, sizeof(cf_agc)); 204abb0f93cSkardel printf("agc <%s> %d\n", ab, i); 2053123f114Skardel } else if (!strncmp(cc, "MONITOR", 7) && 2063123f114Skardel 1 == sscanf(ca, "%99s", ab)) { 2072950cc38Schristos strlcpy(cf_monitor, ab, sizeof(cf_monitor)); 208abb0f93cSkardel printf("monitor <%s> %d\n", ab, mixer_name(ab, -1)); 209abb0f93cSkardel } 210abb0f93cSkardel } 211abb0f93cSkardel fclose(fd); 212abb0f93cSkardel return; 213abb0f93cSkardel } 214abb0f93cSkardel #endif /* PCM_STYLE_SOUND */ 215abb0f93cSkardel 216abb0f93cSkardel /* 217abb0f93cSkardel * audio_init - open and initialize audio device 218abb0f93cSkardel * 219abb0f93cSkardel * This code works with SunOS 4.x, Solaris 2.x, and PCM; however, it is 220abb0f93cSkardel * believed generic and applicable to other systems with a minor twid 221abb0f93cSkardel * or two. All it does is open the device, set the buffer size (Solaris 222abb0f93cSkardel * only), preset the gain and set the input port. It assumes that the 223abb0f93cSkardel * codec sample rate (8000 Hz), precision (8 bits), number of channels 224abb0f93cSkardel * (1) and encoding (ITU-T G.711 mu-law companded) have been set by 225abb0f93cSkardel * default. 226abb0f93cSkardel */ 227abb0f93cSkardel int 228abb0f93cSkardel audio_init( 229e19314b7Schristos const char *dname, /* device name */ 230abb0f93cSkardel int bufsiz, /* buffer size */ 231abb0f93cSkardel int unit /* device unit (0-3) */ 232abb0f93cSkardel ) 233abb0f93cSkardel { 234abb0f93cSkardel #ifdef PCM_STYLE_SOUND 235abb0f93cSkardel # define ACTL_DEV "/dev/mixer%d" 236abb0f93cSkardel char actl_dev[30]; 237abb0f93cSkardel # ifdef HAVE_STRUCT_SND_SIZE 238abb0f93cSkardel struct snd_size s_size; 239abb0f93cSkardel # endif 240abb0f93cSkardel # ifdef AIOGFMT 241abb0f93cSkardel snd_chan_param s_c_p; 242abb0f93cSkardel # endif 243abb0f93cSkardel #endif 244abb0f93cSkardel int fd; 245abb0f93cSkardel int rval; 246e19314b7Schristos const char *actl = 247abb0f93cSkardel #ifdef PCM_STYLE_SOUND 248abb0f93cSkardel actl_dev 249abb0f93cSkardel #else 250abb0f93cSkardel "/dev/audioctl" 251abb0f93cSkardel #endif 252abb0f93cSkardel ; 253abb0f93cSkardel 254abb0f93cSkardel #ifdef PCM_STYLE_SOUND 2553123f114Skardel snprintf(actl_dev, sizeof(actl_dev), ACTL_DEV, unit); 256abb0f93cSkardel 257abb0f93cSkardel audio_config_read(unit, &actl, &dname); 258abb0f93cSkardel /* If we have values for cf_c_dev or cf_i_dev, use them. */ 259abb0f93cSkardel if (*cf_c_dev) 260abb0f93cSkardel actl = cf_c_dev; 261abb0f93cSkardel if (*cf_i_dev) 262abb0f93cSkardel dname = cf_i_dev; 263abb0f93cSkardel #endif 264abb0f93cSkardel 265abb0f93cSkardel /* 266abb0f93cSkardel * Open audio device 267abb0f93cSkardel */ 268abb0f93cSkardel fd = open(dname, O_RDWR | O_NONBLOCK, 0777); 269abb0f93cSkardel if (fd < 0) { 2702950cc38Schristos msyslog(LOG_ERR, "audio_init: %s %m", dname); 271abb0f93cSkardel return (fd); 272abb0f93cSkardel } 273abb0f93cSkardel 274abb0f93cSkardel /* 275abb0f93cSkardel * Open audio control device. 276abb0f93cSkardel */ 277abb0f93cSkardel ctl_fd = open(actl, O_RDWR); 278abb0f93cSkardel if (ctl_fd < 0) { 2792950cc38Schristos msyslog(LOG_ERR, "audio_init: invalid control device <%s>", 280abb0f93cSkardel actl); 281abb0f93cSkardel close(fd); 282abb0f93cSkardel return(ctl_fd); 283abb0f93cSkardel } 284abb0f93cSkardel 285abb0f93cSkardel /* 286abb0f93cSkardel * Set audio device parameters. 287abb0f93cSkardel */ 288abb0f93cSkardel #ifdef PCM_STYLE_SOUND 289abb0f93cSkardel printf("audio_init: <%s> bufsiz %d\n", dname, bufsiz); 290abb0f93cSkardel rval = fd; 291abb0f93cSkardel 292abb0f93cSkardel # ifdef HAVE_STRUCT_SND_SIZE 293abb0f93cSkardel if (ioctl(fd, AIOGSIZE, &s_size) == -1) 294abb0f93cSkardel printf("audio_init: AIOGSIZE: %s\n", strerror(errno)); 295abb0f93cSkardel else 296abb0f93cSkardel printf("audio_init: orig: play_size %d, rec_size %d\n", 297abb0f93cSkardel s_size.play_size, s_size.rec_size); 298abb0f93cSkardel 299abb0f93cSkardel s_size.play_size = s_size.rec_size = bufsiz; 300abb0f93cSkardel printf("audio_init: want: play_size %d, rec_size %d\n", 301abb0f93cSkardel s_size.play_size, s_size.rec_size); 302abb0f93cSkardel 303abb0f93cSkardel if (ioctl(fd, AIOSSIZE, &s_size) == -1) 304abb0f93cSkardel printf("audio_init: AIOSSIZE: %s\n", strerror(errno)); 305abb0f93cSkardel else 306abb0f93cSkardel printf("audio_init: set: play_size %d, rec_size %d\n", 307abb0f93cSkardel s_size.play_size, s_size.rec_size); 308abb0f93cSkardel # endif /* HAVE_STRUCT_SND_SIZE */ 309abb0f93cSkardel 310abb0f93cSkardel # ifdef SNDCTL_DSP_SETFRAGMENT 311abb0f93cSkardel { 312abb0f93cSkardel int tmp = (16 << 16) + 6; /* 16 fragments, each 2^6 bytes */ 313abb0f93cSkardel if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) 314abb0f93cSkardel printf("audio_init: SNDCTL_DSP_SETFRAGMENT: %s\n", 315abb0f93cSkardel strerror(errno)); 316abb0f93cSkardel } 317abb0f93cSkardel # endif /* SNDCTL_DSP_SETFRAGMENT */ 318abb0f93cSkardel 319abb0f93cSkardel # ifdef AIOGFMT 320abb0f93cSkardel if (ioctl(fd, AIOGFMT, &s_c_p) == -1) 321abb0f93cSkardel printf("audio_init: AIOGFMT: %s\n", strerror(errno)); 322abb0f93cSkardel else 323abb0f93cSkardel printf("audio_init: play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n", 324abb0f93cSkardel s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format); 325abb0f93cSkardel # endif 326abb0f93cSkardel 327abb0f93cSkardel /* Grab the device and record masks */ 328abb0f93cSkardel 329abb0f93cSkardel if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) 330abb0f93cSkardel printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno)); 331abb0f93cSkardel if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) 332abb0f93cSkardel printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno)); 333abb0f93cSkardel 334abb0f93cSkardel /* validate and set any specified config file stuff */ 3353123f114Skardel if (cf_agc[0] != '\0') { 336abb0f93cSkardel int i; 337abb0f93cSkardel 3382950cc38Schristos /* recmask */ 3392950cc38Schristos i = mixer_name(cf_agc, recmask); 340abb0f93cSkardel if (i >= 0) 341abb0f93cSkardel agc = MIXER_WRITE(i); 342abb0f93cSkardel else 343abb0f93cSkardel printf("input %s not in recmask %#x\n", 344abb0f93cSkardel cf_agc, recmask); 345abb0f93cSkardel } 346abb0f93cSkardel 3473123f114Skardel if (cf_monitor[0] != '\0') { 348abb0f93cSkardel int i; 349abb0f93cSkardel 350abb0f93cSkardel /* devmask */ 351abb0f93cSkardel i = mixer_name(cf_monitor, devmask); 352abb0f93cSkardel if (i >= 0) 35303cfe0ffSchristos audiomonitor = MIXER_WRITE(i); 354abb0f93cSkardel else 355abb0f93cSkardel printf("monitor %s not in devmask %#x\n", 356abb0f93cSkardel cf_monitor, devmask); 357abb0f93cSkardel } 358abb0f93cSkardel 359abb0f93cSkardel #else /* not PCM_STYLE_SOUND */ 360abb0f93cSkardel AUDIO_INITINFO(&info); 361abb0f93cSkardel info.play.gain = AUDIO_MAX_GAIN; 362abb0f93cSkardel info.play.port = AUDIO_SPEAKER; 363abb0f93cSkardel # ifdef HAVE_SYS_AUDIOIO_H 364abb0f93cSkardel info.record.buffer_size = bufsiz; 365abb0f93cSkardel # endif /* HAVE_SYS_AUDIOIO_H */ 366ccc794f0Schristos rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info); 367abb0f93cSkardel if (rval < 0) { 3682950cc38Schristos msyslog(LOG_ERR, "audio: invalid control device parameters"); 369abb0f93cSkardel close(ctl_fd); 370abb0f93cSkardel close(fd); 371abb0f93cSkardel return(rval); 372abb0f93cSkardel } 373abb0f93cSkardel rval = fd; 374abb0f93cSkardel #endif /* not PCM_STYLE_SOUND */ 375abb0f93cSkardel return (rval); 376abb0f93cSkardel } 377abb0f93cSkardel 378abb0f93cSkardel 379abb0f93cSkardel /* 380abb0f93cSkardel * audio_gain - adjust codec gains and port 381abb0f93cSkardel */ 382abb0f93cSkardel int 383abb0f93cSkardel audio_gain( 384abb0f93cSkardel int gain, /* volume level (gain) 0-255 */ 385abb0f93cSkardel int mongain, /* input to output mix (monitor gain) 0-255 */ 386abb0f93cSkardel int port /* selected I/O port: 1 mic/2 line in */ 387abb0f93cSkardel ) 388abb0f93cSkardel { 389abb0f93cSkardel int rval; 390abb0f93cSkardel static int o_mongain = -1; 391abb0f93cSkardel static int o_port = -1; 392abb0f93cSkardel 393abb0f93cSkardel #ifdef PCM_STYLE_SOUND 394abb0f93cSkardel int l, r; 395abb0f93cSkardel 396af12ab5eSchristos # ifdef GCC 397af12ab5eSchristos rval = 0; /* GCC thinks rval is used uninitialized */ 398af12ab5eSchristos # endif 399abb0f93cSkardel 400abb0f93cSkardel r = l = 100 * gain / 255; /* Normalize to 0-100 */ 401abb0f93cSkardel # ifdef DEBUG 402abb0f93cSkardel if (debug > 1) 403abb0f93cSkardel printf("audio_gain: gain %d/%d\n", gain, l); 404abb0f93cSkardel # endif 405abb0f93cSkardel #if 0 /* not a good idea to do this; connector wiring dependency */ 406abb0f93cSkardel /* figure out what channel(s) to use. just nuke right for now. */ 407abb0f93cSkardel r = 0 ; /* setting to zero nicely mutes the channel */ 408abb0f93cSkardel #endif 409abb0f93cSkardel l |= r << 8; 4103123f114Skardel if (cf_agc[0] != '\0') 411abb0f93cSkardel rval = ioctl(ctl_fd, agc, &l); 412abb0f93cSkardel else 413af12ab5eSchristos rval = ioctl(ctl_fd 414af12ab5eSchristos , (2 == port) 415af12ab5eSchristos ? SOUND_MIXER_WRITE_LINE 416af12ab5eSchristos : SOUND_MIXER_WRITE_MIC 417af12ab5eSchristos , &l); 4183123f114Skardel if (-1 == rval) { 419abb0f93cSkardel printf("audio_gain: agc write: %s\n", strerror(errno)); 4203123f114Skardel return rval; 421abb0f93cSkardel } 422abb0f93cSkardel 423abb0f93cSkardel if (o_mongain != mongain) { 424abb0f93cSkardel r = l = 100 * mongain / 255; /* Normalize to 0-100 */ 425abb0f93cSkardel # ifdef DEBUG 426abb0f93cSkardel if (debug > 1) 427abb0f93cSkardel printf("audio_gain: mongain %d/%d\n", mongain, l); 428abb0f93cSkardel # endif 429abb0f93cSkardel l |= r << 8; 4303123f114Skardel if (cf_monitor[0] != '\0') 43103cfe0ffSchristos rval = ioctl(ctl_fd, audiomonitor, &l ); 432abb0f93cSkardel else 4333123f114Skardel rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_VOLUME, 4343123f114Skardel &l); 4353123f114Skardel if (-1 == rval) { 436abb0f93cSkardel printf("audio_gain: mongain write: %s\n", 437abb0f93cSkardel strerror(errno)); 438abb0f93cSkardel return (rval); 439abb0f93cSkardel } 440abb0f93cSkardel o_mongain = mongain; 441abb0f93cSkardel } 442abb0f93cSkardel 443abb0f93cSkardel if (o_port != port) { 444abb0f93cSkardel # ifdef DEBUG 445abb0f93cSkardel if (debug > 1) 446abb0f93cSkardel printf("audio_gain: port %d\n", port); 447abb0f93cSkardel # endif 448abb0f93cSkardel l = (1 << ((port == 2) ? SOUND_MIXER_LINE : SOUND_MIXER_MIC)); 449abb0f93cSkardel rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_RECSRC, &l); 450abb0f93cSkardel if (rval == -1) { 451abb0f93cSkardel printf("SOUND_MIXER_WRITE_RECSRC: %s\n", 452abb0f93cSkardel strerror(errno)); 453abb0f93cSkardel return (rval); 454abb0f93cSkardel } 455abb0f93cSkardel # ifdef DEBUG 456abb0f93cSkardel if (debug > 1) { 457abb0f93cSkardel if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &l) == -1) 458abb0f93cSkardel printf("SOUND_MIXER_WRITE_RECSRC: %s\n", 459abb0f93cSkardel strerror(errno)); 460abb0f93cSkardel else 461abb0f93cSkardel printf("audio_gain: recsrc is %d\n", l); 462abb0f93cSkardel } 463abb0f93cSkardel # endif 464abb0f93cSkardel o_port = port; 465abb0f93cSkardel } 466abb0f93cSkardel #else /* not PCM_STYLE_SOUND */ 467ccc794f0Schristos ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info); 468abb0f93cSkardel info.record.encoding = AUDIO_ENCODING_ULAW; 469abb0f93cSkardel info.record.error = 0; 470abb0f93cSkardel info.record.gain = gain; 471abb0f93cSkardel if (o_mongain != mongain) 472abb0f93cSkardel o_mongain = info.monitor_gain = mongain; 473abb0f93cSkardel if (o_port != port) 474abb0f93cSkardel o_port = info.record.port = port; 475ccc794f0Schristos rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info); 476abb0f93cSkardel if (rval < 0) { 477abb0f93cSkardel msyslog(LOG_ERR, "audio_gain: %m"); 478abb0f93cSkardel return (rval); 479abb0f93cSkardel } 480abb0f93cSkardel rval = info.record.error; 481abb0f93cSkardel #endif /* not PCM_STYLE_SOUND */ 482abb0f93cSkardel return (rval); 483abb0f93cSkardel } 484abb0f93cSkardel 485abb0f93cSkardel 486abb0f93cSkardel /* 487abb0f93cSkardel * audio_show - display audio parameters 488abb0f93cSkardel * 489abb0f93cSkardel * This code doesn't really do anything, except satisfy curiousity and 490abb0f93cSkardel * verify the ioctl's work. 491abb0f93cSkardel */ 492abb0f93cSkardel void 493abb0f93cSkardel audio_show(void) 494abb0f93cSkardel { 495abb0f93cSkardel #ifdef PCM_STYLE_SOUND 496abb0f93cSkardel int recsrc = 0; 497abb0f93cSkardel 498abb0f93cSkardel printf("audio_show: ctl_fd %d\n", ctl_fd); 499abb0f93cSkardel if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 500abb0f93cSkardel printf("SOUND_MIXER_READ_RECSRC: %s\n", strerror(errno)); 501abb0f93cSkardel 502abb0f93cSkardel #else /* not PCM_STYLE_SOUND */ 503abb0f93cSkardel # ifdef HAVE_SYS_AUDIOIO_H 504ccc794f0Schristos ioctl(ctl_fd, AUDIO_GETDEV, &device); 505abb0f93cSkardel printf("audio: name %s, version %s, config %s\n", 506abb0f93cSkardel device.name, device.version, device.config); 507abb0f93cSkardel # endif /* HAVE_SYS_AUDIOIO_H */ 508ccc794f0Schristos ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info); 509abb0f93cSkardel printf( 510abb0f93cSkardel "audio: rate %d, chan %d, prec %d, code %d, gain %d, mon %d, port %d\n", 511abb0f93cSkardel info.record.sample_rate, info.record.channels, 512abb0f93cSkardel info.record.precision, info.record.encoding, 513abb0f93cSkardel info.record.gain, info.monitor_gain, info.record.port); 514abb0f93cSkardel printf( 515abb0f93cSkardel "audio: samples %d, eof %d, pause %d, error %d, waiting %d, balance %d\n", 516abb0f93cSkardel info.record.samples, info.record.eof, 517abb0f93cSkardel info.record.pause, info.record.error, 518abb0f93cSkardel info.record.waiting, info.record.balance); 519abb0f93cSkardel #endif /* not PCM_STYLE_SOUND */ 520abb0f93cSkardel } 521abb0f93cSkardel #else 522*eabc0478Schristos NONEMPTY_TRANSLATION_UNIT 523abb0f93cSkardel #endif /* HAVE_{SYS_AUDIOIO,SUN_AUDIOIO,MACHINE_SOUNDCARD,SYS_SOUNDCARD}_H */ 524