~davewalker/ubuntu/maverick/asterisk/lp_705014

« back to all changes in this revision

Viewing changes to muted.c

  • Committer: Bazaar Package Importer
  • Author(s): Kilian Krause
  • Date: 2005-03-09 22:09:05 UTC
  • mto: (1.2.1 upstream) (8.2.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050309220905-9afy6hcpw96xbr6j
Tags: upstream-1.0.6
ImportĀ upstreamĀ versionĀ 1.0.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Mute Daemon
 
3
 *
 
4
 * Specially written for Malcolm Davenport, but I think I'll use it too
 
5
 *
 
6
 * Copyright (C) 2004, Digium Inc.
 
7
 *
 
8
 * Mark Spencer <markster@digium.com>
 
9
 *
 
10
 * Distributed under the terms of the GNU General Public License version 2.0 
 
11
 *
 
12
 */
 
13
#include <linux/soundcard.h>
 
14
#include <stdio.h>
 
15
#include <errno.h>
 
16
#include <stdlib.h>
 
17
#include <unistd.h>
 
18
#include <fcntl.h>
 
19
#include <string.h>
 
20
#include <netdb.h>
 
21
#include <sys/socket.h>
 
22
#include <sys/ioctl.h>
 
23
#include <netinet/in.h>
 
24
#include <arpa/inet.h>
 
25
 
 
26
static char *config = "/etc/muted.conf";
 
27
 
 
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;
 
33
static int muted = 0;
 
34
static int needfork = 1;
 
35
static int debug = 0;
 
36
static int stepsize = 3;
 
37
static int mixchan = SOUND_MIXER_VOLUME;
 
38
 
 
39
struct subchannel {
 
40
        char *name;
 
41
        struct subchannel *next;
 
42
};
 
43
 
 
44
static struct channel {
 
45
        char *tech;
 
46
        char *location;
 
47
        struct channel *next;
 
48
        struct subchannel *subs;
 
49
} *channels;
 
50
 
 
51
static void add_channel(char *tech, char *location)
 
52
{
 
53
        struct channel *chan;
 
54
        chan = malloc(sizeof(struct channel));
 
55
        if (chan) {
 
56
                memset(chan, 0, sizeof(struct channel));
 
57
                chan->tech = strdup(tech);
 
58
                chan->location = strdup(location);
 
59
                chan->next = channels;
 
60
                channels = chan;
 
61
        }
 
62
        
 
63
}
 
64
 
 
65
static int load_config(void)
 
66
{
 
67
        FILE *f;
 
68
        char buf[1024];
 
69
        char *val;
 
70
        char *val2;
 
71
        int lineno=0;
 
72
        int x;
 
73
        f = fopen(config, "r");
 
74
        if (!f) {
 
75
                fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
 
76
                return -1;
 
77
        }
 
78
        while(!feof(f)) {
 
79
                fgets(buf, sizeof(buf), f);
 
80
                if (!feof(f)) {
 
81
                        lineno++;
 
82
                        val = strchr(buf, '#');
 
83
                        if (val) *val = '\0';
 
84
                        while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
 
85
                                buf[strlen(buf) - 1] = '\0';
 
86
                        if (!strlen(buf))
 
87
                                continue;
 
88
                        val = buf;
 
89
                        while(*val) {
 
90
                                if (*val < 33)
 
91
                                        break;
 
92
                                val++;
 
93
                        }
 
94
                        if (*val) {
 
95
                                *val = '\0';
 
96
                                val++;
 
97
                                while(*val && (*val < 33)) val++;
 
98
                        }
 
99
                        if (!strcasecmp(buf, "host")) {
 
100
                                if (val && strlen(val))
 
101
                                        strncpy(host, val, sizeof(host) - 1);
 
102
                                else
 
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);
 
107
                                else
 
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);
 
112
                                else
 
113
                                        fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
 
114
                        } else if (!strcasecmp(buf, "smoothfade")) {
 
115
                                smoothfade = 1;
 
116
                        } else if (!strcasecmp(buf, "mutelevel")) {
 
117
                                if (val && (sscanf(val, "%d", &x) == 1) && (x > -1) && (x < 101)) {
 
118
                                        mutelevel = x;
 
119
                                } else 
 
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, '/');
 
124
                                        if (val2) {
 
125
                                                *val2 = '\0';
 
126
                                                val2++;
 
127
                                                add_channel(val, val2);
 
128
                                        } else
 
129
                                                fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
 
130
                                } else
 
131
                                        fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
 
132
                        } else {
 
133
                                fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
 
134
                        }
 
