00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef __Darwin__
00033 #include <linux/soundcard.h>
00034 #else
00035 #include <CoreAudio/AudioHardware.h>
00036 #endif
00037 #include <stdio.h>
00038 #include <errno.h>
00039 #include <stdlib.h>
00040 #include <unistd.h>
00041 #include <fcntl.h>
00042 #include <string.h>
00043 #include <netdb.h>
00044 #include <sys/socket.h>
00045 #include <sys/ioctl.h>
00046 #include <netinet/in.h>
00047 #include <arpa/inet.h>
00048
00049 static char *config = "/etc/muted.conf";
00050
00051 static char host[256] = "";
00052 static char user[256] = "";
00053 static char pass[256] = "";
00054 static int smoothfade = 0;
00055 static int mutelevel = 20;
00056 static int muted = 0;
00057 static int needfork = 1;
00058 static int debug = 0;
00059 static int stepsize = 3;
00060 #ifndef __Darwin__
00061 static int mixchan = SOUND_MIXER_VOLUME;
00062 #endif
00063
00064 struct subchannel {
00065 char *name;
00066 struct subchannel *next;
00067 };
00068
00069 static struct channel {
00070 char *tech;
00071 char *location;
00072 struct channel *next;
00073 struct subchannel *subs;
00074 } *channels;
00075
00076 static void add_channel(char *tech, char *location)
00077 {
00078 struct channel *chan;
00079 chan = malloc(sizeof(struct channel));
00080 if (chan) {
00081 memset(chan, 0, sizeof(struct channel));
00082 chan->tech = strdup(tech);
00083 chan->location = strdup(location);
00084 chan->next = channels;
00085 channels = chan;
00086 }
00087
00088 }
00089
00090 static int load_config(void)
00091 {
00092 FILE *f;
00093 char buf[1024];
00094 char *val;
00095 char *val2;
00096 int lineno=0;
00097 int x;
00098 f = fopen(config, "r");
00099 if (!f) {
00100 fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
00101 return -1;
00102 }
00103 while(!feof(f)) {
00104 fgets(buf, sizeof(buf), f);
00105 if (!feof(f)) {
00106 lineno++;
00107 val = strchr(buf, '#');
00108 if (val) *val = '\0';
00109 while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
00110 buf[strlen(buf) - 1] = '\0';
00111 if (!strlen(buf))
00112 continue;
00113 val = buf;
00114 while(*val) {
00115 if (*val < 33)
00116 break;
00117 val++;
00118 }
00119 if (*val) {
00120 *val = '\0';
00121 val++;
00122 while(*val && (*val < 33)) val++;
00123 }
00124 if (!strcasecmp(buf, "host")) {
00125 if (val && strlen(val))
00126 strncpy(host, val, sizeof(host) - 1);
00127 else
00128 fprintf(stderr, "host needs an argument (the host) at line %d\n", lineno);
00129 } else if (!strcasecmp(buf, "user")) {
00130 if (val && strlen(val))
00131 strncpy(user, val, sizeof(user) - 1);
00132 else
00133 fprintf(stderr, "user needs an argument (the user) at line %d\n", lineno);
00134 } else if (!strcasecmp(buf, "pass")) {
00135 if (val && strlen(val))
00136 strncpy(pass, val, sizeof(pass) - 1);
00137 else
00138 fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
00139 } else if (!strcasecmp(buf, "smoothfade")) {
00140 smoothfade = 1;
00141 } else if (!strcasecmp(buf, "mutelevel")) {
00142 if (val && (sscanf(val, "%d", &x) == 1) && (x > -1) && (x < 101)) {
00143 mutelevel = x;
00144 } else
00145 fprintf(stderr, "mutelevel must be a number from 0 (most muted) to 100 (no mute) at line %d\n", lineno);
00146 } else if (!strcasecmp(buf, "channel")) {
00147 if (val && strlen(val)) {
00148 val2 = strchr(val, '/');
00149 if (val2) {
00150 *val2 = '\0';
00151 val2++;
00152 add_channel(val, val2);
00153 } else
00154 fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
00155 } else
00156 fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
00157 } else {
00158 fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
00159 }
00160 }
00161 }
00162 fclose(f);
00163 if (!strlen(host))
00164 fprintf(stderr, "no 'host' specification in config file\n");
00165 else if (!strlen(user))
00166 fprintf(stderr, "no 'user' specification in config file\n");
00167 else if (!channels)
00168 fprintf(stderr, "no 'channel' specifications in config file\n");
00169 else
00170 return 0;
00171 return -1;
00172 }
00173
00174 static FILE *astf;
00175 #ifndef __Darwin__
00176 static int mixfd;
00177
00178 static int open_mixer(void)
00179 {
00180 mixfd = open("/dev/mixer", O_RDWR);
00181 if (mixfd < 0) {
00182 fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
00183 return -1;
00184 }
00185 return 0;
00186 }
00187 #endif
00188
00189
00190 static int connect_asterisk(void)
00191 {
00192 int sock;
00193 struct hostent *hp;
00194 char *ports;
00195 int port = 5038;
00196 struct sockaddr_in sin;
00197
00198 ports = strchr(host, ':');
00199 if (ports) {
00200 *ports = '\0';
00201 ports++;
00202 if ((sscanf(ports, "%d", &port) != 1) || (port < 1) || (port > 65535)) {
00203 fprintf(stderr, "'%s' is not a valid port number in the hostname\n", ports);
00204 return -1;
00205 }
00206 }
00207 hp = gethostbyname(host);
00208 if (!hp) {
00209 fprintf(stderr, "Can't find host '%s'\n", host);
00210 return -1;
00211 }
00212 sock = socket(AF_INET, SOCK_STREAM, 0);
00213 if (sock < 0) {
00214 fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
00215 return -1;
00216 }
00217 sin.sin_family = AF_INET;
00218 sin.sin_port = htons(port);
00219 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
00220 if (connect(sock, &sin, sizeof(sin))) {
00221 fprintf(stderr, "Failed to connect to '%s' port '%d': %s\n", host, port, strerror(errno));
00222 close(sock);
00223 return -1;
00224 }
00225 astf = fdopen(sock, "r+");
00226 if (!astf) {
00227 fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
00228 close(sock);
00229 return -1;
00230 }
00231 return 0;
00232 }
00233
00234 static char *get_line(void)
00235 {
00236 static char buf[1024];
00237 if (fgets(buf, sizeof(buf), astf)) {
00238 while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
00239 buf[strlen(buf) - 1] = '\0';
00240 return buf;
00241 } else
00242 return NULL;
00243 }
00244
00245
00246 static int login_asterisk(void)
00247 {
00248 char *welcome;
00249 char *resp;
00250 if (!(welcome = get_line())) {
00251 fprintf(stderr, "disconnected (1)\n");
00252 return -1;
00253 }
00254 fprintf(astf,
00255 "Action: Login\r\n"
00256 "Username: %s\r\n"
00257 "Secret: %s\r\n\r\n", user, pass);
00258 if (!(welcome = get_line())) {
00259 fprintf(stderr, "disconnected (2)\n");
00260 return -1;
00261 }
00262 if (strcasecmp(welcome, "Response: Success")) {
00263 fprintf(stderr, "login failed ('%s')\n", welcome);
00264 return -1;
00265 }
00266
00267 while((resp = get_line()) && strlen(resp));
00268 if (!resp) {
00269 fprintf(stderr, "disconnected (3)\n");
00270 return -1;
00271 }
00272 fprintf(astf,
00273 "Action: Status\r\n\r\n");
00274 if (!(welcome = get_line())) {
00275 fprintf(stderr, "disconnected (4)\n");
00276 return -1;
00277 }
00278 if (strcasecmp(welcome, "Response: Success")) {
00279 fprintf(stderr, "status failed ('%s')\n", welcome);
00280 return -1;
00281 }
00282
00283 while((resp = get_line()) && strlen(resp));
00284 if (!resp) {
00285 fprintf(stderr, "disconnected (5)\n");
00286 return -1;
00287 }
00288 return 0;
00289 }
00290
00291 static struct channel *find_channel(char *channel)
00292 {
00293 char tmp[256] = "";
00294 char *s, *t;
00295 struct channel *chan;
00296 strncpy(tmp, channel, sizeof(tmp) - 1);
00297 s = strchr(tmp, '/');
00298 if (s) {
00299 *s = '\0';
00300 s++;
00301 t = strrchr(s, '-');
00302 if (t) {
00303 *t = '\0';
00304 }
00305 if (debug)
00306 printf("Searching for '%s' tech, '%s' location\n", tmp, s);
00307 chan = channels;
00308 while(chan) {
00309 if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
00310 if (debug)
00311 printf("Found '%s'/'%s'\n", chan->tech, chan->location);
00312 break;
00313 }
00314 chan = chan->next;
00315 }
00316 } else
00317 chan = NULL;
00318 return chan;
00319 }
00320
00321 #ifndef __Darwin__
00322 static int getvol(void)
00323 {
00324 int vol;
00325
00326 if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
00327 #else
00328 static float getvol(void)
00329 {
00330 float volumeL, volumeR, vol;
00331 OSStatus err;
00332 AudioDeviceID device;
00333 UInt32 size;
00334 UInt32 channels[2];
00335
00336 size = sizeof(device);
00337 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
00338 size = sizeof(channels);
00339 if (!err)
00340 err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
00341 size = sizeof(vol);
00342 if (!err)
00343 err = AudioDeviceGetProperty(device, channels[0], false, kAudioDevicePropertyVolumeScalar, &size, &volumeL);
00344 if (!err)
00345 err = AudioDeviceGetProperty(device, channels[1], false, kAudioDevicePropertyVolumeScalar, &size, &volumeR);
00346 if (!err)
00347 vol = (volumeL < volumeR) ? volumeR : volumeL;
00348 else {
00349 #endif
00350 fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
00351 return -1;
00352 }
00353 return vol;
00354 }
00355
00356 #ifndef __Darwin__
00357 static int setvol(int vol)
00358 #else
00359 static int setvol(float vol)
00360 #endif
00361 {
00362 #ifndef __Darwin__
00363 if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
00364 #else
00365 float volumeL = vol;
00366 float volumeR = vol;
00367 OSStatus err;
00368 AudioDeviceID device;
00369 UInt32 size;
00370 UInt32 channels[2];
00371
00372 size = sizeof(device);
00373 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
00374 size = sizeof(channels);
00375 err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
00376 size = sizeof(vol);
00377 if (!err)
00378 err = AudioDeviceSetProperty(device, 0, channels[0], false, kAudioDevicePropertyVolumeScalar, size, &volumeL);
00379 if (!err)
00380 err = AudioDeviceSetProperty(device, 0, channels[1], false, kAudioDevicePropertyVolumeScalar, size, &volumeR);
00381 if (err) {
00382 #endif
00383
00384 fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
00385 return -1;
00386
00387 }
00388 return 0;
00389 }
00390
00391 #ifndef __Darwin__
00392 static int oldvol = 0;
00393 static int mutevol = 0;
00394 #else
00395 static float oldvol = 0;
00396 static float mutevol = 0;
00397 #endif
00398
00399 #ifndef __Darwin__
00400 static int mutedlevel(int orig, int mutelevel)
00401 {
00402 int l = orig >> 8;
00403 int r = orig & 0xff;
00404 l = (float)(mutelevel) * (float)(l) / 100.0;
00405 r = (float)(mutelevel) * (float)(r) / 100.0;
00406
00407 return (l << 8) | r;
00408 #else
00409 static float mutedlevel(float orig, float mutelevel)
00410 {
00411 float master = orig;
00412 master = mutelevel * master / 100.0;
00413 return master;
00414 #endif
00415
00416 }
00417
00418 static void mute(void)
00419 {
00420 #ifndef __Darwin__
00421 int vol;
00422 int start;
00423 int x;
00424 #else
00425 float vol;
00426 float start = 1.0;
00427 float x;
00428 #endif
00429 vol = getvol();
00430 oldvol = vol;
00431 if (smoothfade)
00432 #ifdef __Darwin__
00433 start = mutelevel;
00434 #else
00435 start = 100;
00436 else
00437 start = mutelevel;
00438 #endif
00439 for (x=start;x>=mutelevel;x-=stepsize) {
00440 mutevol = mutedlevel(vol, x);
00441 setvol(mutevol);
00442
00443 usleep(10000);
00444 }
00445 mutevol = mutedlevel(vol, mutelevel);
00446 setvol(mutevol);
00447 if (debug)
00448 #ifdef __Darwin__
00449 printf("Mute from '%f' to '%f'!\n", oldvol, mutevol);
00450 #else
00451 printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
00452 #endif
00453 muted = 1;
00454 }
00455
00456 static void unmute(void)
00457 {
00458 #ifdef __Darwin__
00459 float vol;
00460 float start;
00461 float x;
00462 #else
00463 int vol;
00464 int start;
00465 int x;
00466 #endif
00467 vol = getvol();
00468 if (debug)
00469 #ifdef __Darwin__
00470 printf("Unmute from '%f' (should be '%f') to '%f'!\n", vol, mutevol, oldvol);
00471 mutevol = vol;
00472 if (vol == mutevol) {
00473 #else
00474 printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
00475 if ((int)vol == mutevol) {
00476 #endif
00477 if (smoothfade)
00478 start = mutelevel;
00479 else
00480 #ifdef __Darwin__
00481 start = 1.0;
00482 #else
00483 start = 100;
00484 #endif
00485 for (x=start;x<100;x+=stepsize) {
00486 mutevol = mutedlevel(oldvol, x);
00487 setvol(mutevol);
00488
00489 usleep(10000);
00490 }
00491 setvol(oldvol);
00492 } else
00493 printf("Whoops, it's already been changed!\n");
00494 muted = 0;
00495 }
00496
00497 static void check_mute(void)
00498 {
00499 int offhook = 0;
00500 struct channel *chan;
00501 chan = channels;
00502 while(chan) {
00503 if (chan->subs) {
00504 offhook++;
00505 break;
00506 }
00507 chan = chan->next;
00508 }
00509 if (offhook && !muted)
00510 mute();
00511 else if (!offhook && muted)
00512 unmute();
00513 }
00514
00515 static void delete_sub(struct channel *chan, char *name)
00516 {
00517 struct subchannel *sub, *prev;
00518 prev = NULL;
00519 sub = chan->subs;
00520 while(sub) {
00521 if (!strcasecmp(sub->name, name)) {
00522 if (prev)
00523 prev->next = sub->next;
00524 else
00525 chan->subs = sub->next;
00526 free(sub->name);
00527 free(sub);
00528 return;
00529 }
00530 prev = sub;
00531 sub = sub->next;
00532 }
00533 }
00534
00535 static void append_sub(struct channel *chan, char *name)
00536 {
00537 struct subchannel *sub;
00538 sub = chan->subs;
00539 while(sub) {
00540 if (!strcasecmp(sub->name, name))
00541 return;
00542 sub = sub->next;
00543 }
00544 sub = malloc(sizeof(struct subchannel));
00545 if (sub) {
00546 memset(sub, 0, sizeof(struct subchannel));
00547 sub->name = strdup(name);
00548 sub->next = chan->subs;
00549 chan->subs = sub;
00550 }
00551 }
00552
00553 static void hangup_chan(char *channel)
00554 {
00555 struct channel *chan;
00556 if (debug)
00557 printf("Hangup '%s'\n", channel);
00558 chan = find_channel(channel);
00559 if (chan)
00560 delete_sub(chan, channel);
00561 check_mute();
00562 }
00563
00564 static void offhook_chan(char *channel)
00565 {
00566 struct channel *chan;
00567 if (debug)
00568 printf("Offhook '%s'\n", channel);
00569 chan = find_channel(channel);
00570 if (chan)
00571 append_sub(chan, channel);
00572 check_mute();
00573 }
00574
00575 static int wait_event(void)
00576 {
00577 char *resp;
00578 char event[120]="";
00579 char channel[120]="";
00580 char oldname[120]="";
00581 char newname[120]="";
00582
00583 resp = get_line();
00584 if (!resp) {
00585 fprintf(stderr, "disconnected (6)\n");
00586 return -1;
00587 }
00588 if (!strncasecmp(resp, "Event: ", strlen("Event: "))) {
00589 strncpy(event, resp + strlen("Event: "), sizeof(event) - 1);
00590
00591 while((resp = get_line()) && strlen(resp)) {
00592 if (!strncasecmp(resp, "Channel: ", strlen("Channel: ")))
00593 strncpy(channel, resp + strlen("Channel: "), sizeof(channel) - 1);
00594 if (!strncasecmp(resp, "Newname: ", strlen("Newname: ")))
00595 strncpy(newname, resp + strlen("Newname: "), sizeof(newname) - 1);
00596 if (!strncasecmp(resp, "Oldname: ", strlen("Oldname: ")))
00597 strncpy(oldname, resp + strlen("Oldname: "), sizeof(oldname) - 1);
00598 }
00599 if (strlen(channel)) {
00600 if (!strcasecmp(event, "Hangup"))
00601 hangup_chan(channel);
00602 else
00603 offhook_chan(channel);
00604 }
00605 if (strlen(newname) && strlen(oldname)) {
00606 if (!strcasecmp(event, "Rename")) {
00607 hangup_chan(oldname);
00608 offhook_chan(newname);
00609 }
00610 }
00611 } else {
00612
00613 while((resp = get_line()) && strlen(resp));
00614 }
00615 if (!resp) {
00616 fprintf(stderr, "disconnected (7)\n");
00617 return -1;
00618 }
00619 return 0;
00620 }
00621
00622 static void usage(void)
00623 {
00624 printf("Usage: muted [-f] [-d]\n"
00625 " -f : Do not fork\n"
00626 " -d : Debug (implies -f)\n");
00627 }
00628
00629 int main(int argc, char *argv[])
00630 {
00631 int x;
00632 while((x = getopt(argc, argv, "fhd")) > 0) {
00633 switch(x) {
00634 case 'd':
00635 debug = 1;
00636 needfork = 0;
00637 break;
00638 case 'f':
00639 needfork = 0;
00640 break;
00641 case 'h':
00642
00643 default:
00644 usage();
00645 exit(1);
00646 }
00647 }
00648 if (load_config())
00649 exit(1);
00650 #ifndef __Darwin__
00651 if (open_mixer())
00652 exit(1);
00653 #endif
00654 if (connect_asterisk()) {
00655 #ifndef __Darwin__
00656 close(mixfd);
00657 #endif
00658 exit(1);
00659 }
00660 if (login_asterisk()) {
00661 #ifndef __Darwin__
00662 close(mixfd);
00663 #endif
00664 fclose(astf);
00665 exit(1);
00666 }
00667 if (needfork)
00668 daemon(0,0);
00669 for(;;) {
00670 if (wait_event()) {
00671 fclose(astf);
00672 while(connect_asterisk()) {
00673 sleep(5);
00674 }
00675 if (login_asterisk()) {
00676 fclose(astf);
00677 exit(1);
00678 }
00679 }
00680 }
00681 exit(0);
00682 }