diff options
author | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-09-07 01:30:01 +0000 |
---|---|---|
committer | kpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b> | 2005-09-07 01:30:01 +0000 |
commit | 38ba89121ef20c5c80c48257c14b480864215da0 (patch) | |
tree | 8165a261cb124dd45a1b6129516aabef87fce470 /apps | |
parent | 054df857925f00c4fc914fe2c08e4744e15d24fa (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: http://svn.digium.com/svn/asterisk/trunk@6519 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps')
-rwxr-xr-x | apps/app_chanspy.c | 225 | ||||
-rwxr-xr-x | apps/app_meetme.c | 169 |
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! */ |