135
                }
 
136
        }
 
137
        fclose(f);
 
138
        if (!strlen(host))
 
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");
 
142
        else if (!channels) 
 
143
                fprintf(stderr, "no 'channel' specifications in config file\n");
 
144
        else
 
145
                return 0;
 
146
        return -1;
 
147
}
 
148
 
 
149
static FILE *astf;
 
150
 
 
151
static int mixfd;
 
152
 
 
153
static int open_mixer(void)
 
154
{
 
155
        mixfd = open("/dev/mixer", O_RDWR);
 
156
        if (mixfd < 0) {
 
157
                fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
 
158
                return -1;
 
159
        }
 
160
        return 0;
 
161
}
 
162
 
 
163
static int connect_asterisk(void)
 
164
{
 
165
        int sock;
 
166
        struct hostent *hp;
 
167
        char *ports;
 
168
        int port = 5038;
 
169
        struct sockaddr_in sin;
 
170
        ports = strchr(host, ':');
 
171
        if (ports) {
 
172
                *ports = '\0';
 
173
                ports++;
 
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);
 
176
                        return -1;
 
177
                }
 
178
        }
 
179
        hp = gethostbyname(host);
 
180
        if (!hp) {
 
181
                fprintf(stderr, "Can't find host '%s'\n", host);
 
182
                return -1;
 
183
        }
 
184
        sock = socket(AF_INET, SOCK_STREAM, 0);
 
185
        if (sock < 0) {
 
186
                fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
 
187
                return -1;
 
188
        }
 
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));
 
194
                close(sock);
 
195
                return -1;
 
196
        }
 
197
        astf = fdopen(sock, "r+");
 
198
        if (!astf) {
 
199
                fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
 
200
                close(sock);
 
201
                return -1;
 
202
        }
 
203
        return 0;
 
204
}
 
205
 
 
206
static char *get_line(void)
 
207
{
 
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';
 
212
                return buf;
 
213
        } else
 
214
                return NULL;
 
215
}
 
216
 
 
217
static int login_asterisk(void)
 
218
{
 
219
        char *welcome;
 
220
        char *resp;
 
221
        if (!(welcome = get_line())) {
 
222
                fprintf(stderr, "disconnected (1)\n");
 
223
                return -1;
 
224
        }
 
225
        fprintf(astf, 
 
226
                "Action: Login\r\n"
 
227
                "Username: %s\r\n"
 
228
                "Secret: %s\r\n\r\n", user, pass);
 
229
        if (!(welcome = get_line())) {
 
230
                fprintf(stderr, "disconnected (2)\n");
 
231
                return -1;
 
232
        }
 
233
        if (strcasecmp(welcome, "Response: Success")) {
 
234
                fprintf(stderr, "login failed ('%s')\n", welcome);
 
235
                return -1;
 
236
        }
 
237
        /* Eat the rest of the event */
 
238
        while((resp = get_line()) && strlen(resp));
 
239
        if (!resp) {
 
240
                fprintf(stderr, "disconnected (3)\n");
 
241
                return -1;
 
242
        }
 
243
        fprintf(astf, 
 
244
                "Action: Status\r\n\r\n");
 
245
        if (!(welcome = get_line())) {
 
246
                fprintf(stderr, "disconnected (4)\n");
 
247
                return -1;
 
248
        }
 
249
        if (strcasecmp(welcome, "Response: Success")) {
 
250
                fprintf(stderr, "status failed ('%s')\n", welcome);
 
251
                return -1;
 
252
        }
 
253
        /* Eat the rest of the event */
 
254
        while((resp = get_line()) && strlen(resp));
 
255
        if (!resp) {
 
256
                fprintf(stderr, "disconnected (5)\n");
 
257
                return -1;
 
258
        }
 
259
        return 0;
 
260
}
 
261
 
 
262
static struct channel *find_channel(char *channel)
 
