[Asterisk-cvs] asterisk muted.c,NONE,1.1 muted.conf.sample,NONE,1.1 Makefile,1.86,1.87

markster at lists.digium.com markster at lists.digium.com
Mon May 17 02:19:37 CDT 2004


Update of /usr/cvsroot/asterisk
In directory mongoose.digium.com:/tmp/cvs-serv7435

Modified Files:
	Makefile 
Added Files:
	muted.c muted.conf.sample 
Log Message:
Add muted for malcolm!


--- NEW FILE: muted.c ---
/*
 * Mute Daemon
 *
 * Specially written for Malcolm Davenport, but I think I'll use it too
 *
 * Copyright (C) 2004, Digium Inc.
 *
 * Mark Spencer <markster at digium.com>
 *
 * Distributed under the terms of the GNU General Public License version 2.0 
 *
 */
#include <linux/soundcard.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static char *config = "/etc/muted.conf";

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;
static int mixchan = SOUND_MIXER_VOLUME;

static struct channel {
	char *tech;
	char *location;
	struct channel *next;
	int offhook;
} *channels;

static void add_channel(char *tech, char *location)
{
	struct channel *chan;
	chan = malloc(sizeof(struct channel));
	if (chan) {
		memset(chan, 0, sizeof(struct channel));
		chan->tech = strdup(tech);
		chan->location = strdup(location);
		chan->next = channels;
		channels = chan;
	}
	
}

static int load_config(void)
{
	FILE *f;
	char buf[1024];
	char *val;
	char *val2;
	int lineno=0;
	int x;
	f = fopen(config, "r");
	if (!f) {
		fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
		return -1;
	}
	while(!feof(f)) {
		fgets(buf, sizeof(buf), f);
		if (!feof(f)) {
			lineno++;
			val = strchr(buf, '#');
			if (val) *val = '\0';
			while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
				buf[strlen(buf) - 1] = '\0';
			if (!strlen(buf))
				continue;
			val = buf;
			while(*val) {
				if (*val < 33)
					break;
				val++;
			}
			if (*val) {
				*val = '\0';
				val++;
				while(*val && (*val < 33)) val++;
			}
			if (!strcasecmp(buf, "host")) {
				if (val && strlen(val))
					strncpy(host, val, sizeof(host));
				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));
				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));
				else
					fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
			} else if (!strcasecmp(buf, "smoothfade")) {
				smoothfade = 1;
			} else if (!strcasecmp(buf, "mutelevel")) {
				if (val && (sscanf(val, "%d", &x) == 1) && (x > -1) && (x < 101)) {
					mutelevel = x;
				} else 
					fprintf(stderr, "mutelevel must be a number from 0 (most muted) to 100 (no mute) at line %d\n", lineno);
			} else if (!strcasecmp(buf, "channel")) {
				if (val && strlen(val)) {
					val2 = strchr(val, '/');
					if (val2) {
						*val2 = '\0';
						val2++;
						add_channel(val, val2);
					} else
						fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
				} else
					fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
			} else {
				fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
			}
		}
	}
	fclose(f);
	if (!strlen(host))
		fprintf(stderr, "no 'host' specification in config file\n");
	else if (!strlen(user))
		fprintf(stderr, "no 'user' specification in config file\n");
	else if (!channels) 
		fprintf(stderr, "no 'channel' specifications in config file\n");
	else
		return 0;
	return -1;
}

static FILE *astf;

static int mixfd;

