spoon

set dwm status
git clone git://git.2f30.org/spoon.git
Log | Files | Refs | LICENSE

mix.c (4754B)


      1 #include <err.h>
      2 #include <stdio.h>
      3 
      4 #include "util.h"
      5 
      6 #ifdef __OpenBSD__
      7 #include <sys/ioctl.h>
      8 #include <sys/audioio.h>
      9 
     10 #include <fcntl.h>
     11 #include <string.h>
     12 #include <unistd.h>
     13 
     14 int
     15 mixread(void *arg, char *buf, size_t len)
     16 {
     17 	mixer_devinfo_t dinfo;
     18 	mixer_ctrl_t mctl;
     19 	int fd, master, ret = 0, i = -1;
     20 
     21 	fd = open("/dev/mixer", O_RDONLY);
     22 	if (fd == -1) {
     23 		warn("open %s", "/dev/mixer");
     24 		return -1;
     25 	}
     26 	dinfo.index = 0;
     27 	/* outputs */
     28 	for (; ; dinfo.index++) {
     29 		ret = ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo);
     30 		if (ret == -1) {
     31 			warn("AUDIO_MIXER_DEVINFO %s", "/dev/mixer");
     32 			goto out;
     33 		}
     34 		if (dinfo.type == AUDIO_MIXER_CLASS &&
     35 		    strcmp(dinfo.label.name, AudioCoutputs) == 0) {
     36 			i = dinfo.index;
     37 			break;
     38 		}
     39 	}
     40 	if (i == -1) {
     41 		warnx("no outputs mixer class: %s", "/dev/mixer");
     42 		goto out;
     43 	}
     44 	/* outputs.master */
     45 	for (; ; dinfo.index++) {
     46 		ret = ioctl(fd, AUDIO_MIXER_DEVINFO, &dinfo);
     47 		if (ret == -1) {
     48 			warn("AUDIO_MIXER_DEVINFO %s", "/dev/mixer");
     49 			goto out;
     50 		}
     51 		if (dinfo.type == AUDIO_MIXER_VALUE &&
     52 		    dinfo.prev == AUDIO_MIXER_LAST &&
     53 		    dinfo.mixer_class == i &&
     54 		    strcmp(dinfo.label.name, AudioNmaster) == 0)
     55 			break;
     56 	}
     57 	mctl.dev = dinfo.index;
     58 	ret = ioctl(fd, AUDIO_MIXER_READ, &mctl);
     59 	if (ret == -1) {
     60 		warn("AUDIO_MIXER_READ %s", "/dev/mixer");
     61 		goto out;
     62 	}
     63 	master = mctl.un.value.level[0] * 100 / 255;
     64 	snprintf(buf, len, "%d%%", master);
     65 out:
     66 	close(fd);
     67 	return ret;
     68 }
     69 #elif __linux__ && !USE_TINYALSA
     70 #include <alsa/asoundlib.h>
     71 
     72 static int active;
     73 static int master;
     74 
     75 int
     76 mixer_elem_cb(snd_mixer_elem_t *elem, unsigned int mask)
     77 {
     78 	long min, max, vol;
     79 	int r;
     80 
     81 	r = snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_UNKNOWN, &active);
     82 	if (r < 0) {
     83 		warnx("snd_mixer_selem_get_playback_switch: %s",
     84 		      snd_strerror(r));
     85 		return -1;
     86 	}
     87 	DPRINTF_D(active);
     88 	r = snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
     89 	if (r < 0) {
     90 		warnx("snd_mixer_selem_get_playback_volume_range: %s",
     91 		      snd_strerror(r));
     92 		return -1;
     93 	}
     94 	r = snd_mixer_selem_get_playback_volume(elem,
     95 	    SND_MIXER_SCHN_UNKNOWN, &vol);
     96 	if (r < 0) {
     97 		warnx("snd_mixer_selem_get_playback_volume: %s",
     98 		      snd_strerror(r));
     99 		return -1;
    100 	}
    101 	/* compute percentage */
    102 	vol -= min;
    103 	max -= min;
    104 	if (max == 0)
    105 		master = 0;
    106 	else
    107 		master = 100 * vol / max;
    108 	DPRINTF_D(master);
    109 	return 0;
    110 }
    111 
    112 int
    113 mixread(void *arg, char *buf, size_t len)
    114 {
    115 	snd_mixer_selem_id_t *id;
    116 	snd_mixer_elem_t *elem;
    117 	static snd_mixer_t *mixerp;
    118 	struct pollfd pfd[1];
    119 	int r;
    120 
    121 	snd_mixer_selem_id_alloca(&id);
    122 	snd_mixer_selem_id_set_name(id, "Master");
    123 	snd_mixer_selem_id_set_index(id, 0);
    124 
    125 	if (mixerp != NULL)
    126 		goto readvol;
    127 
    128 	r = snd_mixer_open(&mixerp, O_RDONLY);
    129 	if (r < 0) {
    130 		warnx("snd_mixer_open: %s", snd_strerror(r));
    131 		return -1;
    132 	}
    133 	r = snd_mixer_attach(mixerp, "default");
    134 	if (r < 0) {
    135 		warnx("snd_mixer_attach: %s", snd_strerror(r));
    136 		goto out;
    137 	}
    138 	r = snd_mixer_selem_register(mixerp, NULL, NULL);
    139 	if (r < 0) {
    140 		warnx("snd_mixer_selem_register: %s", snd_strerror(r));
    141 		goto out;
    142 	}
    143 	r = snd_mixer_load(mixerp);
    144 	if (r < 0) {
    145 		warnx("snd_mixer_load: %s", snd_strerror(r));
    146 		goto out;
    147 	}
    148 	elem = snd_mixer_find_selem(mixerp, id);
    149 	if (elem == NULL) {
    150 		warnx("could not find mixer element");
    151 		goto out;
    152 	}
    153 	snd_mixer_elem_set_callback(elem, mixer_elem_cb);
    154 	/* force the callback the first time around */
    155 	r = mixer_elem_cb(elem, 0);
    156 	if (r < 0)
    157 		goto out;
    158 readvol:
    159 	r = snd_mixer_poll_descriptors(mixerp, pfd, LEN(pfd));
    160 	if (r < 0) {
    161 		warnx("snd_mixer_poll_descriptors: %s", snd_strerror(r));
    162 		goto out;
    163 	}
    164 	r = snd_mixer_handle_events(mixerp);
    165 	if (r < 0) {
    166 		warnx("snd_mixer_handle_events: %s", snd_strerror(r));
    167 		goto out;
    168 	}
    169 	if (active)
    170 		snprintf(buf, len, "%d%%", master);
    171 	else
    172 		snprintf(buf, len, "!%d%%", master);
    173 	return 0;
    174 out:
    175 	snd_mixer_free(mixerp);
    176 	snd_mixer_close(mixerp);
    177 	mixerp = NULL;
    178 	return -1;
    179 }
    180 #elif __linux__ && USE_TINYALSA
    181 #include <tinyalsa/asoundlib.h>
    182 
    183 int
    184 mixread(void *arg, char *buf, size_t len)
    185 {
    186 	static struct mixer	*mixer;
    187 	struct mixer_ctl	*ctl;
    188 	int			 cur, max;
    189 
    190 	if (mixer == NULL && (mixer = mixer_open(0)) == NULL) {
    191 		warnx("mixer_open() failed");
    192 		return -1;
    193 	}
    194 
    195 	if ((ctl = mixer_get_ctl_by_name(mixer, "Master Playback Switch"))
    196 	    == NULL) {
    197 		warnx("mixer_get_ctl_by_name() failed");
    198 		goto out;
    199 	}
    200 	if (!mixer_ctl_get_value(ctl, 0)) {
    201 		snprintf(buf, len, "mute");
    202 		return 0;
    203 	}
    204 
    205 	if ((ctl = mixer_get_ctl_by_name(mixer, "Master Playback Volume"))
    206 	    == NULL) {
    207 		warnx("mixer_get_ctl_by_name() failed");
    208 		goto out;
    209 	}
    210 
    211 	cur = mixer_ctl_get_value(ctl, 0);
    212 	max = mixer_ctl_get_range_max(ctl);
    213 	snprintf(buf, len, "%d%%", cur * 100 / max);
    214 	return 0;
    215 
    216 out:
    217 	mixer_close(mixer);
    218 	mixer = NULL;
    219 	return -1;
    220 }
    221 #endif