allow users of RTP to know when the peer endpoint is (apparently) behind a NAT
[asterisk/asterisk.git] / muted.c
diff --git a/muted.c b/muted.c
index c4e03dd..baeb63e 100755 (executable)
--- a/muted.c
+++ b/muted.c
@@ -3,14 +3,22 @@
  *
  * Specially written for Malcolm Davenport, but I think I'll use it too
  *
- * Copyright (C) 2004, Digium Inc.
+ * Copyright (C)  2004 - 2005, Digium Inc.
  *
  * Mark Spencer <markster@digium.com>
+ * 
+ * Updated for Mac OSX CoreAudio 
+ * by Josh Roberson <josh@asteriasgi.com>
  *
  * Distributed under the terms of the GNU General Public License version 2.0 
  *
  */
+
+#ifndef __Darwin__
 #include <linux/soundcard.h>
+#else
+#include <CoreAudio/AudioHardware.h> 
+#endif
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
 
 static char *config = "/etc/muted.conf";
 
-static char host[256];
-static char user[256];
-static char pass[256];
+static char host[256] = "";
+static char user[256] = "";
+static char pass[256] = "";
 static int smoothfade = 0;
 static int mutelevel = 20;
 static int muted = 0;
 static int needfork = 1;
 static int debug = 0;
 static int stepsize = 3;
+#ifndef __Darwin__
 static int mixchan = SOUND_MIXER_VOLUME;
+#endif
+
+struct subchannel {
+       char *name;
+       struct subchannel *next;
+};
 
 static struct channel {
        char *tech;
        char *location;
        struct channel *next;
-       int offhook;
+       struct subchannel *subs;
 } *channels;
 
 static void add_channel(char *tech, char *location)
@@ -93,17 +108,17 @@ static int load_config(void)
                        }
                        if (!strcasecmp(buf, "host")) {
                                if (val && strlen(val))
-                                       strncpy(host, val, sizeof(host));
+                                       strncpy(host, val, sizeof(host) - 1);
                                else
                                        fprintf(stderr, "host needs an argument (the host) at line %d\n", lineno);
                        } else if (!strcasecmp(buf, "user")) {
                                if (val && strlen(val))
-                                       strncpy(user, val, sizeof(user));
+                                       strncpy(user, val, sizeof(user) - 1);
                                else
                                        fprintf(stderr, "user needs an argument (the user) at line %d\n", lineno);
                        } else if (!strcasecmp(buf, "pass")) {
                                if (val && strlen(val))
-                                       strncpy(pass, val, sizeof(pass));
+                                       strncpy(pass, val, sizeof(pass) - 1);
                                else
                                        fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
                        } else if (!strcasecmp(buf, "smoothfade")) {
@@ -142,7 +157,7 @@ static int load_config(void)
 }
 
 static FILE *astf;
-
+#ifndef __Darwin__
 static int mixfd;
 
 static int open_mixer(void)
@@ -154,6 +169,7 @@ static int open_mixer(void)
        }
        return 0;
 }
