1 /*
2  *
3  * Conky, a system monitor, based on torsmo
4  *
5  * Any original torsmo code is licensed under the BSD license
6  *
7  * All code written since the fork of torsmo is licensed under the GPL
8  *
9  * Please see COPYING for details
10  *
11  * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen
12  * Copyright (c) 2005-2021 Brenden Matthews, Philip Kovacs, et. al.
13  *	(see AUTHORS)
14  * All rights reserved.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  * You should have received a copy of the GNU General Public License
26  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27  *
28  */
29 
30 #include <ctype.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include "conky.h"
35 #include "logging.h"
36 #include "specials.h"
37 #include "text_object.h"
38 
39 #ifdef HAVE_LINUX_SOUNDCARD_H
40 #include <linux/soundcard.h>
41 #else
42 #ifdef __OpenBSD__
43 #include <soundcard.h>
44 #else
45 #include <sys/soundcard.h>
46 #endif /* __OpenBSD__ */
47 #endif /* HAVE_LINUX_SOUNDCARD_H */
48 
49 #if defined(__sun)
50 #include <stropts.h>
51 #include <unistd.h>
52 #endif
53 
54 #define MIXER_DEV "/dev/mixer"
55 
56 static int mixer_fd;
57 static const char *devs[] = SOUND_DEVICE_NAMES;
58 
mixer_init(const char * name)59 int mixer_init(const char *name) {
60   unsigned int i;
61 
62   if (name == 0 || name[0] == '\0') { name = "vol"; }
63 
64   /* open mixer */
65   if (mixer_fd <= 0) {
66     mixer_fd = open(MIXER_DEV, O_RDONLY);
67     if (mixer_fd == -1) {
68       NORM_ERR("can't open %s: %s", MIXER_DEV, strerror(errno));
69       return -1;
70     }
71   }
72 
73   for (i = 0; i < sizeof(devs) / sizeof(const char *); i++) {
74     if (strcasecmp(devs[i], name) == 0) { return i; }
75   }
76 
77   return -1;
78 }
79 
mixer_get(int i)80 static int mixer_get(int i) {
81   static char rep = 0;
82   int val = -1;
83 
84   if (ioctl(mixer_fd, MIXER_READ(i), &val) == -1) {
85     if (!rep) { NORM_ERR("mixer ioctl: %s", strerror(errno)); }
86     rep = 1;
87     return 0;
88   }
89   rep = 0;
90 
91   return val;
92 }
93 
mixer_get_avg(int i)94 static int mixer_get_avg(int i) {
95   int v = mixer_get(i);
96 
97   return ((v >> 8) + (v & 0xFF)) / 2;
98 }
99 
mixer_get_left(int i)100 static int mixer_get_left(int i) { return mixer_get(i) >> 8; }
101 
mixer_get_right(int i)102 static int mixer_get_right(int i) { return mixer_get(i) & 0xFF; }
mixer_is_mute(int i)103 int mixer_is_mute(int i) { return !mixer_get(i); }
104 
105 #define mixer_to_255(i, x) x
106 
parse_mixer_arg(struct text_object * obj,const char * arg)107 void parse_mixer_arg(struct text_object *obj, const char *arg) {
108   obj->data.l = mixer_init(arg);
109 }
110 
mixer_percentage(struct text_object * obj)111 uint8_t mixer_percentage(struct text_object *obj) {
112   return mixer_get_avg(obj->data.l);
113 }
114 
mixerl_percentage(struct text_object * obj)115 uint8_t mixerl_percentage(struct text_object *obj) {
116   return mixer_get_left(obj->data.l);
117 }
118 
mixerr_percentage(struct text_object * obj)119 uint8_t mixerr_percentage(struct text_object *obj) {
120   return mixer_get_right(obj->data.l);
121 }
122 
check_mixer_muted(struct text_object * obj)123 int check_mixer_muted(struct text_object *obj) {
124   if (!mixer_is_mute(obj->data.l)) return 0;
125   return 1;
126 }
127 
scan_mixer_bar(struct text_object * obj,const char * arg)128 void scan_mixer_bar(struct text_object *obj, const char *arg) {
129   char buf1[64];
130   int n;
131 
132   if (arg && sscanf(arg, "%63s %n", buf1, &n) >= 1) {
133     obj->data.i = mixer_init(buf1);
134     scan_bar(obj, arg + n, 100);
135   } else {
136     obj->data.i = mixer_init(nullptr);
137     scan_bar(obj, arg, 100);
138   }
139 }
140 
mixer_barval(struct text_object * obj)141 double mixer_barval(struct text_object *obj) {
142   return mixer_to_255(obj->data.i, mixer_get_avg(obj->data.i));
143 }
144 
mixerl_barval(struct text_object * obj)145 double mixerl_barval(struct text_object *obj) {
146   return mixer_to_255(obj->data.i, mixer_get_left(obj->data.i));
147 }
148 
mixerr_barval(struct text_object * obj)149 double mixerr_barval(struct text_object *obj) {
150   return mixer_to_255(obj->data.i, mixer_get_right(obj->data.i));
151 }
152