1a151a66cSOllivier Robert /* 2a151a66cSOllivier Robert * audio.c - audio interface for reference clock audio drivers 3a151a66cSOllivier Robert */ 4a151a66cSOllivier Robert #ifdef HAVE_CONFIG_H 5a151a66cSOllivier Robert # include <config.h> 6a151a66cSOllivier Robert #endif 7a151a66cSOllivier Robert 89c2daa00SOllivier Robert #if defined(HAVE_SYS_AUDIOIO_H) || defined(HAVE_SUN_AUDIOIO_H) || \ 99c2daa00SOllivier Robert defined(HAVE_SYS_SOUNDCARD_H) || defined(HAVE_MACHINE_SOUNDCARD_H) 10224ba2bdSOllivier Robert 11a151a66cSOllivier Robert #include "audio.h" 12224ba2bdSOllivier Robert #include "ntp_stdlib.h" 13224ba2bdSOllivier Robert #include "ntp_syslog.h" 14224ba2bdSOllivier Robert #ifdef HAVE_UNISTD_H 15a151a66cSOllivier Robert # include <unistd.h> 16224ba2bdSOllivier Robert #endif 17a151a66cSOllivier Robert #include <stdio.h> 18224ba2bdSOllivier Robert #include "ntp_string.h" 19a151a66cSOllivier Robert 20a151a66cSOllivier Robert #ifdef HAVE_SYS_AUDIOIO_H 21a151a66cSOllivier Robert # include <sys/audioio.h> 22a151a66cSOllivier Robert #endif /* HAVE_SYS_AUDIOIO_H */ 23224ba2bdSOllivier Robert 24a151a66cSOllivier Robert #ifdef HAVE_SUN_AUDIOIO_H 25224ba2bdSOllivier Robert # include <sys/ioccom.h> 26a151a66cSOllivier Robert # include <sun/audioio.h> 27a151a66cSOllivier Robert #endif /* HAVE_SUN_AUDIOIO_H */ 28224ba2bdSOllivier Robert 29a151a66cSOllivier Robert #ifdef HAVE_SYS_IOCTL_H 30a151a66cSOllivier Robert # include <sys/ioctl.h> 31a151a66cSOllivier Robert #endif /* HAVE_SYS_IOCTL_H */ 32a151a66cSOllivier Robert 33a151a66cSOllivier Robert #include <fcntl.h> 34a151a66cSOllivier Robert 359c2daa00SOllivier Robert #ifdef HAVE_MACHINE_SOUNDCARD_H 369c2daa00SOllivier Robert # include <machine/soundcard.h> 379c2daa00SOllivier Robert # define PCM_STYLE_SOUND 389c2daa00SOllivier Robert #else 399c2daa00SOllivier Robert # ifdef HAVE_SYS_SOUNDCARD_H 409c2daa00SOllivier Robert # include <sys/soundcard.h> 419c2daa00SOllivier Robert # define PCM_STYLE_SOUND 429c2daa00SOllivier Robert # endif 439c2daa00SOllivier Robert #endif 449c2daa00SOllivier Robert 459c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 469c2daa00SOllivier Robert # include <ctype.h> 479c2daa00SOllivier Robert #endif 489c2daa00SOllivier Robert 49f0574f5cSXin LI 50f0574f5cSXin LI /* 51f0574f5cSXin LI * 4.4BSD-Lite switched to an unsigned long ioctl arg. Detect common 52f0574f5cSXin LI * derivatives here, and apply that type. To make the following code 53f0574f5cSXin LI * less verbose we make a proper typedef. 54f0574f5cSXin LI * The joy of IOCTL programming... 55f0574f5cSXin LI */ 56f0574f5cSXin LI # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__) || defined __OpenBSD__ 57f0574f5cSXin LI typedef unsigned long ioctl_arg_T; 58f0574f5cSXin LI #else 59f0574f5cSXin LI typedef int ioctl_arg_T; 60f0574f5cSXin LI #endif 61f0574f5cSXin LI 62a151a66cSOllivier Robert /* 63a151a66cSOllivier Robert * Global variables 64a151a66cSOllivier Robert */ 65a151a66cSOllivier Robert #ifdef HAVE_SYS_AUDIOIO_H 66a151a66cSOllivier Robert static struct audio_device device; /* audio device ident */ 67224ba2bdSOllivier Robert #endif /* HAVE_SYS_AUDIOIO_H */ 689c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 699c2daa00SOllivier Robert # define INIT_FILE "/etc/ntp.audio" 709c2daa00SOllivier Robert 71f0574f5cSXin LI static ioctl_arg_T agc = SOUND_MIXER_WRITE_RECLEV; /* or IGAIN or LINE */ 72f0574f5cSXin LI static ioctl_arg_T audiomonitor = SOUND_MIXER_WRITE_VOLUME; /* or OGAIN */ 73f0574f5cSXin LI static int devmask = 0; 74f0574f5cSXin LI static int recmask = 0; 75f0574f5cSXin LI static char cf_c_dev[100], cf_i_dev[100], cf_agc[100], cf_monitor[100]; 76f0574f5cSXin LI 77f0574f5cSXin LI static const char *m_names[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; 789c2daa00SOllivier Robert #else /* not PCM_STYLE_SOUND */ 79a151a66cSOllivier Robert static struct audio_info info; /* audio device info */ 809c2daa00SOllivier Robert #endif /* not PCM_STYLE_SOUND */ 81a151a66cSOllivier Robert static int ctl_fd; /* audio control file descriptor */ 82a151a66cSOllivier Robert 839c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 842b15cb3dSCy Schubert static void audio_config_read (int, const char **, const char **); 852b15cb3dSCy Schubert static int mixer_name (const char *, int); 869c2daa00SOllivier Robert 879c2daa00SOllivier Robert 889c2daa00SOllivier Robert int 899c2daa00SOllivier Robert mixer_name( 909c2daa00SOllivier Robert const char *m_name, 919c2daa00SOllivier Robert int m_mask 929c2daa00SOllivier Robert ) 939c2daa00SOllivier Robert { 949c2daa00SOllivier Robert int i; 959c2daa00SOllivier Robert 969c2daa00SOllivier Robert for (i = 0; i < SOUND_MIXER_NRDEVICES; ++i) 979c2daa00SOllivier Robert if (((1 << i) & m_mask) 989c2daa00SOllivier Robert && !strcmp(m_names[i], m_name)) 999c2daa00SOllivier Robert break; 1009c2daa00SOllivier Robert 1019c2daa00SOllivier Robert return (SOUND_MIXER_NRDEVICES == i) 1029c2daa00SOllivier Robert ? -1 1039c2daa00SOllivier Robert : i 1049c2daa00SOllivier Robert ; 1059c2daa00SOllivier Robert } 1069c2daa00SOllivier Robert 1079c2daa00SOllivier Robert 1089c2daa00SOllivier Robert /* 1099c2daa00SOllivier Robert * Check: 1109c2daa00SOllivier Robert * 1119c2daa00SOllivier Robert * /etc/ntp.audio# where # is the unit number 1129c2daa00SOllivier Robert * /etc/ntp.audio.# where # is the unit number 1139c2daa00SOllivier Robert * /etc/ntp.audio 1149c2daa00SOllivier Robert * 1159c2daa00SOllivier Robert * for contents of the form: 1169c2daa00SOllivier Robert * 1179c2daa00SOllivier Robert * idev /dev/input_device 1189c2daa00SOllivier Robert * cdev /dev/control_device 1199c2daa00SOllivier Robert * agc pcm_input_device {igain,line,line1,...} 1209c2daa00SOllivier Robert * monitor pcm_monitor_device {ogain,...} 1219c2daa00SOllivier Robert * 1229c2daa00SOllivier Robert * The device names for the "agc" and "monitor" keywords 1239c2daa00SOllivier Robert * can be found by running either the "mixer" program or the 1249c2daa00SOllivier Robert * util/audio-pcm program. 1259c2daa00SOllivier Robert * 1269c2daa00SOllivier Robert * Great hunks of this subroutine were swiped from refclock_oncore.c 1279c2daa00SOllivier Robert */ 1289c2daa00SOllivier Robert static void 1299c2daa00SOllivier Robert audio_config_read( 1309c2daa00SOllivier Robert int unit, 1312b15cb3dSCy Schubert const char **c_dev, /* Control device */ 1322b15cb3dSCy Schubert const char **i_dev /* input device */ 1339c2daa00SOllivier Robert ) 1349c2daa00SOllivier Robert { 1359c2daa00SOllivier Robert FILE *fd; 1369c2daa00SOllivier Robert char device[20], line[100], ab[100]; 1379c2daa00SOllivier Robert 1382b15cb3dSCy Schubert snprintf(device, sizeof(device), "%s%d", INIT_FILE, unit); 1399c2daa00SOllivier Robert if ((fd = fopen(device, "r")) == NULL) { 1409c2daa00SOllivier Robert printf("audio_config_read: <%s> NO\n", device); 1412b15cb3dSCy Schubert snprintf(device, sizeof(device), "%s.%d", INIT_FILE, 1422b15cb3dSCy Schubert unit); 1439c2daa00SOllivier Robert if ((fd = fopen(device, "r")) == NULL) { 1449c2daa00SOllivier Robert printf("audio_config_read: <%s> NO\n", device); 1452b15cb3dSCy Schubert snprintf(device, sizeof(device), "%s", 1462b15cb3dSCy Schubert INIT_FILE); 1479c2daa00SOllivier Robert if ((fd = fopen(device, "r")) == NULL) { 1482b15cb3dSCy Schubert printf("audio_config_read: <%s> NO\n", 1492b15cb3dSCy Schubert device); 1509c2daa00SOllivier Robert return; 1519c2daa00SOllivier Robert } 1529c2daa00SOllivier Robert } 1539c2daa00SOllivier Robert } 1549c2daa00SOllivier Robert printf("audio_config_read: reading <%s>\n", device); 1559c2daa00SOllivier Robert while (fgets(line, sizeof line, fd)) { 1569c2daa00SOllivier Robert char *cp, *cc, *ca; 1579c2daa00SOllivier Robert int i; 1589c2daa00SOllivier Robert 1599c2daa00SOllivier Robert /* Remove comments */ 1609c2daa00SOllivier Robert if ((cp = strchr(line, '#'))) 1619c2daa00SOllivier Robert *cp = '\0'; 1629c2daa00SOllivier Robert 1639c2daa00SOllivier Robert /* Remove any trailing spaces */ 1649c2daa00SOllivier Robert for (i = strlen(line); 1652b15cb3dSCy Schubert i > 0 && isascii((unsigned char)line[i - 1]) && isspace((unsigned char)line[i - 1]); 1669c2daa00SOllivier Robert ) 1679c2daa00SOllivier Robert line[--i] = '\0'; 1689c2daa00SOllivier Robert 1699c2daa00SOllivier Robert /* Remove leading space */ 1702b15cb3dSCy Schubert for (cc = line; *cc && isascii((unsigned char)*cc) && isspace((unsigned char)*cc); cc++) 1719c2daa00SOllivier Robert continue; 1729c2daa00SOllivier Robert 1739c2daa00SOllivier Robert /* Stop if nothing left */ 1749c2daa00SOllivier Robert if (!*cc) 1759c2daa00SOllivier Robert continue; 1769c2daa00SOllivier Robert 1779c2daa00SOllivier Robert /* Uppercase the command and find the arg */ 1789c2daa00SOllivier Robert for (ca = cc; *ca; ca++) { 1792b15cb3dSCy Schubert if (isascii((unsigned char)*ca)) { 1802b15cb3dSCy Schubert if (islower((unsigned char)*ca)) { 1812b15cb3dSCy Schubert *ca = toupper((unsigned char)*ca); 1822b15cb3dSCy Schubert } else if (isspace((unsigned char)*ca) || (*ca == '=')) 1839c2daa00SOllivier Robert break; 1849c2daa00SOllivier Robert } 1859c2daa00SOllivier Robert } 1869c2daa00SOllivier Robert 1879c2daa00SOllivier Robert /* Remove space (and possible =) leading the arg */ 1882b15cb3dSCy Schubert for (; *ca && isascii((unsigned char)*ca) && (isspace((unsigned char)*ca) || (*ca == '=')); ca++) 1899c2daa00SOllivier Robert continue; 1909c2daa00SOllivier Robert 1912b15cb3dSCy Schubert if (!strncmp(cc, "IDEV", 4) && 1922b15cb3dSCy Schubert 1 == sscanf(ca, "%99s", ab)) { 1932b15cb3dSCy Schubert strlcpy(cf_i_dev, ab, sizeof(cf_i_dev)); 1949c2daa00SOllivier Robert printf("idev <%s>\n", ab); 1952b15cb3dSCy Schubert } else if (!strncmp(cc, "CDEV", 4) && 1962b15cb3dSCy Schubert 1 == sscanf(ca, "%99s", ab)) { 1972b15cb3dSCy Schubert strlcpy(cf_c_dev, ab, sizeof(cf_c_dev)); 1989c2daa00SOllivier Robert printf("cdev <%s>\n", ab); 1992b15cb3dSCy Schubert } else if (!strncmp(cc, "AGC", 3) && 2002b15cb3dSCy Schubert 1 == sscanf(ca, "%99s", ab)) { 2012b15cb3dSCy Schubert strlcpy(cf_agc, ab, sizeof(cf_agc)); 2029c2daa00SOllivier Robert printf("agc <%s> %d\n", ab, i); 2032b15cb3dSCy Schubert } else if (!strncmp(cc, "MONITOR", 7) && 2042b15cb3dSCy Schubert 1 == sscanf(ca, "%99s", ab)) { 2052b15cb3dSCy Schubert strlcpy(cf_monitor, ab, sizeof(cf_monitor)); 2069c2daa00SOllivier Robert printf("monitor <%s> %d\n", ab, mixer_name(ab, -1)); 2079c2daa00SOllivier Robert } 2089c2daa00SOllivier Robert } 2099c2daa00SOllivier Robert fclose(fd); 2109c2daa00SOllivier Robert return; 2119c2daa00SOllivier Robert } 2129c2daa00SOllivier Robert #endif /* PCM_STYLE_SOUND */ 213a151a66cSOllivier Robert 214a151a66cSOllivier Robert /* 215a151a66cSOllivier Robert * audio_init - open and initialize audio device 216a151a66cSOllivier Robert * 2179c2daa00SOllivier Robert * This code works with SunOS 4.x, Solaris 2.x, and PCM; however, it is 218a151a66cSOllivier Robert * believed generic and applicable to other systems with a minor twid 219a151a66cSOllivier Robert * or two. All it does is open the device, set the buffer size (Solaris 220a151a66cSOllivier Robert * only), preset the gain and set the input port. It assumes that the 221a151a66cSOllivier Robert * codec sample rate (8000 Hz), precision (8 bits), number of channels 222a151a66cSOllivier Robert * (1) and encoding (ITU-T G.711 mu-law companded) have been set by 223a151a66cSOllivier Robert * default. 224a151a66cSOllivier Robert */ 225a151a66cSOllivier Robert int 226224ba2bdSOllivier Robert audio_init( 2272b15cb3dSCy Schubert const char *dname, /* device name */ 2289c2daa00SOllivier Robert int bufsiz, /* buffer size */ 2299c2daa00SOllivier Robert int unit /* device unit (0-3) */ 230224ba2bdSOllivier Robert ) 231a151a66cSOllivier Robert { 2329c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 2339c2daa00SOllivier Robert # define ACTL_DEV "/dev/mixer%d" 2349c2daa00SOllivier Robert char actl_dev[30]; 2359c2daa00SOllivier Robert # ifdef HAVE_STRUCT_SND_SIZE 2369c2daa00SOllivier Robert struct snd_size s_size; 2379c2daa00SOllivier Robert # endif 2389c2daa00SOllivier Robert # ifdef AIOGFMT 2399c2daa00SOllivier Robert snd_chan_param s_c_p; 2409c2daa00SOllivier Robert # endif 2419c2daa00SOllivier Robert #endif 242a151a66cSOllivier Robert int fd; 243a151a66cSOllivier Robert int rval; 2442b15cb3dSCy Schubert const char *actl = 2459c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 2469c2daa00SOllivier Robert actl_dev 2479c2daa00SOllivier Robert #else 2489c2daa00SOllivier Robert "/dev/audioctl" 2499c2daa00SOllivier Robert #endif 2509c2daa00SOllivier Robert ; 2519c2daa00SOllivier Robert 2529c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 2532b15cb3dSCy Schubert snprintf(actl_dev, sizeof(actl_dev), ACTL_DEV, unit); 2549c2daa00SOllivier Robert 2559c2daa00SOllivier Robert audio_config_read(unit, &actl, &dname); 2569c2daa00SOllivier Robert /* If we have values for cf_c_dev or cf_i_dev, use them. */ 2579c2daa00SOllivier Robert if (*cf_c_dev) 258ea906c41SOllivier Robert actl = cf_c_dev; 2599c2daa00SOllivier Robert if (*cf_i_dev) 260ea906c41SOllivier Robert dname = cf_i_dev; 2619c2daa00SOllivier Robert #endif 262a151a66cSOllivier Robert 263a151a66cSOllivier Robert /* 2642b15cb3dSCy Schubert * Open audio device 265a151a66cSOllivier Robert */ 266224ba2bdSOllivier Robert fd = open(dname, O_RDWR | O_NONBLOCK, 0777); 2672b15cb3dSCy Schubert if (fd < 0) { 2682b15cb3dSCy Schubert msyslog(LOG_ERR, "audio_init: %s %m", dname); 269a151a66cSOllivier Robert return (fd); 2702b15cb3dSCy Schubert } 271a151a66cSOllivier Robert 272a151a66cSOllivier Robert /* 273224ba2bdSOllivier Robert * Open audio control device. 274a151a66cSOllivier Robert */ 2759c2daa00SOllivier Robert ctl_fd = open(actl, O_RDWR); 276a151a66cSOllivier Robert if (ctl_fd < 0) { 2772b15cb3dSCy Schubert msyslog(LOG_ERR, "audio_init: invalid control device <%s>", 2782b15cb3dSCy Schubert actl); 279a151a66cSOllivier Robert close(fd); 280a151a66cSOllivier Robert return(ctl_fd); 281a151a66cSOllivier Robert } 282a151a66cSOllivier Robert 283a151a66cSOllivier Robert /* 284a151a66cSOllivier Robert * Set audio device parameters. 285a151a66cSOllivier Robert */ 2869c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 2879c2daa00SOllivier Robert printf("audio_init: <%s> bufsiz %d\n", dname, bufsiz); 2889c2daa00SOllivier Robert rval = fd; 2899c2daa00SOllivier Robert 2909c2daa00SOllivier Robert # ifdef HAVE_STRUCT_SND_SIZE 2919c2daa00SOllivier Robert if (ioctl(fd, AIOGSIZE, &s_size) == -1) 2929c2daa00SOllivier Robert printf("audio_init: AIOGSIZE: %s\n", strerror(errno)); 2939c2daa00SOllivier Robert else 2949c2daa00SOllivier Robert printf("audio_init: orig: play_size %d, rec_size %d\n", 2959c2daa00SOllivier Robert s_size.play_size, s_size.rec_size); 2969c2daa00SOllivier Robert 2979c2daa00SOllivier Robert s_size.play_size = s_size.rec_size = bufsiz; 2989c2daa00SOllivier Robert printf("audio_init: want: play_size %d, rec_size %d\n", 2999c2daa00SOllivier Robert s_size.play_size, s_size.rec_size); 3009c2daa00SOllivier Robert 3019c2daa00SOllivier Robert if (ioctl(fd, AIOSSIZE, &s_size) == -1) 3029c2daa00SOllivier Robert printf("audio_init: AIOSSIZE: %s\n", strerror(errno)); 3039c2daa00SOllivier Robert else 3049c2daa00SOllivier Robert printf("audio_init: set: play_size %d, rec_size %d\n", 3059c2daa00SOllivier Robert s_size.play_size, s_size.rec_size); 3069c2daa00SOllivier Robert # endif /* HAVE_STRUCT_SND_SIZE */ 3079c2daa00SOllivier Robert 308ea906c41SOllivier Robert # ifdef SNDCTL_DSP_SETFRAGMENT 309ea906c41SOllivier Robert { 310ea906c41SOllivier Robert int tmp = (16 << 16) + 6; /* 16 fragments, each 2^6 bytes */ 311ea906c41SOllivier Robert if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) 312ea906c41SOllivier Robert printf("audio_init: SNDCTL_DSP_SETFRAGMENT: %s\n", 313ea906c41SOllivier Robert strerror(errno)); 314ea906c41SOllivier Robert } 315ea906c41SOllivier Robert # endif /* SNDCTL_DSP_SETFRAGMENT */ 316ea906c41SOllivier Robert 3179c2daa00SOllivier Robert # ifdef AIOGFMT 3189c2daa00SOllivier Robert if (ioctl(fd, AIOGFMT, &s_c_p) == -1) 3199c2daa00SOllivier Robert printf("audio_init: AIOGFMT: %s\n", strerror(errno)); 3209c2daa00SOllivier Robert else 3219c2daa00SOllivier Robert printf("audio_init: play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n", 3229c2daa00SOllivier Robert s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format); 3239c2daa00SOllivier Robert # endif 3249c2daa00SOllivier Robert 3259c2daa00SOllivier Robert /* Grab the device and record masks */ 3269c2daa00SOllivier Robert 3279c2daa00SOllivier Robert if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) 3289c2daa00SOllivier Robert printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno)); 3299c2daa00SOllivier Robert if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) 3309c2daa00SOllivier Robert printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno)); 3319c2daa00SOllivier Robert 3329c2daa00SOllivier Robert /* validate and set any specified config file stuff */ 3332b15cb3dSCy Schubert if (cf_agc[0] != '\0') { 3349c2daa00SOllivier Robert int i; 3359c2daa00SOllivier Robert 3362b15cb3dSCy Schubert /* recmask */ 3372b15cb3dSCy Schubert i = mixer_name(cf_agc, recmask); 3389c2daa00SOllivier Robert if (i >= 0) 3399c2daa00SOllivier Robert agc = MIXER_WRITE(i); 3409c2daa00SOllivier Robert else 3419c2daa00SOllivier Robert printf("input %s not in recmask %#x\n", 3429c2daa00SOllivier Robert cf_agc, recmask); 3439c2daa00SOllivier Robert } 3449c2daa00SOllivier Robert 3452b15cb3dSCy Schubert if (cf_monitor[0] != '\0') { 3469c2daa00SOllivier Robert int i; 3479c2daa00SOllivier Robert 3489c2daa00SOllivier Robert /* devmask */ 3499c2daa00SOllivier Robert i = mixer_name(cf_monitor, devmask); 3509c2daa00SOllivier Robert if (i >= 0) 351f391d6bcSXin LI audiomonitor = MIXER_WRITE(i); 3529c2daa00SOllivier Robert else 3539c2daa00SOllivier Robert printf("monitor %s not in devmask %#x\n", 3549c2daa00SOllivier Robert cf_monitor, devmask); 3559c2daa00SOllivier Robert } 3569c2daa00SOllivier Robert 3579c2daa00SOllivier Robert #else /* not PCM_STYLE_SOUND */ 3589c2daa00SOllivier Robert AUDIO_INITINFO(&info); 3599c2daa00SOllivier Robert info.play.gain = AUDIO_MAX_GAIN; 3609c2daa00SOllivier Robert info.play.port = AUDIO_SPEAKER; 3619c2daa00SOllivier Robert # ifdef HAVE_SYS_AUDIOIO_H 3629c2daa00SOllivier Robert info.record.buffer_size = bufsiz; 3639c2daa00SOllivier Robert # endif /* HAVE_SYS_AUDIOIO_H */ 364f0574f5cSXin LI rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info); 365a151a66cSOllivier Robert if (rval < 0) { 3662b15cb3dSCy Schubert msyslog(LOG_ERR, "audio: invalid control device parameters"); 367a151a66cSOllivier Robert close(ctl_fd); 368a151a66cSOllivier Robert close(fd); 369a151a66cSOllivier Robert return(rval); 370a151a66cSOllivier Robert } 3719c2daa00SOllivier Robert rval = fd; 3729c2daa00SOllivier Robert #endif /* not PCM_STYLE_SOUND */ 3739c2daa00SOllivier Robert return (rval); 374a151a66cSOllivier Robert } 375a151a66cSOllivier Robert 376a151a66cSOllivier Robert 377a151a66cSOllivier Robert /* 3789c2daa00SOllivier Robert * audio_gain - adjust codec gains and port 379a151a66cSOllivier Robert */ 380a151a66cSOllivier Robert int 381a151a66cSOllivier Robert audio_gain( 3829c2daa00SOllivier Robert int gain, /* volume level (gain) 0-255 */ 3839c2daa00SOllivier Robert int mongain, /* input to output mix (monitor gain) 0-255 */ 3849c2daa00SOllivier Robert int port /* selected I/O port: 1 mic/2 line in */ 385a151a66cSOllivier Robert ) 386a151a66cSOllivier Robert { 387a151a66cSOllivier Robert int rval; 3889c2daa00SOllivier Robert static int o_mongain = -1; 3899c2daa00SOllivier Robert static int o_port = -1; 390a151a66cSOllivier Robert 3919c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 3929c2daa00SOllivier Robert int l, r; 3939c2daa00SOllivier Robert 3949034852cSGleb Smirnoff # ifdef GCC 3959034852cSGleb Smirnoff rval = 0; /* GCC thinks rval is used uninitialized */ 3969034852cSGleb Smirnoff # endif 3979c2daa00SOllivier Robert 3989c2daa00SOllivier Robert r = l = 100 * gain / 255; /* Normalize to 0-100 */ 3999c2daa00SOllivier Robert # ifdef DEBUG 4009c2daa00SOllivier Robert if (debug > 1) 4019c2daa00SOllivier Robert printf("audio_gain: gain %d/%d\n", gain, l); 4029c2daa00SOllivier Robert # endif 4032b15cb3dSCy Schubert #if 0 /* not a good idea to do this; connector wiring dependency */ 4049c2daa00SOllivier Robert /* figure out what channel(s) to use. just nuke right for now. */ 4059c2daa00SOllivier Robert r = 0 ; /* setting to zero nicely mutes the channel */ 4062b15cb3dSCy Schubert #endif 4079c2daa00SOllivier Robert l |= r << 8; 4082b15cb3dSCy Schubert if (cf_agc[0] != '\0') 409ea906c41SOllivier Robert rval = ioctl(ctl_fd, agc, &l); 410ea906c41SOllivier Robert else 4119034852cSGleb Smirnoff rval = ioctl(ctl_fd 4129034852cSGleb Smirnoff , (2 == port) 4139034852cSGleb Smirnoff ? SOUND_MIXER_WRITE_LINE 4149034852cSGleb Smirnoff : SOUND_MIXER_WRITE_MIC 4159034852cSGleb Smirnoff , &l); 4162b15cb3dSCy Schubert if (-1 == rval) { 4179c2daa00SOllivier Robert printf("audio_gain: agc write: %s\n", strerror(errno)); 4182b15cb3dSCy Schubert return rval; 4199c2daa00SOllivier Robert } 4209c2daa00SOllivier Robert 4219c2daa00SOllivier Robert if (o_mongain != mongain) { 4229c2daa00SOllivier Robert r = l = 100 * mongain / 255; /* Normalize to 0-100 */ 4239c2daa00SOllivier Robert # ifdef DEBUG 4249c2daa00SOllivier Robert if (debug > 1) 4259c2daa00SOllivier Robert printf("audio_gain: mongain %d/%d\n", mongain, l); 4269c2daa00SOllivier Robert # endif 4279c2daa00SOllivier Robert l |= r << 8; 4282b15cb3dSCy Schubert if (cf_monitor[0] != '\0') 429f391d6bcSXin LI rval = ioctl(ctl_fd, audiomonitor, &l ); 430ea906c41SOllivier Robert else 4312b15cb3dSCy Schubert rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_VOLUME, 4322b15cb3dSCy Schubert &l); 4332b15cb3dSCy Schubert if (-1 == rval) { 4349c2daa00SOllivier Robert printf("audio_gain: mongain write: %s\n", 4359c2daa00SOllivier Robert strerror(errno)); 4369c2daa00SOllivier Robert return (rval); 4379c2daa00SOllivier Robert } 4389c2daa00SOllivier Robert o_mongain = mongain; 4399c2daa00SOllivier Robert } 4409c2daa00SOllivier Robert 4419c2daa00SOllivier Robert if (o_port != port) { 4429c2daa00SOllivier Robert # ifdef DEBUG 4439c2daa00SOllivier Robert if (debug > 1) 4449c2daa00SOllivier Robert printf("audio_gain: port %d\n", port); 4459c2daa00SOllivier Robert # endif 4469c2daa00SOllivier Robert l = (1 << ((port == 2) ? SOUND_MIXER_LINE : SOUND_MIXER_MIC)); 4479c2daa00SOllivier Robert rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_RECSRC, &l); 4489c2daa00SOllivier Robert if (rval == -1) { 4499c2daa00SOllivier Robert printf("SOUND_MIXER_WRITE_RECSRC: %s\n", 4509c2daa00SOllivier Robert strerror(errno)); 4519c2daa00SOllivier Robert return (rval); 4529c2daa00SOllivier Robert } 4539c2daa00SOllivier Robert # ifdef DEBUG 4549c2daa00SOllivier Robert if (debug > 1) { 4559c2daa00SOllivier Robert if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &l) == -1) 4569c2daa00SOllivier Robert printf("SOUND_MIXER_WRITE_RECSRC: %s\n", 4579c2daa00SOllivier Robert strerror(errno)); 4589c2daa00SOllivier Robert else 4599c2daa00SOllivier Robert printf("audio_gain: recsrc is %d\n", l); 4609c2daa00SOllivier Robert } 4619c2daa00SOllivier Robert # endif 4629c2daa00SOllivier Robert o_port = port; 4639c2daa00SOllivier Robert } 4649c2daa00SOllivier Robert #else /* not PCM_STYLE_SOUND */ 465f0574f5cSXin LI ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info); 4669c2daa00SOllivier Robert info.record.encoding = AUDIO_ENCODING_ULAW; 467a151a66cSOllivier Robert info.record.error = 0; 4689c2daa00SOllivier Robert info.record.gain = gain; 4699c2daa00SOllivier Robert if (o_mongain != mongain) 4709c2daa00SOllivier Robert o_mongain = info.monitor_gain = mongain; 4719c2daa00SOllivier Robert if (o_port != port) 4729c2daa00SOllivier Robert o_port = info.record.port = port; 473f0574f5cSXin LI rval = ioctl(ctl_fd, AUDIO_SETINFO, (char *)&info); 474a151a66cSOllivier Robert if (rval < 0) { 475224ba2bdSOllivier Robert msyslog(LOG_ERR, "audio_gain: %m"); 476a151a66cSOllivier Robert return (rval); 477a151a66cSOllivier Robert } 4789c2daa00SOllivier Robert rval = info.record.error; 4799c2daa00SOllivier Robert #endif /* not PCM_STYLE_SOUND */ 4809c2daa00SOllivier Robert return (rval); 481a151a66cSOllivier Robert } 482a151a66cSOllivier Robert 483a151a66cSOllivier Robert 484a151a66cSOllivier Robert /* 485a151a66cSOllivier Robert * audio_show - display audio parameters 486a151a66cSOllivier Robert * 487a151a66cSOllivier Robert * This code doesn't really do anything, except satisfy curiousity and 488a151a66cSOllivier Robert * verify the ioctl's work. 489a151a66cSOllivier Robert */ 490a151a66cSOllivier Robert void 491a151a66cSOllivier Robert audio_show(void) 492a151a66cSOllivier Robert { 4939c2daa00SOllivier Robert #ifdef PCM_STYLE_SOUND 4949c2daa00SOllivier Robert int recsrc = 0; 4959c2daa00SOllivier Robert 4969c2daa00SOllivier Robert printf("audio_show: ctl_fd %d\n", ctl_fd); 4979c2daa00SOllivier Robert if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) 4989c2daa00SOllivier Robert printf("SOUND_MIXER_READ_RECSRC: %s\n", strerror(errno)); 4999c2daa00SOllivier Robert 5009c2daa00SOllivier Robert #else /* not PCM_STYLE_SOUND */ 501a151a66cSOllivier Robert # ifdef HAVE_SYS_AUDIOIO_H 502f0574f5cSXin LI ioctl(ctl_fd, AUDIO_GETDEV, &device); 503a151a66cSOllivier Robert printf("audio: name %s, version %s, config %s\n", 504a151a66cSOllivier Robert device.name, device.version, device.config); 505224ba2bdSOllivier Robert # endif /* HAVE_SYS_AUDIOIO_H */ 506f0574f5cSXin LI ioctl(ctl_fd, AUDIO_GETINFO, (char *)&info); 507a151a66cSOllivier Robert printf( 5089c2daa00SOllivier Robert "audio: rate %d, chan %d, prec %d, code %d, gain %d, mon %d, port %d\n", 509a151a66cSOllivier Robert info.record.sample_rate, info.record.channels, 510224ba2bdSOllivier Robert info.record.precision, info.record.encoding, 5119c2daa00SOllivier Robert info.record.gain, info.monitor_gain, info.record.port); 512a151a66cSOllivier Robert printf( 513a151a66cSOllivier Robert "audio: samples %d, eof %d, pause %d, error %d, waiting %d, balance %d\n", 514a151a66cSOllivier Robert info.record.samples, info.record.eof, 515a151a66cSOllivier Robert info.record.pause, info.record.error, 516a151a66cSOllivier Robert info.record.waiting, info.record.balance); 5179c2daa00SOllivier Robert #endif /* not PCM_STYLE_SOUND */ 518a151a66cSOllivier Robert } 519224ba2bdSOllivier Robert #else 520*f5f40dd6SCy Schubert NONEMPTY_TRANSLATION_UNIT 5219c2daa00SOllivier Robert #endif /* HAVE_{SYS_AUDIOIO,SUN_AUDIOIO,MACHINE_SOUNDCARD,SYS_SOUNDCARD}_H */ 522