summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorKevin P. Fleming <kpfleming@digium.com>2005-09-07 01:30:01 +0000
committerKevin P. Fleming <kpfleming@digium.com>2005-09-07 01:30:01 +0000
commit5fdc070109c757f0df4321d3cd5d0069b77b3f46 (patch)
tree8165a261cb124dd45a1b6129516aabef87fce470 /apps
parent2f67f665779c1cbc714c9757143769e79845fd5c (diff)
add new channel option (via ast_channel_setoption()) to let channel drivers adjust txgain/rxgain if they are able (only Zap channels at this time)
modify app_chanspy to use new gain option reformat app_chanspy to match coding guidelines add user-controlled volume adjustment to app_meetme (issue #4170, heavily modified to actually work on Zap channels) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6519 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'apps')
-rwxr-xr-xapps/app_chanspy.c225
-rwxr-xr-xapps/app_meetme.c169
2 files changed, 281 insertions, 113 deletions
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 5bc8c79d7..93c898741 100755
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -39,12 +39,10 @@ AST_MUTEX_DEFINE_STATIC(modlock);
#define AST_NAME_STRLEN 256
#define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
-#define minmax(x,y) x ? (x > y) ? y : ((x < (y * -1)) ? (y * -1) : x) : 0
-
-static char *synopsis = "Tap into any type of asterisk channel and listen to audio";
-static char *app = "ChanSpy";
-static char *desc = " Chanspy([<scanspec>][|<options>])\n\n"
+static const char *synopsis = "Tap into any type of asterisk channel and listen to audio";
+static const char *app = "ChanSpy";
+static const char *desc = " Chanspy([<scanspec>][|<options>])\n\n"
"Valid Options:\n"
" - q: quiet, don't announce channels beep, etc.\n"
" - b: bridged, only spy on channels involved in a bridged call.\n"
@@ -237,104 +235,102 @@ static int spy_queue_ready(struct ast_channel_spy *spy)
}
#endif
-
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
{
- struct chanspy_translation_helper *csth = data;
- struct ast_frame frame, *f;
- int len0 = 0, len1 = 0, samp0 = 0, samp1 = 0, x, vf, maxsamp;
- short buf0[1280], buf1[1280], buf[1280];
+ struct chanspy_translation_helper *csth = data;
+ struct ast_frame frame, *f;
+ int len0 = 0, len1 = 0, samp0 = 0, samp1 = 0, x, vf, maxsamp;
+ short buf0[1280], buf1[1280], buf[1280];
- if (csth->spy.status == CHANSPY_DONE) {
- return -1;
+ if (csth->spy.status == CHANSPY_DONE) {
+ return -1;
}
- ast_mutex_lock(&csth->spy.lock);
- while((f = csth->spy.queue[0])) {
- csth->spy.queue[0] = f->next;
- ast_slinfactory_feed(&csth->slinfactory[0], f);
- ast_frfree(f);
- }
- ast_mutex_unlock(&csth->spy.lock);
- ast_mutex_lock(&csth->spy.lock);
- while((f = csth->spy.queue[1])) {
- csth->spy.queue[1] = f->next;
- ast_slinfactory_feed(&csth->slinfactory[1], f);
- ast_frfree(f);
- }
- ast_mutex_unlock(&csth->spy.lock);
+ ast_mutex_lock(&csth->spy.lock);
+ while((f = csth->spy.queue[0])) {
+ csth->spy.queue[0] = f->next;
+ ast_slinfactory_feed(&csth->slinfactory[0], f);
+ ast_frfree(f);
+ }
+ ast_mutex_unlock(&csth->spy.lock);
+ ast_mutex_lock(&csth->spy.lock);
+ while((f = csth->spy.queue[1])) {
+ csth->spy.queue[1] = f->next;
+ ast_slinfactory_feed(&csth->slinfactory[1], f);
+ ast_frfree(f);
+ }
+ ast_mutex_unlock(&csth->spy.lock);
- if (csth->slinfactory[0].size < len || csth->slinfactory[1].size < len) {
- return 0;
- }
+ if (csth->slinfactory[0].size < len || csth->slinfactory[1].size < len) {
+ return 0;
+ }
- if ((len0 = ast_slinfactory_read(&csth->slinfactory[0], buf0, len))) {
- samp0 = len0 / 2;
- }
- if((len1 = ast_slinfactory_read(&csth->slinfactory[1], buf1, len))) {
- samp1 = len1 / 2;
- }
+ if ((len0 = ast_slinfactory_read(&csth->slinfactory[0], buf0, len))) {
+ samp0 = len0 / 2;
+ }
+ if ((len1 = ast_slinfactory_read(&csth->slinfactory[1], buf1, len))) {
+ samp1 = len1 / 2;
+ }
- maxsamp = (samp0 > samp1) ? samp0 : samp1;
- vf = get_volfactor(csth->volfactor);
- vf = minmax(vf, 16);
+ maxsamp = (samp0 > samp1) ? samp0 : samp1;
+ vf = get_volfactor(csth->volfactor);
- for(x=0; x < maxsamp; x++) {
- if (vf < 0) {
- if (samp0) {
- buf0[x] /= abs(vf);
- }
- if (samp1) {
- buf1[x] /= abs(vf);
- }
- } else if (vf > 0) {
- if (samp0) {
- buf0[x] *= vf;
- }
- if (samp1) {
- buf1[x] *= vf;
- }
+ for(x=0; x < maxsamp; x++) {
+ if (vf < 0) {
+ if (samp0) {
+ buf0[x] /= abs(vf);
}
- if (samp0 && samp1) {
- if (x < samp0 && x < samp1) {
- buf[x] = buf0[x] + buf1[x];
- } else if (x < samp0) {
- buf[x] = buf0[x];
- } else if (x < samp1) {
- buf[x] = buf1[x];
- }
+ if (samp1) {
+ buf1[x] /= abs(vf);
+ }
+ } else if (vf > 0) {
+ if (samp0) {
+ buf0[x] *= vf;
+ }
+ if (samp1) {
+ buf1[x] *= vf;
+ }
+ }
+ if (samp0 && samp1) {
+ if (x < samp0 && x < samp1) {
+ buf[x] = buf0[x] + buf1[x];
} else if (x < samp0) {
buf[x] = buf0[x];
} else if (x < samp1) {
buf[x] = buf1[x];
}
+ } else if (x < samp0) {
+ buf[x] = buf0[x];
+ } else if (x < samp1) {
+ buf[x] = buf1[x];
}
+ }
- memset(&frame, 0, sizeof(frame));
- frame.frametype = AST_FRAME_VOICE;
- frame.subclass = AST_FORMAT_SLINEAR;
- frame.data = buf;
- frame.samples = x;
- frame.datalen = x * 2;
-
- if (ast_write(chan, &frame)) {
- csth->spy.status = CHANSPY_DONE;
- return -1;
- }
+ memset(&frame, 0, sizeof(frame));
+ frame.frametype = AST_FRAME_VOICE;
+ frame.subclass = AST_FORMAT_SLINEAR;
+ frame.data = buf;
+ frame.samples = x;
+ frame.datalen = x * 2;
+
+ if (ast_write(chan, &frame)) {
+ csth->spy.status = CHANSPY_DONE;
+ return -1;
+ }
- if (csth->fd) {
- write(csth->fd, buf1, len1);
- }
+ if (csth->fd) {
+ write(csth->fd, buf1, len1);
+ }
- return 0;
+ return 0;
}
static struct ast_generator spygen = {
- alloc: spy_alloc,
- release: spy_release,
- generate: spy_generate,
+ alloc: spy_alloc,
+ release: spy_release,
+ generate: spy_generate,
};
static void start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy)
@@ -398,6 +394,34 @@ static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy)
}
+/* Map 'volume' levels from -4 through +4 into
+ decibel (dB) settings for channel drivers
+*/
+static signed char volfactor_map[] = {
+ -24,
+ -18,
+ -12,
+ -6,
+ 0,
+ 6,
+ 12,
+ 18,
+ 24,
+};
+
+/* attempt to set the desired gain adjustment via the channel driver;
+ if successful, clear it out of the csth structure so the
+ generator will not attempt to do the adjustment itself
+*/
+static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
+{
+ signed char volume_adjust = volfactor_map[csth->volfactor + 4];
+
+ if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0)) {
+ csth->volfactor = 0;
+ }
+}
+
static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd)
{
struct chanspy_translation_helper csth;
@@ -416,6 +440,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
csth.spy.status = CHANSPY_RUNNING;
ast_mutex_init(&csth.spy.lock);
csth.volfactor = *volfactor;
+ set_volume(chan, &csth);
if (fd) {
csth.fd = fd;
@@ -423,12 +448,12 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
start_spying(spyee, chan, &csth.spy);
ast_activate_generator(chan, &spygen, &csth);
- while(csth.spy.status == CHANSPY_RUNNING &&
- chan && !ast_check_hangup(chan) &&
- spyee &&
- !ast_check_hangup(spyee)
- && running == 1 &&
- (res = ast_waitfor(chan, -1) > -1)) {
+ while (csth.spy.status == CHANSPY_RUNNING &&
+ chan && !ast_check_hangup(chan) &&
+ spyee &&
+ !ast_check_hangup(spyee) &&
+ running == 1 &&
+ (res = ast_waitfor(chan, -1) > -1)) {
if ((f = ast_read(chan))) {
res = 0;
if (f->frametype == AST_FRAME_DTMF) {
@@ -456,14 +481,15 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
running = x ? atoi(inp) : -1;
break;
} else {
- csth.volfactor++;
- if (csth.volfactor > 4) {
- csth.volfactor = -4;
+ (*volfactor)++;
+ if (*volfactor > 4) {
+ *volfactor = -4;
}
if (option_verbose > 2) {
- ast_verbose(VERBOSE_PREFIX_3"Setting spy volume on %s to %d\n", chan->name, csth.volfactor);
+ ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
}
- *volfactor = csth.volfactor;
+ csth.volfactor = *volfactor;
+ set_volume(chan, &csth);
}
} else if (res >= 48 && res <= 57) {
inp[x++] = res;
@@ -483,8 +509,6 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
return running;
}
-
-
static int chanspy_exec(struct ast_channel *chan, void *data)
{
struct localuser *u;
@@ -560,12 +584,13 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
silent = ast_test_flag(&flags, OPTION_QUIET);
bronly = ast_test_flag(&flags, OPTION_BRIDGED);
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
- if (sscanf(opts[0], "%d", &volfactor) != 1)
- ast_log(LOG_NOTICE, "volfactor must be a number between -4 and 4\n");
- else {
- volfactor = minmax(volfactor, 4);
+ int vol;
+
+ if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
+ ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
+ else
+ volfactor = vol;
}
- }
}
if (recbase) {
@@ -614,9 +639,9 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
}
if (igrp && (!spec || ((strlen(spec) < strlen(peer->name) &&
- !strncasecmp(peer->name, spec, strlen(spec)))))) {
+ !strncasecmp(peer->name, spec, strlen(spec)))))) {
if (peer && (!bronly || ast_bridged_channel(peer)) &&
- !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
+ !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
int x = 0;
strncpy(peer_name, peer->name, AST_NAME_STRLEN);
@@ -694,7 +719,7 @@ int load_module(void)
char *description(void)
{
- return synopsis;
+ return (char *) synopsis;
}
int usecount(void)
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index 5589f2967..0599e5ebf 100755
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -136,16 +136,19 @@ static struct ast_conference {
} *confs;
struct ast_conf_user {
- int user_no; /* User Number */
- struct ast_conf_user *prevuser; /* Pointer to the previous user */
- struct ast_conf_user *nextuser; /* Pointer to the next user */
- int userflags; /* Flags as set in the conference */
- int adminflags; /* Flags set by the Admin */
- struct ast_channel *chan; /* Connected channel */
- int talking; /* Is user talking */
- char usrvalue[50]; /* Custom User Value */
- char namerecloc[AST_MAX_EXTENSION]; /* Name Recorded file Location */
- time_t jointime; /* Time the user joined the conference */
+ int user_no; /* User Number */
+ struct ast_conf_user *prevuser; /* Pointer to the previous user */
+ struct ast_conf_user *nextuser; /* Pointer to the next user */
+ int userflags; /* Flags as set in the conference */
+ int adminflags; /* Flags set by the Admin */
+ struct ast_channel *chan; /* Connected channel */
+ int talking; /* Is user talking */
+ int zapchannel; /* Is a Zaptel channel */
+ char usrvalue[50]; /* Custom User Value */
+ char namerecloc[AST_MAX_EXTENSION]; /* Name Recorded file Location */
+ time_t jointime; /* Time the user joined the conference */
+ int desired_volume; /* Desired volume adjustment */
+ int actual_volume; /* Actual volume adjustment (for channels that can't adjust) */
};
#define ADMINFLAG_MUTED (1 << 1) /* User is muted */
@@ -153,6 +156,11 @@ struct ast_conf_user {
#define MEETME_DELAYDETECTTALK 300
#define MEETME_DELAYDETECTENDTALK 1000
+enum volume_action {
+ VOL_UP,
+ VOL_DOWN,
+};
+
AST_MUTEX_DEFINE_STATIC(conflock);
static int admin_exec(struct ast_channel *chan, void *data);
@@ -251,6 +259,94 @@ static int careful_write(int fd, unsigned char *data, int len)
return 0;
}
+/* Map 'volume' levels from -5 through +5 into
+ decibel (dB) settings for channel drivers
+ Note: these are not a straight linear-to-dB
+ conversion... the numbers have been modified
+ to give the user a better level of adjustability
+*/
+static signed char gain_map[] = {
+ -15,
+ -13,
+ -10,
+ -6,
+ 0,
+ 0,
+ 0,
+ 6,
+ 10,
+ 13,
+ 15,
+};
+
+static int set_volume(struct ast_conf_user *user, int volume)
+{
+ signed char gain_adjust;
+
+ /* attempt to make the adjustment in the channel driver;
+ if successful, don't adjust in the frame reading routine
+ */
+ gain_adjust = gain_map[volume + 5];
+ return ast_channel_setoption(user->chan, AST_OPTION_TXGAIN, &gain_adjust, sizeof(gain_adjust), 0);
+}
+
+static void tweak_volume(struct ast_conf_user *user, enum volume_action action)
+{
+ switch (action) {
+ case VOL_UP:
+ switch (user->desired_volume) {
+ case 5:
+ break;
+ case 0:
+ user->desired_volume = 2;
+ break;
+ case -2:
+ user->desired_volume = 0;
+ break;
+ default:
+ user->desired_volume++;
+ break;
+ }
+ break;
+ case VOL_DOWN:
+ switch (user->desired_volume) {
+ case -5:
+ break;
+ case 2:
+ user->desired_volume = 0;
+ break;
+ case 0:
+ user->desired_volume = -2;
+ break;
+ default:
+ user->desired_volume--;
+ break;
+ }
+ }
+ /* attempt to make the adjustment in the channel driver;
+ if successful, don't adjust in the frame reading routine
+ */
+ if (!set_volume(user, user->desired_volume))
+ user->actual_volume = 0;
+ else
+ user->actual_volume = user->desired_volume;
+}
+
+static void adjust_volume(struct ast_frame *f, int vol)
+{
+ int count;
+ short *fdata = f->data;
+
+ for (count = 0; count < f->datalen; count++) {
+ if (vol > 0) {
+ fdata[count] *= abs(vol);
+ } else if (vol < 0) {
+ fdata[count] /= abs(vol);
+ }
+ }
+}
+
+
static void conf_play(struct ast_channel *chan, struct ast_conference *conf, int sound)
{
unsigned char *data;
@@ -789,6 +885,7 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
}
ast_indicate(chan, -1);
retryzap = strcasecmp(chan->type, "Zap");
+ user->zapchannel = retryzap;
zapretry:
origfd = chan->fds[0];
if (retryzap) {
@@ -903,7 +1000,7 @@ zapretry:
if (!agifile)
agifile = agifiledefault;
- if (!strcasecmp(chan->type,"Zap")) {
+ if (user->zapchannel) {
/* Set CONFMUTE mode on Zap channel to mute DTMF tones */
x = 1;
ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
@@ -916,13 +1013,13 @@ zapretry:
ast_log(LOG_WARNING, "Could not find application (agi)\n");
ret = -2;
}
- if (!strcasecmp(chan->type,"Zap")) {
+ if (user->zapchannel) {
/* Remove CONFMUTE mode on Zap channel */
x = 0;
ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
}
} else {
- if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) {
+ if (user->zapchannel && (confflags & CONFFLAG_STARMENU)) {
/* Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
x = 1;
ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
@@ -932,8 +1029,19 @@ zapretry:
res = -1;
}
for(;;) {
+ int menu_was_active = 0;
+
outfd = -1;
ms = -1;
+
+ /* if we have just exited from the menu, and the user had a channel-driver
+ volume adjustment, restore it
+ */
+ if (!menu_active && menu_was_active && user->desired_volume && !user->actual_volume)
+ set_volume(user, user->desired_volume);
+
+ menu_was_active = menu_active;
+
currentmarked = conf->markedusers;
if (!(confflags & CONFFLAG_QUIET) && (confflags & CONFFLAG_MARKEDUSER) && (confflags & CONFFLAG_WAITMARKED) && lastmarked == 0) {
if (currentmarked == 1 && conf->users > 1) {
@@ -1079,6 +1187,9 @@ zapretry:
if (!f)
break;
if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
+ if (user->actual_volume) {
+ adjust_volume(f, user->actual_volume);
+ }
if (confflags & CONFFLAG_MONITORTALKER) {
int totalsilence;
if (user->talking == -1)
@@ -1129,6 +1240,13 @@ zapretry:
ast_mutex_unlock(&conflock);
goto outrun;
}
+
+ /* if we are entering the menu, and the user has a channel-driver
+ volume adjustment, clear it
+ */
+ if (!menu_active && user->desired_volume && !user->actual_volume)
+ set_volume(user, 0);
+
if (musiconhold) {
ast_moh_stop(chan);
}
@@ -1189,6 +1307,19 @@ zapretry:
usr->adminflags |= ADMINFLAG_KICKME;
ast_stopstream(chan);
break;
+
+ case '9':
+ tweak_volume(user, VOL_UP);
+ break;
+
+ case '8':
+ menu_active = 0;
+ break;
+
+ case '7':
+ tweak_volume(user, VOL_DOWN);
+ break;
+
default:
menu_active = 0;
/* Play an error message! */
@@ -1232,6 +1363,18 @@ zapretry:
ast_waitstream(chan, "");
}
break;
+ case '9':
+ tweak_volume(user, VOL_UP);
+ break;
+
+ case '8':
+ menu_active = 0;
+ break;
+
+ case '7':
+ tweak_volume(user, VOL_DOWN);
+ break;
+
default:
menu_active = 0;
/* Play an error message! */