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 | |
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
-rwxr-xr-x | apps/app_chanspy.c | 225 | ||||
-rwxr-xr-x | apps/app_meetme.c | 169 | ||||
-rwxr-xr-x | channels/chan_iax2.c | 35 | ||||
-rwxr-xr-x | channels/chan_zap.c | 248 | ||||
-rwxr-xr-x | include/asterisk/frame.h | 16 |
5 files changed, 474 insertions, 219 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! */ diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index b05544f24..9c1c5f489 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -2992,18 +2992,29 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat { struct ast_option_header *h; int res; - h = malloc(datalen + sizeof(struct ast_option_header)); - if (h) { - h->flag = AST_OPTION_FLAG_REQUEST; - h->option = htons(option); - memcpy(h->data, data, datalen); - res = send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_CONTROL, - AST_CONTROL_OPTION, 0, (unsigned char *)h, datalen + sizeof(struct ast_option_header), -1); - free(h); - return res; - } else - ast_log(LOG_WARNING, "Out of memory\n"); - return -1; + + switch (option) { + case AST_OPTION_TXGAIN: + case AST_OPTION_RXGAIN: + /* these two cannot be sent, because they require a result */ + errno = ENOSYS; + return -1; + default: + h = malloc(datalen + sizeof(*h)); + if (h) { + h->flag = AST_OPTION_FLAG_REQUEST; + h->option = htons(option); + memcpy(h->data, data, datalen); + res = send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_CONTROL, + AST_CONTROL_OPTION, 0, (unsigned char *) h, + datalen + sizeof(*h), -1); + free(h); + return res; + } else { + ast_log(LOG_WARNING, "Out of memory\n"); + return -1; + } + } } static struct ast_frame *iax2_read(struct ast_channel *c) diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 6bf8f6398..e6e31d2a9 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -1409,50 +1409,105 @@ static void zt_disable_ec(struct zt_pvt *p) p->echocanon = 0; } -int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law) +static void fill_txgain(struct zt_gains *g, float gain, int law) { - struct zt_gains g; - float ltxgain; - float lrxgain; - int j,k; - g.chan = chan; - if ((rxgain != 0.0) || (txgain != 0.0)) { - /* caluculate linear value of tx gain */ - ltxgain = pow(10.0,txgain / 20.0); - /* caluculate linear value of rx gain */ - lrxgain = pow(10.0,rxgain / 20.0); - if (law == ZT_LAW_ALAW) { - for (j=0;j<256;j++) { - k = (int)(((float)AST_ALAW(j)) * lrxgain); - if (k > 32767) k = 32767; - if (k < -32767) k = -32767; - g.rxgain[j] = AST_LIN2A(k); - k = (int)(((float)AST_ALAW(j)) * ltxgain); - if (k > 32767) k = 32767; - if (k < -32767) k = -32767; - g.txgain[j] = AST_LIN2A(k); + int j; + short k; + float linear_gain = pow(10.0, gain / 20.0); + + switch (law) { + case ZT_LAW_ALAW: + for (j = 0; j < (sizeof(g->txgain) / sizeof(g->txgain[0])); j++) { + if (gain) { + k = (short) (((float) AST_ALAW(j)) * linear_gain); + g->txgain[j] = AST_LIN2A(k); + } else { + g->txgain[j] = j; } - } else { - for (j=0;j<256;j++) { - k = (int)(((float)AST_MULAW(j)) * lrxgain); - if (k > 32767) k = 32767; - if (k < -32767) k = -32767; - g.rxgain[j] = AST_LIN2MU(k); - k = (int)(((float)AST_MULAW(j)) * ltxgain); - if (k > 32767) k = 32767; - if (k < -32767) k = -32767; - g.txgain[j] = AST_LIN2MU(k); + } + break; + case ZT_LAW_MULAW: + for (j = 0; j < (sizeof(g->txgain) / sizeof(g->txgain[0])); j++) { + if (gain) { + k = (short) (((float) AST_MULAW(j)) * linear_gain); + g->txgain[j] = AST_LIN2MU(k); + } else { + g->txgain[j] = j; } } - } else { - for (j=0;j<256;j++) { - g.rxgain[j] = j; - g.txgain[j] = j; + break; + } +} + +static void fill_rxgain(struct zt_gains *g, float gain, int law) +{ + int j; + short k; + float linear_gain = pow(10.0, gain / 20.0); + + switch (law) { + case ZT_LAW_ALAW: + for (j = 0; j < (sizeof(g->rxgain) / sizeof(g->rxgain[0])); j++) { + if (gain) { + k = (short) (((float) AST_ALAW(j)) * linear_gain); + g->rxgain[j] = AST_LIN2A(k); + } else { + g->rxgain[j] = j; + } } + break; + case ZT_LAW_MULAW: + for (j = 0; j < (sizeof(g->rxgain) / sizeof(g->rxgain[0])); j++) { + if (gain) { + k = (short) (((float) AST_MULAW(j)) * linear_gain); + g->rxgain[j] = AST_LIN2MU(k); + } else { + g->rxgain[j] = j; + } + } + break; } - - /* set 'em */ - return(ioctl(fd,ZT_SETGAINS,&g)); +} + +int set_actual_txgain(int fd, int chan, float gain, int law) +{ + struct zt_gains g; + int res; + + memset(&g, 0, sizeof(g)); + g.chan = chan; + res = ioctl(fd, ZT_GETGAINS, &g); + if (res) { + ast_log(LOG_DEBUG, "Failed to read gains: %s\n", strerror(errno)); + return res; + } + + fill_txgain(&g, gain, law); + + return ioctl(fd, ZT_SETGAINS, &g); +} + +int set_actual_rxgain(int fd, int chan, float gain, int law) +{ + struct zt_gains g; + int res; + + memset(&g, 0, sizeof(g)); + g.chan = chan; + res = ioctl(fd, ZT_GETGAINS, &g); + if (res) { + ast_log(LOG_DEBUG, "Failed to read gains: %s\n", strerror(errno)); + return res; + } + + fill_rxgain(&g, gain, law); + + return ioctl(fd, ZT_SETGAINS, &g); +} + +int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law) +{ + return set_actual_txgain(fd, chan, txgain, law) | set_actual_rxgain(fd, chan, rxgain, law); } static inline int zt_set_hook(int fd, int hs) @@ -2570,65 +2625,78 @@ static int zt_answer(struct ast_channel *ast) static int zt_setoption(struct ast_channel *chan, int option, void *data, int datalen) { -char *cp; -int x; - + char *cp; + signed char *scp; + int x; + int index; struct zt_pvt *p = chan->tech_pvt; - - if ((option != AST_OPTION_TONE_VERIFY) && (option != AST_OPTION_AUDIO_MODE) && - (option != AST_OPTION_TDD) && (option != AST_OPTION_RELAXDTMF)) - { - errno = ENOSYS; - return -1; - } - cp = (char *)data; - if ((!cp) || (datalen < 1)) - { + /* all supported options require data */ + if (!data || (datalen < 1)) { errno = EINVAL; return -1; - } + } + switch(option) { - case AST_OPTION_TONE_VERIFY: + case AST_OPTION_TXGAIN: + scp = (signed char *) data; + index = zt_get_index(chan, p, 0); + if (index < 0) { + ast_log(LOG_WARNING, "No index in TXGAIN?\n"); + return -1; + } + ast_log(LOG_DEBUG, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp); + return set_actual_txgain(p->subs[index].zfd, 0, p->txgain + (float) *scp, p->law); + case AST_OPTION_RXGAIN: + scp = (signed char *) data; + index = zt_get_index(chan, p, 0); + if (index < 0) { + ast_log(LOG_WARNING, "No index in RXGAIN?\n"); + return -1; + } + ast_log(LOG_DEBUG, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp); + return set_actual_rxgain(p->subs[index].zfd, 0, p->rxgain + (float) *scp, p->law); + case AST_OPTION_TONE_VERIFY: if (!p->dsp) break; - switch(*cp) { - case 1: - ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name); - ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */ + cp = (char *) data; + switch (*cp) { + case 1: + ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name); + ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | p->dtmfrelax); /* set mute mode if desired */ break; - case 2: - ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name); - ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */ + case 2: + ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name); + ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax); /* set mute mode if desired */ break; - default: - ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name); - ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */ + default: + ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name); + ast_dsp_digitmode(p->dsp,DSP_DIGITMODE_DTMF | p->dtmfrelax); /* set mute mode if desired */ break; } break; - case AST_OPTION_TDD: /* turn on or off TDD */ + case AST_OPTION_TDD: + /* turn on or off TDD */ + cp = (char *) data; + p->mate = 0; if (!*cp) { /* turn it off */ ast_log(LOG_DEBUG, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name); if (p->tdd) tdd_free(p->tdd); p->tdd = 0; - p->mate = 0; break; } - if (*cp == 2) - ast_log(LOG_DEBUG, "Set option TDD MODE, value: MATE(2) on %s\n",chan->name); - else ast_log(LOG_DEBUG, "Set option TDD MODE, value: ON(1) on %s\n",chan->name); - p->mate = 0; + ast_log(LOG_DEBUG, "Set option TDD MODE, value: %s(%d) on %s\n", + (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name); zt_disable_ec(p); /* otherwise, turn it on */ if (!p->didtdd) { /* if havent done it yet */ unsigned char mybuf[41000],*buf; int size,res,fd,len; - int index; struct pollfd fds[1]; + buf = mybuf; - memset(buf,0x7f,sizeof(mybuf)); /* set to silence */ - ast_tdd_gen_ecdisa(buf + 16000,16000); /* put in tone */ + memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */ + ast_tdd_gen_ecdisa(buf + 16000, 16000); /* put in tone */ len = 40000; index = zt_get_index(chan, p, 0); if (index < 0) { @@ -2649,7 +2717,7 @@ int x; ast_log(LOG_DEBUG, "poll (for write) ret. 0 on channel %d\n", p->channel); continue; } - /* if got exception */ + /* if got exception */ if (fds[0].revents & POLLPRI) return -1; if (!(fds[0].revents & POLLOUT)) { ast_log(LOG_DEBUG, "write fd not ready on channel %d\n", p->channel); @@ -2671,36 +2739,27 @@ int x; p->tdd = 0; p->mate = 1; break; - } + } if (!p->tdd) { /* if we dont have one yet */ p->tdd = tdd_new(); /* allocate one */ } break; - case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */ + case AST_OPTION_RELAXDTMF: /* Relax DTMF decoding (or not) */ if (!p->dsp) break; - if (!*cp) - { - ast_log(LOG_DEBUG, "Set option RELAX DTMF, value: OFF(0) on %s\n",chan->name); - x = 0; - } - else - { - ast_log(LOG_DEBUG, "Set option RELAX DTMF, value: ON(1) on %s\n",chan->name); - x = 1; - } - ast_dsp_digitmode(p->dsp,x ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF | p->dtmfrelax); + cp = (char *) data; + ast_log(LOG_DEBUG, "Set option RELAX DTMF, value: %s(%d) on %s\n", + *cp ? "ON" : "OFF", (int) *cp, chan->name); + ast_dsp_digitmode(p->dsp, ((*cp) ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF) | p->dtmfrelax); break; - case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */ - if (!*cp) - { - ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: OFF(0) on %s\n",chan->name); + case AST_OPTION_AUDIO_MODE: /* Set AUDIO mode (or not) */ + cp = (char *) data; + if (!*cp) { + ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name); x = 0; zt_disable_ec(p); - } - else - { - ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: ON(1) on %s\n",chan->name); + } else { + ast_log(LOG_DEBUG, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name); x = 1; } if (ioctl(p->subs[SUB_REAL].zfd, ZT_AUDIOMODE, &x) == -1) @@ -2708,6 +2767,7 @@ int x; break; } errno = 0; + return 0; } diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index ae42b6cae..e39974d36 100755 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -227,6 +227,22 @@ struct ast_frame_chain { /* Set (or clear) Audio (Not-Clear) Mode */ #define AST_OPTION_AUDIO_MODE 4 +/* Set channel transmit gain */ +/* Option data is a single signed char + representing number of decibels (dB) + to set gain to (on top of any gain + specified in channel driver) +*/ +#define AST_OPTION_TXGAIN 5 + +/* Set channel receive gain */ +/* Option data is a single signed char + representing number of decibels (dB) + to set gain to (on top of any gain + specified in channel driver) +*/ +#define AST_OPTION_RXGAIN 6 + struct ast_option_header { /* Always keep in network byte order */ #if __BYTE_ORDER == __BIG_ENDIAN |