263
{
 
264
        char tmp[256] = "";
 
265
        char *s, *t;
 
266
        struct channel *chan;
 
267
        strncpy(tmp, channel, sizeof(tmp) - 1);
 
268
        s = strchr(tmp, '/');
 
269
        if (s) {
 
270
                *s = '\0';
 
271
                s++;
 
272
                t = strrchr(s, '-');
 
273
                if (t) {
 
274
                        *t = '\0';
 
275
                }
 
276
                if (debug)
 
277
                        printf("Searching for '%s' tech, '%s' location\n", tmp, s);
 
278
                chan = channels;
 
279
                while(chan) {
 
280
                        if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
 
281
                                if (debug)
 
282
                                        printf("Found '%s'/'%s'\n", chan->tech, chan->location);
 
283
                                break;
 
284
                        }
 
285
                        chan = chan->next;
 
286
                }
 
287
        } else
 
288
                chan = NULL;
 
289
        return chan;
 
290
}
 
291
 
 
292
static int getvol(void)
 
293
{
 
294
        int vol;
 
295
        if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
 
296
                fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
 
297
                return -1;
 
298
        }
 
299
        return vol;
 
300
}
 
301
 
 
302
static int setvol(int vol)
 
303
{
 
304
        if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
 
305
                fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
 
306
                return -1;
 
307
        }
 
308
        return 0;
 
309
}
 
310
 
 
311
static int oldvol = 0;
 
312
static int mutevol = 0;
 
313
 
 
314
static int mutedlevel(int orig, int mutelevel)
 
315
{
 
316
        int l = orig >> 8;
 
317
        int r = orig & 0xff;
 
318
        l = (float)(mutelevel) * (float)(l) / 100.0;
 
319
        r = (float)(mutelevel) * (float)(r) / 100.0;
 
320
        return (l << 8) | r;
 
321
}
 
322
 
 
323
static void mute(void)
 
324
{
 
325
        int vol;
 
326
        int start;
 
327
        int x;
 
328
        vol = getvol();
 
329
        oldvol = vol;
 
330
        if (smoothfade) 
 
331
                start = 100;
 
332
        else
 
333
                start = mutelevel;
 
334
        for (x=start;x>=mutelevel;x-=stepsize) {
 
335
                mutevol = mutedlevel(vol, x);
 
336
                setvol(mutevol);
 
337
                /* Wait 0.01 sec */
 
338
                usleep(10000);
 
339
        }
 
340
        mutevol = mutedlevel(vol, mutelevel);
 
341
        setvol(mutevol);
 
342
        if (debug)
 
343
                printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
 
344
        muted = 1;
 
345
}
 
346
 
 
347
static void unmute(void)
 
348
{
 
349
        int vol;
 
350
        int start;
 
351
        int x;
 
352
        vol = getvol();
 
353
        if (debug)
 
354
                printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
 
355
        if (vol == mutevol) {
 
356
                if (smoothfade)
 
357
                        start = mutelevel;
 
358
                else
 
359
                        start = 100;
 
360
                for (x=start;x<100;x+=stepsize) {
 
361
                        mutevol = mutedlevel(oldvol, x);
 
362
                        setvol(mutevol);
 
363
                        /* Wait 0.01 sec */
 
364
                        usleep(10000);
 
365
                }
 
366
                setvol(oldvol);
 
367
        } else
 
368
                printf("Whoops, it's already been changed!\n");
 
369
        muted = 0;
 
370
}
 
371
 
 
372
static void check_mute(void)
 
373
{
 
374
        int offhook = 0;
 
375
        struct channel *chan;
 
376
        chan = channels;
 
377
        while(chan) {
 
378
                if (chan->subs) {
 
379
                        offhook++;
 
380
                        break;
 
381
                }
 
382
                chan = chan->next;
 
383
        }
 
384
        if (offhook && !muted)
 
385
                mute();
 
386
        else if (!offhook && muted)
 
387
                unmute();
 
388
}
 
389
 
 
390
static void delete_sub(struct channel *chan, char *name)
 
391
{
 
392
        struct subchannel *sub, *prev;
 
393
        prev = NULL;
 
394
        sub = chan->subs;
 
395
        while(sub) {
 
396
                if (!strcasecmp(sub->name, name)) {
 
397
                        if (prev)
 
398
                                prev->next = sub->next;
 
399
                        else
 
400
                                chan->subs = sub->next;
 
401
                        free(sub->name);
 
402
                        free(sub);
 
403
                        return;
 
404
                }
 
405
                prev = sub;
 
406
                sub = sub->next;
 
407
        }
 
408
}
 
