Index: apps/app_meetme.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_meetme.c,v retrieving revision 1.72 diff -u -r1.72 app_meetme.c --- apps/app_meetme.c 22 Jan 2005 04:51:30 -0000 1.72 +++ apps/app_meetme.c 23 Jan 2005 03:14:04 -0000 @@ -33,6 +33,7 @@ #include #include "../asterisk.h" #include "../astconf.h" +#include #ifdef __linux__ #include @@ -61,6 +62,8 @@ " 'm' -- set monitor only mode (Listen only, no talking)\n" " 't' -- set talk only mode. (Talk only, no listening)\n" " 'i' -- announce user join/leave\n" +" 'o' -- allow user to do outbound call and press * to add user in conf\n" +" outbound context defined using ${MEETME_OUTBOUNDCONTEXT}\n" " 'p' -- allow user to exit the conference by pressing '#'\n" " 'X' -- allow user to exit the conference by entering a valid single\n" " digit extension ${MEETME_EXIT_CONTEXT} or the current context\n" @@ -106,7 +109,14 @@ STANDARD_LOCAL_USER; LOCAL_USER_DECL; +struct ast_conferenceuserthread { + struct ast_channel *chan; + struct ast_conference *conf; + int confflags; + pthread_attr_t attr; + pthread_t userthread; +}; static struct ast_conference { char confno[AST_MAX_EXTENSION]; /* Conference */ struct ast_channel *chan; /* Announcements channel */ @@ -149,7 +159,8 @@ static int admin_exec(struct ast_channel *chan, void *data); static void *recordthread(void *args); - +static void *meetmeuserthread(void *args); +int meetme_outbounddial(struct ast_channel *chan,struct ast_conference *conf, int confflags, char *dialcontext); #include "enter.h" #include "leave.h" @@ -176,7 +187,8 @@ #define CONFFLAG_EXIT_CONTEXT (1 << 12) /* If set, the MeetMe will exit to the specified context */ #define CONFFLAG_MARKEDUSER (1 << 13) /* If set, the user will be marked */ #define CONFFLAG_INTROUSER (1 << 14) /* If set, user will be ask record name on entry of conference */ -#define CONFFLAG_RECORDCONF (1<< 15) /* If set, the MeetMe will be recorded */ +#define CONFFLAG_RECORDCONF (1 << 15) /* If set, the MeetMe will be recorded */ +#define CONFFLAG_DIALOUTBOUND (1 << 16) /* If set, user will be allow to do outbound calls */ static int careful_write(int fd, unsigned char *data, int len) { @@ -537,12 +549,13 @@ int menu_active = 0; int using_pseudo = 0; int duration=20; - struct ast_app *app; char *agifile; char *agifiledefault = "conf-background.agi"; char meetmesecs[30] = ""; char exitcontext[AST_MAX_EXTENSION] = ""; + char *dialcontext = ""; + char dialcontexttmp[AST_MAX_EXTENSION] = ""; char recordingtmp[AST_MAX_EXTENSION] = ""; int dtmf; @@ -615,6 +628,14 @@ user->adminflags = 0; ast_mutex_unlock(&conflock); origquiet = confflags & CONFFLAG_QUIET; + if (confflags & CONFFLAG_DIALOUTBOUND) { + dialcontext = pbx_builtin_getvar_helper(chan,"MEETME_OUTBOUNDCONTEXT"); + if (!dialcontext) { + snprintf(dialcontexttmp,sizeof(dialcontexttmp),chan->context); + dialcontext = ast_strdupa(dialcontexttmp); + } + + } if (confflags & CONFFLAG_EXIT_CONTEXT) { if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) strncpy(exitcontext, agifile, sizeof(exitcontext) - 1); @@ -960,6 +981,14 @@ usr->adminflags |= ADMINFLAG_KICKME; ast_stopstream(chan); break; + case '4': /* Outbound Call */ + menu_active = 0; + if (confflags & CONFFLAG_DIALOUTBOUND) { + menu_active = 0; + meetme_outbounddial(chan, conf, confflags, dialcontext); + break; + } + default: menu_active = 0; /* Play an error message! */ @@ -1304,6 +1333,8 @@ strncpy(the_pin, inpin, sizeof(the_pin) - 1); if (inflags) { + if (strchr(inflags, 'o')) + confflags |= CONFFLAG_DIALOUTBOUND; if (strchr(inflags, 'a')) confflags |= CONFFLAG_ADMIN; if (strchr(inflags, 'i')) @@ -1657,7 +1688,138 @@ ast_mutex_unlock(&conflock); return 0; } +int meetme_outbounddial(struct ast_channel *chan,struct ast_conference *conf, int confflags, char *dialcontext) { + struct ast_conferenceuserthread *tmpconfuser; + struct ast_frame *fa; + struct ast_channel *watchers[2]; + struct ast_channel *peer=NULL; + struct ast_channel *winner; + struct ast_channel *outgoing; + int outstate; + int pos=2; + int *to; + char admin_input[80]; + char digit; + int ax; + struct tone_zone_sound *ts; + int res; + int transmitframe; + char app_arg[AST_MAX_EXTENSION]; + + to = &pos; + + ast_stopstream(chan); + + ts = ast_get_indication_tone(chan->zone,"dial"); + if (ts && ts->data[0]) + res = ast_playtones_start(chan, 0, ts->data, 0); + memset(&admin_input,0,sizeof(admin_input)); + for(ax=0;ax < AST_MAX_EXTENSION;ax++) { + digit = ast_waitfordigit(chan,4500); + if(!digit || digit == '#') + break; + if(digit && digit == '*') + return 0; + ast_playtones_stop(chan); + admin_input[ax] = digit; + } + if(admin_input && !ast_strlen_zero(admin_input)) { + ts = ast_get_indication_tone(chan->zone,"ring"); + if (ts && ts->data[0]) + res = ast_playtones_start(chan, 0, ts->data, 0); + sprintf(app_arg,"%s@%s",admin_input,dialcontext); + + outgoing = ast_request_and_dial("Local", ast_best_codec(chan->nativeformats), app_arg,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name); + ast_playtones_stop(chan); + + if(outgoing) { + if (ast_set_write_format(outgoing, AST_FORMAT_SLINEAR) < 0) { + ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name); + ast_hangup(outgoing); + } + + /* Set it into linear mode (read) */ + if (ast_set_read_format(outgoing, AST_FORMAT_SLINEAR) < 0) { + ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name); + ast_hangup(outgoing); + } + if(outgoing->_state == AST_STATE_UP) { + if(option_verbose > 3) + ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", outgoing->name); + while (!peer) { + transmitframe = 0; + watchers[0] = chan; + watchers[1] = outgoing; + + winner = ast_waitfor_n(watchers,2,to); + if (winner == chan || winner == outgoing) { + fa = ast_read(winner); + if (fa && (fa->frametype == AST_FRAME_VOICE)) { + transmitframe = 1; + } else if (fa && fa->frametype == AST_FRAME_DTMF) { + switch (fa->subclass) { + case '#': + ast_frfree(fa); + ast_hangup(outgoing); + return -1; + case '*': + tmpconfuser = malloc(sizeof(struct ast_conferenceuserthread)); + tmpconfuser->confflags = confflags; + tmpconfuser->confflags &= ~CONFFLAG_ADMIN; + tmpconfuser->conf = conf; + tmpconfuser->chan = outgoing; + pthread_attr_init(&tmpconfuser ->attr); + pthread_attr_setdetachstate(&tmpconfuser ->attr, PTHREAD_CREATE_DETACHED); + ast_pthread_create(&tmpconfuser->userthread, &tmpconfuser->attr, meetmeuserthread, tmpconfuser); + peer = outgoing; + break; + + default: + transmitframe = 1; + + } + } else if (!fa || (fa->frametype == AST_FRAME_CONTROL && fa->subclass == AST_CONTROL_HANGUP)) { + + if (fa) + ast_frfree(fa); + if (outgoing->_state == AST_STATE_UP) + ast_hangup(outgoing); + break; + } + if (transmitframe == 1 && (fa && (fa->frametype == AST_FRAME_DTMF || fa->frametype == AST_FRAME_VOICE))) { + if (winner == chan) + if (ast_write(outgoing, fa)) + ast_log(LOG_WARNING, "Unable to forward frame\n"); + if (winner == outgoing) + if (ast_write(chan, fa)) + ast_log(LOG_WARNING, "Unable to forward frame\n"); + } + ast_frfree(fa); + } + } + + } else { + if(option_verbose > 3) + ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", outgoing->name); + ast_hangup(outgoing); + } + } else { + ast_log(LOG_WARNING, "Unable to allocate channel.\n"); + } + } + return 0; + +} +static void *meetmeuserthread(void *args) +{ + struct ast_conferenceuserthread *confthread; + confthread = (struct ast_conferenceuserthread *)args; + conf_run(confthread->chan, confthread->conf, confthread->confflags); + if(confthread->chan) + ast_hangup(confthread->chan); + pthread_exit(0); +} static void *recordthread(void *args) { struct ast_conference *cnf;