4 * Specially written for Malcolm Davenport, but I think I'll use it too
6 * Copyright (C) 2004 - 2005, Digium Inc.
8 * Mark Spencer <markster@digium.com>
10 * Distributed under the terms of the GNU General Public License version 2.0
13 #include <linux/soundcard.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
26 static char *config = "/etc/muted.conf";
28 static char host[256] = "";
29 static char user[256] = "";
30 static char pass[256] = "";
31 static int smoothfade = 0;
32 static int mutelevel = 20;
34 static int needfork = 1;
36 static int stepsize = 3;
37 static int mixchan = SOUND_MIXER_VOLUME;
41 struct subchannel *next;
44 static struct channel {
48 struct subchannel *subs;
51 static void add_channel(char *tech, char *location)
54 chan = malloc(sizeof(struct channel));
56 memset(chan, 0, sizeof(struct channel));
57 chan->tech = strdup(tech);
58 chan->location = strdup(location);
59 chan->next = channels;
65 static int load_config(void)
73 f = fopen(config, "r");
75 fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
79 fgets(buf, sizeof(buf), f);
82 val = strchr(buf, '#');
84 while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
85 buf[strlen(buf) - 1] = '\0';
97 while(*val && (*val < 33)) val++;
99 if (!strcasecmp(buf, "host")) {
100 if (val && strlen(val))
101 strncpy(host, val, sizeof(host) - 1);
103 fprintf(stderr, "host needs an argument (the host) at line %d\n", lineno);
104 } else if (!strcasecmp(buf, "user")) {
105 if (val && strlen(val))
106 strncpy(user, val, sizeof(user) - 1);
108 fprintf(stderr, "user needs an argument (the user) at line %d\n", lineno);
109 } else if (!strcasecmp(buf, "pass")) {
110 if (val && strlen(val))
111 strncpy(pass, val, sizeof(pass) - 1);
113 fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
114 } else if (!strcasecmp(buf, "smoothfade")) {
116 } else if (!strcasecmp(buf, "mutelevel")) {
117 if (val && (sscanf(val, "%d", &x) == 1) && (x > -1) && (x < 101)) {
120 fprintf(stderr, "mutelevel must be a number from 0 (most muted) to 100 (no mute) at line %d\n", lineno);
121 } else if (!strcasecmp(buf, "channel")) {
122 if (val && strlen(val)) {
123 val2 = strchr(val, '/');
127 add_channel(val, val2);
129 fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
131 fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
133 fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
139 fprintf(stderr, "no 'host' specification in config file\n");
140 else if (!strlen(user))
141 fprintf(stderr, "no 'user' specification in config file\n");
143 fprintf(stderr, "no 'channel' specifications in config file\n");
153 static int open_mixer(void)
155 mixfd = open("/dev/mixer", O_RDWR);
157 fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
163 static int connect_asterisk(void)
169 struct sockaddr_in sin;
170 ports = strchr(host, ':');
174 if ((sscanf(ports, "%d", &port) != 1) || (port < 1) || (port > 65535)) {
175 fprintf(stderr, "'%s' is not a valid port number in the hostname\n", ports);
179 hp = gethostbyname(host);
181 fprintf(stderr, "Can't find host '%s'\n", host);
184 sock = socket(AF_INET, SOCK_STREAM, 0);
186 fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
189 sin.sin_family = AF_INET;
190 sin.sin_port = htons(port);
191 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
192 if (connect(sock, &sin, sizeof(sin))) {
193 fprintf(stderr, "Failed to connect to '%s' port '%d': %s\n", host, port, strerror(errno));
197 astf = fdopen(sock, "r+");
199 fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
206 static char *get_line(void)
208 static char buf[1024];
209 if (fgets(buf, sizeof(buf), astf)) {
210 while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
211 buf[strlen(buf) - 1] = '\0';
217 static int login_asterisk(void)
221 if (!(welcome = get_line())) {
222 fprintf(stderr, "disconnected (1)\n");
228 "Secret: %s\r\n\r\n", user, pass);
229 if (!(welcome = get_line())) {
230 fprintf(stderr, "disconnected (2)\n");
233 if (strcasecmp(welcome, "Response: Success")) {
234 fprintf(stderr, "login failed ('%s')\n", welcome);
237 /* Eat the rest of the event */
238 while((resp = get_line()) && strlen(resp));
240 fprintf(stderr, "disconnected (3)\n");
244 "Action: Status\r\n\r\n");
245 if (!(welcome = get_line())) {
246 fprintf(stderr, "disconnected (4)\n");
249 if (strcasecmp(welcome, "Response: Success")) {
250 fprintf(stderr, "status failed ('%s')\n", welcome);
253 /* Eat the rest of the event */
254 while((resp = get_line()) && strlen(resp));
256 fprintf(stderr, "disconnected (5)\n");
262 static struct channel *find_channel(char *channel)
266 struct channel *chan;
267 strncpy(tmp, channel, sizeof(tmp) - 1);
268 s = strchr(tmp, '/');
277 printf("Searching for '%s' tech, '%s' location\n", tmp, s);
280 if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
282 printf("Found '%s'/'%s'\n", chan->tech, chan->location);
292 static int getvol(void)
295 if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
296 fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
302 static int setvol(int vol)
304 if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
305 fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
311 static int oldvol = 0;
312 static int mutevol = 0;
314 static int mutedlevel(int orig, int mutelevel)
318 l = (float)(mutelevel) * (float)(l) / 100.0;
319 r = (float)(mutelevel) * (float)(r) / 100.0;
323 static void mute(void)
334 for (x=start;x>=mutelevel;x-=stepsize) {
335 mutevol = mutedlevel(vol, x);
340 mutevol = mutedlevel(vol, mutelevel);
343 printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
347 static void unmute(void)
354 printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
355 if (vol == mutevol) {
360 for (x=start;x<100;x+=stepsize) {
361 mutevol = mutedlevel(oldvol, x);
368 printf("Whoops, it's already been changed!\n");
372 static void check_mute(void)
375 struct channel *chan;
384 if (offhook && !muted)
386 else if (!offhook && muted)
390 static void delete_sub(struct channel *chan, char *name)
392 struct subchannel *sub, *prev;
396 if (!strcasecmp(sub->name, name)) {
398 prev->next = sub->next;
400 chan->subs = sub->next;
410 static void append_sub(struct channel *chan, char *name)
412 struct subchannel *sub;
415 if (!strcasecmp(sub->name, name))
419 sub = malloc(sizeof(struct subchannel));
421 memset(sub, 0, sizeof(struct subchannel));
422 sub->name = strdup(name);
423 sub->next = chan->subs;
428 static void hangup_chan(char *channel)
430 struct channel *chan;
432 printf("Hangup '%s'\n", channel);
433 chan = find_channel(channel);
435 delete_sub(chan, channel);
439 static void offhook_chan(char *channel)
441 struct channel *chan;
443 printf("Offhook '%s'\n", channel);
444 chan = find_channel(channel);
446 append_sub(chan, channel);
450 static int wait_event(void)
454 char channel[120]="";
455 char oldname[120]="";
456 char newname[120]="";
459 fprintf(stderr, "disconnected (6)\n");
462 if (!strncasecmp(resp, "Event: ", strlen("Event: "))) {
463 strncpy(event, resp + strlen("Event: "), sizeof(event) - 1);
464 /* Consume the rest of the non-event */
465 while((resp = get_line()) && strlen(resp)) {
466 if (!strncasecmp(resp, "Channel: ", strlen("Channel: ")))
467 strncpy(channel, resp + strlen("Channel: "), sizeof(channel) - 1);
468 if (!strncasecmp(resp, "Newname: ", strlen("Newname: ")))
469 strncpy(newname, resp + strlen("Newname: "), sizeof(newname) - 1);
470 if (!strncasecmp(resp, "Oldname: ", strlen("Oldname: ")))
471 strncpy(oldname, resp + strlen("Oldname: "), sizeof(oldname) - 1);
473 if (strlen(channel)) {
474 if (!strcasecmp(event, "Hangup"))
475 hangup_chan(channel);
477 offhook_chan(channel);
479 if (strlen(newname) && strlen(oldname)) {
480 if (!strcasecmp(event, "Rename")) {
481 hangup_chan(oldname);
482 offhook_chan(newname);
486 /* Consume the rest of the non-event */
487 while((resp = get_line()) && strlen(resp));
490 fprintf(stderr, "disconnected (7)\n");
496 static void usage(void)
498 printf("Usage: muted [-f] [-d]\n"
499 " -f : Do not fork\n"
500 " -d : Debug (implies -f)\n");
503 int main(int argc, char *argv[])
506 while((x = getopt(argc, argv, "fhd")) > 0) {
526 if (connect_asterisk()) {
530 if (login_asterisk()) {
540 while(connect_asterisk()) {
543 if (login_asterisk()) {