static int open_mixer(void)
{
	mixfd = open("/dev/mixer", O_RDWR);
	if (mixfd < 0) {
		fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

static int connect_asterisk(void)
{
	int sock;
	struct hostent *hp;
	char *ports;
	int port = 5038;
	struct sockaddr_in sin;
	ports = strchr(host, ':');
	if (ports) {
		*ports = '\0';
		ports++;
		if ((sscanf(ports, "%d", &port) != 1) || (port < 1) || (port > 65535)) {
			fprintf(stderr, "'%s' is not a valid port number in the hostname\n", ports);
			return -1;
		}
	}
	hp = gethostbyname(host);
	if (!hp) {
		fprintf(stderr, "Can't find host '%s'\n", host);
		return -1;
	}
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0) {
		fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
		return -1;
	}
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
	if (connect(sock, &sin, sizeof(sin))) {
		fprintf(stderr, "Failed to connect to '%s' port '%d': %s\n", host, port, strerror(errno));
		close(sock);
		return -1;
	}
	astf = fdopen(sock, "r+");
	if (!astf) {
		fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
		close(sock);
		return -1;
	}
	return 0;
}

static char *get_line(void)
{
	static char buf[1024];
	if (fgets(buf, sizeof(buf), astf)) {
		while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
			buf[strlen(buf) - 1] = '\0';
		return buf;
	} else
		return NULL;
}

static int login_asterisk(void)
{
	char *welcome;
	char *resp;
	if (!(welcome = get_line())) {
		fprintf(stderr, "disconnected (1)\n");
		return -1;
	}
	fprintf(astf, 
		"Action: Login\r\n"
		"Username: %s\r\n"
		"Secret: %s\r\n\r\n", user, pass);
	if (!(welcome = get_line())) {
		fprintf(stderr, "disconnected (2)\n");
		return -1;
	}
	if (strcasecmp(welcome, "Response: Success")) {
		fprintf(stderr, "login failed ('%s')\n", welcome);
		return -1;
	}
	/* Eat the rest of the event */
	while((resp = get_line()) && strlen(resp));
	if (!resp) {
		fprintf(stderr, "disconnected (3)\n");
		return -1;
	}
	fprintf(astf, 
		"Action: Status\r\n\r\n");
	if (!(welcome = get_line())) {
		fprintf(stderr, "disconnected (4)\n");
		return -1;
	}
	if (strcasecmp(welcome, "Response: Success")) {
		fprintf(stderr, "status failed ('%s')\n", welcome);
		return -1;
	}
	/* Eat the rest of the event */
	while((resp = get_line()) && strlen(resp));
	if (!resp) {
		fprintf(stderr, "disconnected (5)\n");
		return -1;
	}
	return 0;
}

static struct channel *find_channel(char *channel)
{
	char tmp[256] = "";
	char *s, *t;
	struct channel *chan;
	strncpy(tmp, channel, sizeof(tmp));
	s = strchr(tmp, '/');
	if (s) {
		*s = '\0';
		s++;
		t = strrchr(s, '-');
		if (t) {
			*t = '\0';
		}
		if (debug)
			printf("Searching for '%s' tech, '%s' location\n", tmp, s);
		chan = channels;
		while(chan) {
			if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
				if (debug)
					printf("Found '%s'/'%s'\n", chan->tech, chan->location);
				break;
			}
			chan = chan->next;
		}
	} else
		chan = NULL;
	return chan;
}

static int getvol(void)
{
	int vol;
	if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
		fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
		return -1;
	}
	return vol;
}

static int setvol(int vol)
{
	if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
		fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
		return -1;
	}
	return 0;
}

static int oldvol = 0;
static int mutevol = 0;

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;
}

static void mute(void)
{
	int vol;
	int start;
	int x;
	vol = getvol();
	oldvol = vol;
	if (smoothfade) 
		start = 100;
	else
		start = mutelevel;
	for (x=start;x>=mutelevel;x-=stepsize) {
		mutevol = mutedlevel(vol, x);
		setvol(mutevol);
		/* Wait 0.01 sec */
		usleep(10000);
	}
	mutevol = mutedlevel(vol, mutelevel);
	setvol(mutevol);
	if (debug)
		printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
	muted = 1;
}