409
 
 
410
static void append_sub(struct channel *chan, char *name)
 
411
{
 
412
        struct subchannel *sub;
 
413
        sub = chan->subs;
 
414
        while(sub) {
 
415
                if (!strcasecmp(sub->name, name)) 
 
416
                        return;
 
417
                sub = sub->next;
 
418
        }
 
419
        sub = malloc(sizeof(struct subchannel));
 
420
        if (sub) {
 
421
                memset(sub, 0, sizeof(struct subchannel));
 
422
                sub->name = strdup(name);
 
423
                sub->next = chan->subs;
 
424
                chan->subs = sub;
 
425
        }
 
426
}
 
427
 
 
428
static void hangup_chan(char *channel)
 
429
{
 
430
        struct channel *chan;
 
431
        if (debug)
 
432
                printf("Hangup '%s'\n", channel);
 
433
        chan = find_channel(channel);
 
434
        if (chan)
 
435
                delete_sub(chan, channel);
 
436
        check_mute();
 
437
}
 
438
 
 
439
static void offhook_chan(char *channel)
 
440
{
 
441
        struct channel *chan;
 
442
        if (debug)
 
443
                printf("Offhook '%s'\n", channel);
 
444
        chan = find_channel(channel);
 
445
        if (chan)
 
446
                append_sub(chan, channel);
 
447
        check_mute();
 
448
}
 
449
 
 
450
static int wait_event(void)
 
451
{
 
452
        char *resp;
 
453
        char event[120]="";
 
454
        char channel[120]="";
 
455
        char oldname[120]="";
 
456
        char newname[120]="";
 
457
        resp = get_line();
 
458
        if (!resp) {
 
459
                fprintf(stderr, "disconnected (6)\n");
 
460
                return -1;
 
461
        }
 
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);
 
472
                }
 
473
                if (strlen(channel)) {
 
474
                        if (!strcasecmp(event, "Hangup")) 
 
475
                                hangup_chan(channel);
 
476
                        else
 
477
                                offhook_chan(channel);
 
478
                }
 
479
                if (strlen(newname) && strlen(oldname)) {
 
480
                        if (!strcasecmp(event, "Rename")) {
 
481
                                hangup_chan(oldname);
 
482
                                offhook_chan(newname);
 
483
                        }
 
484
                }
 
485
        } else {
 
486
                /* Consume the rest of the non-event */
 
487
                while((resp = get_line()) && strlen(resp));
 
488
        }
 
489
        if (!resp) {
 
490
                fprintf(stderr, "disconnected (7)\n");
 
491
                return -1;
 
492
        }
 
493
        return 0;
 
494
}
 
495
 
 
496
static void usage(void)
 
497
{
 
498
        printf("Usage: muted [-f] [-d]\n"
 
499
               "        -f : Do not fork\n"
 
500
                   "        -d : Debug (implies -f)\n");
 
501
}
 
502
 
 
503
int main(int argc, char *argv[])
 
504
{
 
505
        int x;
 
506
        while((x = getopt(argc, argv, "fhd")) > 0) {
 
507
                switch(x) {
 
508
                case 'd':
 
509
                        debug = 1;
 
510
                        needfork = 0;
 
511
                        break;
 
512
                case 'f':
 
513
                        needfork = 0;
 
514
                        break;
 
515
                case 'h':
 
516
                        /* Fall through */
 
517
                default:
 
518
                        usage();
 
519
                        exit(1);
 
520
                }
 
521
        }
 
522
        if (load_config())
 
523
                exit(1);
 
524
        if (open_mixer())
 
525
                exit(1);
 
526
        if (connect_asterisk()) {
 
527
                close(mixfd);
 
528
                exit(1);
 
529
        }
 
530
        if (login_asterisk()) {
 
531
                close(mixfd);
 
532
                fclose(astf);
 
533
                exit(1);
 
534
        }
 
535
        if (needfork)
 
536
                daemon(0,0);
 
537
        for(;;) {
 
538
                if (wait_event()) {
 
539
                        fclose(astf);
 
540
                        while(connect_asterisk()) {
 
541
                                sleep(5);
 
542
                        }
 
543
                        if (login_asterisk()) {
 
544
                                fclose(astf);
 
545
                                exit(1);
 
546
                        }
 
547
                }
 
548
        }
 
549
        exit(0);
 
550
}