4
* Specially written for Malcolm Davenport, but I think I'll use it too
6
* Copyright (C) 2004, 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()) {