static void unmute(void)
{
	int vol;
	int start;
	int x;
	vol = getvol();
	if (debug)
		printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
	if (vol == mutevol) {
		if (smoothfade)
			start = mutelevel;
		else
			start = 100;
		for (x=start;x<100;x+=stepsize) {
			mutevol = mutedlevel(oldvol, x);
			setvol(mutevol);
			/* Wait 0.01 sec */
			usleep(10000);
		}
		setvol(oldvol);
	} else
		printf("Whoops, it's already been changed!\n");
	muted = 0;
}

static void check_mute(void)
{
	int offhook = 0;
	struct channel *chan;
	chan = channels;
	while(chan) {
		if (chan->offhook) {
			offhook++;
			break;
		}
		chan = chan->next;
	}
	if (offhook && !muted)
		mute();
	else if (!offhook && muted)
		unmute();
}

static void hangup_chan(char *channel)
{
	struct channel *chan;
	chan = find_channel(channel);
	if (chan)
		chan->offhook = 0;
	check_mute();
}

static void offhook_chan(char *channel)
{
	struct channel *chan;
	chan = find_channel(channel);
	if (chan)
		chan->offhook = 1;
	check_mute();
}

static int wait_event(void)
{
	char *resp;
	char event[80]="";
	char channel[80]="";
	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));
		/* 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));
		}
		if (strlen(channel)) {
			if (!strcasecmp(event, "Hangup")) 
				hangup_chan(channel);
			else
				offhook_chan(channel);
		}
	} else {
		/* Consume the rest of the non-event */
		while((resp = get_line()) && strlen(resp));
	}
	if (!resp) {
		fprintf(stderr, "disconnected (7)\n");
		return -1;
	}
	return 0;
}

static void usage(void)
{
	printf("Usage: muted [-f] [-d]\n"
	       "        -f : Do not fork\n"
		   "        -d : Debug (implies -f)\n");
}

int main(int argc, char *argv[])
{
	int x;
	while((x = getopt(argc, argv, "fhd")) > 0) {
		switch(x) {
		case 'd':
			debug = 1;
			needfork = 0;
			break;
		case 'f':
			needfork = 0;
			break;
		case 'h':
			/* Fall through */
		default:
			usage();
			exit(1);
		}
	}
	if (load_config())
		exit(1);
	if (open_mixer())
		exit(1);
	if (connect_asterisk()) {
		close(mixfd);
		exit(1);
	}
	if (login_asterisk()) {
		close(mixfd);
		fclose(astf);
		exit(1);
	}
	if (needfork)
		daemon(0,0);
	for(;;) {
		if (wait_event())
			exit(1);
	}
	exit(0);
}

--- NEW FILE: muted.conf.sample ---
#
# Sample muted configuration file
#
# Copyright (C) 2004 Digium, Inc.
#
# First you have the host, username, and password
# we use to connect to the asterisk system
#
host misery.digium.com
user mark
pass blah
#
# List each channel we're supposed to watch
#
channel Zap/39
channel Zap/40
channel SIP/mark
#
# Mute level is the percentage of the current volume we should
# lower the music to.
#
mutelevel 20
#
# Smooth fade makes the fadein/fadeout nicer sounding
#
smoothfade

Index: Makefile
===================================================================
RCS file: /usr/cvsroot/asterisk/Makefile,v
retrieving revision 1.86
retrieving revision 1.87
diff -u -d -r1.86 -r1.87
--- Makefile	9 May 2004 08:22:15 -0000	1.86
+++ Makefile	17 May 2004 06:31:24 -0000	1.87
@@ -252,6 +252,9 @@
 asterisk: editline/libedit.a db1-ast/libdb1.a stdtime/libtime.a $(OBJS)
 	$(CC) $(DEBUG) -o asterisk $(ASTLINK) $(OBJS) $(LIBS) $(LIBEDIT) db1-ast/libdb1.a stdtime/libtime.a
 
+muted: muted.o
+	$(CC) -o muted muted.o
+
 subdirs: 
 	for x in $(SUBDIRS); do $(MAKE) -C $$x || exit 1 ; done
 




More information about the svn-commits mailing list