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