+#endif /* !__Darwin */
 
 static int connect_asterisk(void)
 {
@@ -259,7 +275,7 @@ static struct channel *find_channel(char *channel)
        char tmp[256] = "";
        char *s, *t;
        struct channel *chan;
-       strncpy(tmp, channel, sizeof(tmp));
+       strncpy(tmp, channel, sizeof(tmp) - 1);
        s = strchr(tmp, '/');
        if (s) {
                *s = '\0';
@@ -284,48 +300,124 @@ static struct channel *find_channel(char *channel)
        return chan;
 }
 
+#ifndef __Darwin__
 static int getvol(void)
 {
        int vol;
+
        if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
+#else
+static float getvol(void)
+{
+       float volumeL, volumeR, vol;
+       OSStatus err;
+       AudioDeviceID device;
+       UInt32 size;
+       UInt32 channels[2];
+
+       size = sizeof(device);
+       err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
+       size = sizeof(channels);
+       if (!err) 
+               err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
+       size = sizeof(vol);
+       if (!err)
+               err = AudioDeviceGetProperty(device, channels[0], false, kAudioDevicePropertyVolumeScalar, &size, &volumeL);
+       if (!err)
+               err = AudioDeviceGetProperty(device, channels[1], false, kAudioDevicePropertyVolumeScalar, &size, &volumeR);
+       if (!err)
+               vol = (volumeL < volumeR) ? volumeR : volumeL;
+       else {
+#endif
                fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
                return -1;
        }
        return vol;
 }
 
+#ifndef __Darwin__
 static int setvol(int vol)
+#else
+static int setvol(float vol)
+#endif
 {
+#ifndef __Darwin__
        if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
+#else  
+       float volumeL = vol;
+       float volumeR = vol;
+       OSStatus err;
+       AudioDeviceID device;
+       UInt32 size;
+       UInt32 channels[2];
+
+       size = sizeof(device);
+       err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &device);
+       size = sizeof(channels);
+       err = AudioDeviceGetProperty(device, 0, false, kAudioDevicePropertyPreferredChannelsForStereo, &size, &channels);
+       size = sizeof(vol);
+       if (!err)
+               err = AudioDeviceSetProperty(device, 0, channels[0], false, kAudioDevicePropertyVolumeScalar, size, &volumeL);
+       if (!err)
+               err = AudioDeviceSetProperty(device, 0, channels[1], false, kAudioDevicePropertyVolumeScalar, size, &volumeR); 
+       if (err) {
+#endif
+
                fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
                return -1;
+
        }
        return 0;
 }
 
+#ifndef __Darwin__
 static int oldvol = 0;
 static int mutevol = 0;
+#else
+static float oldvol = 0;
+static float mutevol = 0;
+#endif
 
+#ifndef __Darwin__
 static int mutedlevel(int orig, int mutelevel)
 {
        int l = orig >> 8;
        int r = orig & 0xff;
        l = (float)(mutelevel) * (float)(l) / 100.0;
        r = (float)(mutelevel) * (float)(r) / 100.0;
+
        return (l << 8) | r;
+#else
+static float mutedlevel(float orig, float mutelevel)
+{
+       float master = orig;
+       master = mutelevel * master / 100.0;
+       return master;
+#endif
+       
 }
 
 static void mute(void)
 {
+#ifndef __Darwin__
        int vol;
        int start;
        int x;
+#else
+       float vol;
+       float start = 1.0;
+       float x;
+#endif
        vol = getvol();
        oldvol = vol;
-       if (smoothfade) 
+       if (smoothfade)
+#ifdef __Darwin__ 
+               start = mutelevel;
+#else
                start = 100;
        else
                start = mutelevel;
+#endif
        for (x=start;x>=mutelevel;x-=stepsize) {
                mutevol = mutedlevel(vol, x);
                setvol(mutevol);
@@ -335,23 +427,43 @@ static void mute(void)
        mutevol = mutedlevel(vol, mutelevel);
        setvol(mutevol);
        if (debug)
+#ifdef __Darwin__
+               printf("Mute from '%f' to '%f'!\n", oldvol, mutevol);
+#else
                printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
+#endif
        muted = 1;
 }
 
 static void unmute(void)
 {
+#ifdef __Darwin__
+       float vol;
+       float start;
+       float x;
+#else
        int vol;
        int start;
        int x;
+#endif
        vol = getvol();
        if (debug)
-               printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
+#ifdef __Darwin__
+               printf("Unmute from '%f' (should be '%f') to '%f'!\n", vol, mutevol, oldvol);
+       mutevol = vol;
        if (vol == mutevol) {
+#else
+               printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
+       if ((int)vol == mutevol) {
+#endif
                if (smoothfade)
                        start = mutelevel;
                else
+#ifdef __Darwin__
+                       start = 1.0;
+#else
                        start = 100;
+#endif
                for (x=start;x<100;x+=stepsize) {
                        mutevol = mutedlevel(oldvol, x);
                        setvol(mutevol);
@@ -370,7 +482,7 @@ static void check_mute(void)
        struct channel *chan;
        chan = channels;
        while(chan) {
-               if (chan->offhook) {
+               if (chan->subs) {
                        offhook++;
                        break;
                }
@@ -382,40 +494,88 @@ static void check_mute(void)
                unmute();
 }
 
+static void delete_sub(struct channel *chan, char *name)
+{
+       struct subchannel *sub, *prev;
+       prev = NULL;
+       sub = chan->subs;
+       while(sub) {
+               if (!strcasecmp(sub->name, name)) {
+                       if (prev)
+                               prev->next = sub->next;
+                       else
+                               chan->subs = sub->next;
+                       free(sub->name);
+                       free(sub);
+                       return;
+               }
+               prev = sub;
+               sub = sub->next;
+       }
+}
+
+static void append_sub(struct channel *chan, char *name)
+{
+       struct subchannel *sub;
+       sub = chan->subs;
+       while(sub) {
+               if (!strcasecmp(sub->name, name)) 
+                       return;
+               sub = sub->next;
+       }
+       sub = malloc(sizeof(struct subchannel));
+       if (sub) {
+               memset(sub, 0, sizeof(struct subchannel));
+               sub->name = strdup(name);
+               sub->next = chan->subs;
+               chan->subs = sub;
+       }
+}
+
 static void hangup_chan(char *channel)
 {
        struct channel *chan;
+       if (debug)
+               printf("Hangup '%s'\n", channel);
        chan = find_channel(channel);
        if (chan)
-               chan->offhook = 0;
+               delete_sub(chan, channel);
        check_mute();
 }
 
 static void offhook_chan(char *channel)
 {
        struct channel *chan;
+       if (debug)
+               printf("Offhook '%s'\n", channel);
        chan = find_channel(channel);
        if (chan)
-               chan->offhook = 1;
+               append_sub(chan, channel);
        check_mute();
 }
 
 static int wait_event(void)
 {
        char *resp;
-       char event[80]="";
-       char channel[80]="";
+       char event[120]="";
+       char channel[120]="";
+       char oldname[120]="";
+       char newname[120]="";
        resp = get_line();
        if (!resp) {
                fprintf(stderr, "disconnected (6)\n");
                return -1;
        }
        if (!strncasecmp(resp, "Event: ", strlen("Event: "))) {
-               strncpy(event, resp + strlen("Event: "), sizeof(event));
+               strncpy(event, resp + strlen("Event: "), sizeof(event) - 1);
                /* Consume the rest of the non-event */
                while((resp = get_line()) && strlen(resp)) {
                        if (!strncasecmp(resp, "Channel: ", strlen("Channel: ")))
-                               strncpy(channel, resp + strlen("Channel: "), sizeof(channel));
+                               strncpy(channel, resp + strlen("Channel: "), sizeof(channel) - 1);
+                       if (!strncasecmp(resp, "Newname: ", strlen("Newname: ")))
+                               strncpy(newname, resp + strlen("Newname: "), sizeof(newname) - 1);
+                       if (!strncasecmp(resp, "Oldname: ", strlen("Oldname: ")))
+                               strncpy(oldname, resp + strlen("Oldname: "), sizeof(oldname) - 1);
                }
                if (strlen(channel)) {
                        if (!strcasecmp(event, "Hangup")) 
@@ -423,6 +583,12 @@ static int wait_event(void)
                        else
                                offhook_chan(channel);
                }
+               if (strlen(newname) && strlen(oldname)) {
+                       if (!strcasecmp(event, "Rename")) {
+                               hangup_chan(oldname);
+                               offhook_chan(newname);
+                       }
+               }
        } else {
                /* Consume the rest of the non-event */
                while((resp = get_line()) && strlen(resp));
@@ -462,22 +628,36 @@ int main(int argc, char *argv[])
        }
        if (load_config())
                exit(1);
+#ifndef __Darwin__
        if (open_mixer())
                exit(1);
+#endif
        if (connect_asterisk()) {
+#ifndef __Darwin__
                close(mixfd);
+#endif
                exit(1);
        }
        if (login_asterisk()) {
+#ifndef __Darwin__             
                close(mixfd);
+#endif
                fclose(astf);
                exit(1);
        }
        if (needfork)
                daemon(0,0);
        for(;;) {
-               if (wait_event())
-                       exit(1);
+               if (wait_event()) {
+                       fclose(astf);
+                       while(connect_asterisk()) {
+                               sleep(5);
+                       }
+                       if (login_asterisk()) {
+                               fclose(astf);
+                               exit(1);
+                       }
+               }
        }
        exit(0);
 }