Mon Mar 31 07:40:36 2008

Asterisk developer's documentation


features.h File Reference

Call Parking and Pickup API Includes code and algorithms from the Zapata library. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_call_feature
 main call feature structure More...

Defines

#define FEATURE_APP_ARGS_LEN   256
#define FEATURE_APP_LEN   64
#define FEATURE_EXTEN_LEN   32
#define FEATURE_MAX_LEN   11
#define FEATURE_MOH_LEN   80
#define FEATURE_SNAME_LEN   32

Functions

int ast_bridge_call (struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
 Bridge a call, optionally allowing redirection.
int ast_masq_park_call (struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout)
 Park a call via a masqueraded channel.
int ast_park_call (struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout)
 Park a call and read back parked location.
char * ast_parking_ext (void)
 Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.
int ast_pickup_call (struct ast_channel *chan)
 Pickup a call.
char * ast_pickup_ext (void)
 Determine system call pickup extension.
void ast_register_feature (struct ast_call_feature *feature)
 register new feature into feature_set
void ast_unregister_feature (struct ast_call_feature *feature)
 unregister feature from feature_set


Detailed Description

Call Parking and Pickup API Includes code and algorithms from the Zapata library.

Definition in file features.h.


Define Documentation

#define FEATURE_APP_ARGS_LEN   256

Definition at line 29 of file features.h.

#define FEATURE_APP_LEN   64

Definition at line 28 of file features.h.

#define FEATURE_EXTEN_LEN   32

Definition at line 31 of file features.h.

#define FEATURE_MAX_LEN   11

Definition at line 27 of file features.h.

Referenced by ast_bridge_call().

#define FEATURE_MOH_LEN   80

Definition at line 32 of file features.h.

#define FEATURE_SNAME_LEN   32

Definition at line 30 of file features.h.


Function Documentation

int ast_bridge_call ( struct ast_channel chan,
struct ast_channel peer,
struct ast_bridge_config config 
)

Bridge a call, optionally allowing redirection.

append the event to featurecode. we rely on the string being zero-filled, and not overflowing it.

Todo:
XXX how do we guarantee the latter ?

Definition at line 1376 of file res_features.c.

References ast_channel::appl, ast_answer(), ast_cdr_alloc(), ast_cdr_appenduserfield(), ast_cdr_discard(), AST_CDR_FLAG_LOCKED, ast_cdr_init(), ast_cdr_merge(), ast_cdr_setdestchan(), ast_cdr_setuserfield(), ast_cdr_start(), ast_channel_bridge(), ast_channel_setoption(), ast_check_hangup(), ast_clear_flag, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HANGUP, AST_CONTROL_HOLD, AST_CONTROL_OPTION, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_dtmf_stream(), ast_feature_interpret(), AST_FEATURE_PLAY_WARNING, AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_DTMF_BEGIN, ast_frfree, ast_indicate(), ast_indicate_data(), ast_log(), AST_OPTION_FLAG_REQUEST, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cdr, ast_cdr::channel, config, ast_channel::data, ast_option_header::data, ast_cdr::dstchannel, f, FEATURE_MAX_LEN, FEATURE_RETURN_PASSDIGITS, FEATURE_RETURN_SUCCESS, FEATURE_SENSE_CHAN, FEATURE_SENSE_PEER, ast_option_header::flag, free, LOG_DEBUG, LOG_WARNING, monitor_app, ast_option_header::option, option_debug, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_exec(), pbx_findapp(), set_config_flags(), and ast_cdr::userfield.

Referenced by app_exec(), ast_bridge_call_thread(), bridge_exec(), builtin_atxfer(), park_exec(), and try_calling().

01377 {
01378    /* Copy voice back and forth between the two channels.  Give the peer
01379       the ability to transfer calls with '#<extension' syntax. */
01380    struct ast_frame *f;
01381    struct ast_channel *who;
01382    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01383    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01384    int res;
01385    int diff;
01386    int hasfeatures=0;
01387    int hadfeatures=0;
01388    struct ast_option_header *aoh;
01389    struct ast_bridge_config backup_config;
01390    struct ast_cdr *bridge_cdr;
01391 
01392    memset(&backup_config, 0, sizeof(backup_config));
01393 
01394    config->start_time = ast_tvnow();
01395 
01396    if (chan && peer) {
01397       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01398       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01399    } else if (chan)
01400       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01401 
01402    if (monitor_ok) {
01403       const char *monitor_exec;
01404       struct ast_channel *src = NULL;
01405       if (!monitor_app) { 
01406          if (!(monitor_app = pbx_findapp("Monitor")))
01407             monitor_ok=0;
01408       }
01409       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01410          src = chan;
01411       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01412          src = peer;
01413       if (monitor_app && src) {
01414          char *tmp = ast_strdupa(monitor_exec);
01415          pbx_exec(src, monitor_app, tmp);
01416       }
01417    }
01418    
01419    set_config_flags(chan, peer, config);
01420    config->firstpass = 1;
01421 
01422    /* Answer if need be */
01423    if (ast_answer(chan))
01424       return -1;
01425    peer->appl = "Bridged Call";
01426    peer->data = chan->name;
01427 
01428    /* copy the userfield from the B-leg to A-leg if applicable */
01429    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01430       char tmp[256];
01431       if (!ast_strlen_zero(chan->cdr->userfield)) {
01432          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01433          ast_cdr_appenduserfield(chan, tmp);
01434       } else
01435          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01436       /* free the peer's cdr without ast_cdr_free complaining */
01437       free(peer->cdr);
01438       peer->cdr = NULL;
01439    }
01440 
01441    for (;;) {
01442       struct ast_channel *other; /* used later */
01443 
01444       res = ast_channel_bridge(chan, peer, config, &f, &who);
01445 
01446       if (config->feature_timer) {
01447          /* Update time limit for next pass */
01448          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01449          config->feature_timer -= diff;
01450          if (hasfeatures) {
01451             /* Running on backup config, meaning a feature might be being
01452                activated, but that's no excuse to keep things going 
01453                indefinitely! */
01454             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01455                if (option_debug)
01456                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01457                config->feature_timer = 0;
01458                who = chan;
01459                if (f)
01460                   ast_frfree(f);
01461                f = NULL;
01462                res = 0;
01463             } else if (config->feature_timer <= 0) {
01464                /* Not *really* out of time, just out of time for
01465                   digits to come in for features. */
01466                if (option_debug)
01467                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01468                if (!ast_strlen_zero(peer_featurecode)) {
01469                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01470                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01471                }
01472                if (!ast_strlen_zero(chan_featurecode)) {
01473                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01474                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01475                }
01476                if (f)
01477                   ast_frfree(f);
01478                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01479                if (!hasfeatures) {
01480                   /* Restore original (possibly time modified) bridge config */
01481                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01482                   memset(&backup_config, 0, sizeof(backup_config));
01483                }
01484                hadfeatures = hasfeatures;
01485                /* Continue as we were */
01486                continue;
01487             } else if (!f) {
01488                /* The bridge returned without a frame and there is a feature in progress.
01489                 * However, we don't think the feature has quite yet timed out, so just
01490                 * go back into the bridge. */
01491                continue;
01492             }
01493          } else {
01494             if (config->feature_timer <=0) {
01495                /* We ran out of time */
01496                config->feature_timer = 0;
01497                who = chan;
01498                if (f)
01499                   ast_frfree(f);
01500                f = NULL;
01501                res = 0;
01502             }
01503          }
01504       }
01505       if (res < 0) {
01506          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01507             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01508          return -1;
01509       }
01510       
01511       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01512             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01513                f->subclass == AST_CONTROL_CONGESTION))) {
01514          res = -1;
01515          break;
01516       }
01517       /* many things should be sent to the 'other' channel */
01518       other = (who == chan) ? peer : chan;
01519       if (f->frametype == AST_FRAME_CONTROL) {
01520          switch (f->subclass) {
01521          case AST_CONTROL_RINGING:
01522          case AST_CONTROL_FLASH:
01523          case -1:
01524             ast_indicate(other, f->subclass);
01525             break;
01526          case AST_CONTROL_HOLD:
01527          case AST_CONTROL_UNHOLD:
01528             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01529             break;
01530          case AST_CONTROL_OPTION:
01531             aoh = f->data;
01532             /* Forward option Requests */
01533             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01534                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01535                   f->datalen - sizeof(struct ast_option_header), 0);
01536             }
01537             break;
01538          }
01539       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01540          /* eat it */
01541       } else if (f->frametype == AST_FRAME_DTMF) {
01542          char *featurecode;
01543          int sense;
01544 
01545          hadfeatures = hasfeatures;
01546          /* This cannot overrun because the longest feature is one shorter than our buffer */
01547          if (who == chan) {
01548             sense = FEATURE_SENSE_CHAN;
01549             featurecode = chan_featurecode;
01550          } else  {
01551             sense = FEATURE_SENSE_PEER;
01552             featurecode = peer_featurecode;
01553          }
01554          /*! append the event to featurecode. we rely on the string being zero-filled, and
01555           * not overflowing it. 
01556           * \todo XXX how do we guarantee the latter ?
01557           */
01558          featurecode[strlen(featurecode)] = f->subclass;
01559          /* Get rid of the frame before we start doing "stuff" with the channels */
01560          ast_frfree(f);
01561          f = NULL;
01562          config->feature_timer = backup_config.feature_timer;
01563          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01564          switch(res) {
01565          case FEATURE_RETURN_PASSDIGITS:
01566             ast_dtmf_stream(other, who, featurecode, 0);
01567             /* Fall through */
01568          case FEATURE_RETURN_SUCCESS:
01569             memset(featurecode, 0, sizeof(chan_featurecode));
01570             break;
01571          }
01572          if (res >= FEATURE_RETURN_PASSDIGITS) {
01573             res = 0;
01574          } else 
01575             break;
01576          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01577          if (hadfeatures && !hasfeatures) {
01578             /* Restore backup */
01579             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01580             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01581          } else if (hasfeatures) {
01582             if (!hadfeatures) {
01583                /* Backup configuration */
01584                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01585                /* Setup temporary config options */
01586                config->play_warning = 0;
01587                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01588                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01589                config->warning_freq = 0;
01590                config->warning_sound = NULL;
01591                config->end_sound = NULL;
01592                config->start_sound = NULL;
01593                config->firstpass = 0;
01594             }
01595             config->start_time = ast_tvnow();
01596             config->feature_timer = featuredigittimeout;
01597             if (option_debug)
01598                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01599          }
01600       }
01601       if (f)
01602          ast_frfree(f);
01603 
01604    }
01605 
01606    /* arrange the cdrs */
01607    bridge_cdr = ast_cdr_alloc();
01608    if (bridge_cdr) {
01609       if (chan->cdr && peer->cdr) { /* both of them? merge */
01610          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01611          ast_cdr_start(bridge_cdr); /* now is the time to start */
01612 
01613          /* absorb the channel cdr */
01614          ast_cdr_merge(bridge_cdr, chan->cdr);
01615          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01616             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01617          
01618          /* absorb the peer cdr */
01619          ast_cdr_merge(bridge_cdr, peer->cdr);
01620          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01621             ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
01622          
01623          peer->cdr = NULL;
01624          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01625       } else if (chan->cdr) {
01626          /* take the cdr from the channel - literally */
01627          ast_cdr_init(bridge_cdr,chan);
01628          /* absorb this data */
01629          ast_cdr_merge(bridge_cdr, chan->cdr);
01630          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01631             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01632          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01633       } else if (peer->cdr) {
01634          /* take the cdr from the peer - literally */
01635          ast_cdr_init(bridge_cdr,peer);
01636          /* absorb this data */
01637          ast_cdr_merge(bridge_cdr, peer->cdr);
01638          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01639             ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01640          peer->cdr = NULL;
01641          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01642       } else {
01643          /* make up a new cdr */
01644          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01645          chan->cdr = bridge_cdr; /*  */
01646       }
01647       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01648          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01649             ast_cdr_setdestchan(bridge_cdr, peer->name);
01650          else
01651             ast_cdr_setdestchan(bridge_cdr, chan->name);
01652       }
01653    }
01654    return res;
01655 }

int ast_masq_park_call ( struct ast_channel rchan,
struct ast_channel host,
int  timeout,
int *  extout 
)

Park a call via a masqueraded channel.

Parameters:
rchan the real channel to be parked
host the channel to have the parking read to Masquerade the channel rchan into a new, empty channel which is then parked with ast_park_call
timeout is a timeout in milliseconds
extout is a parameter to an int that will hold the parked location, or NULL if you want

Definition at line 477 of file res_features.c.

References ast_channel::amaflags, ast_channel_alloc(), ast_channel_masquerade(), ast_frfree, ast_log(), ast_read(), AST_STATE_DOWN, ast_strdupa, ast_channel::context, ast_channel::exten, f, LOG_WARNING, park_call_full(), ast_channel::priority, ast_channel::readformat, set_c_e_p(), and ast_channel::writeformat.

Referenced by manager_park(), mgcp_ss(), parkandannounce_exec(), and ss_thread().

00478 {
00479    struct ast_channel *chan;
00480    struct ast_frame *f;
00481    char *orig_chan_name = NULL;
00482 
00483    /* Make a new, fake channel that we'll use to masquerade in the real one */
00484    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00485       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00486       return -1;
00487    }
00488 
00489    /* Make formats okay */
00490    chan->readformat = rchan->readformat;
00491    chan->writeformat = rchan->writeformat;
00492    ast_channel_masquerade(chan, rchan);
00493 
00494    /* Setup the extensions and such */
00495    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00496 
00497    /* Make the masq execute */
00498    f = ast_read(chan);
00499    if (f)
00500       ast_frfree(f);
00501 
00502    orig_chan_name = ast_strdupa(chan->name);
00503 
00504    park_call_full(chan, peer, timeout, extout, orig_chan_name);
00505 
00506    return 0;
00507 }

int ast_park_call ( struct ast_channel chan,
struct ast_channel peer,
int  timeout,
int *  extout 
)

Park a call and read back parked location.

Note:
We put the user in the parking list, then wake up the parking thread to be sure it looks after these channels too

Definition at line 472 of file res_features.c.

References park_call_full().

Referenced by builtin_blindtransfer(), builtin_parkcall(), iax_park_thread(), and sip_park_thread().

00473 {
00474    return park_call_full(chan, peer, timeout, extout, NULL);
00475 }

char* ast_parking_ext ( void   ) 

Determine system parking extension Returns the call parking extension for drivers that provide special call parking help.

Definition at line 159 of file res_features.c.

Referenced by builtin_blindtransfer(), dp_lookup(), handle_request_refer(), mgcp_ss(), socket_process(), and ss_thread().

00160 {
00161    return parking_ext;
00162 }

int ast_pickup_call ( struct ast_channel chan  ) 

Pickup a call.

Definition at line 2324 of file res_features.c.

References ast_channel::_state, ast_answer(), ast_channel_masquerade(), ast_channel_unlock, ast_channel_walk_locked(), AST_CONTROL_ANSWER, ast_log(), ast_queue_control(), AST_STATE_RING, AST_STATE_RINGING, ast_channel::callgroup, LOG_DEBUG, LOG_WARNING, option_debug, ast_channel::pbx, and ast_channel::pickupgroup.

Referenced by cb_events(), handle_request_invite(), mgcp_ss(), and ss_thread().

02325 {
02326    struct ast_channel *cur = NULL;
02327    int res = -1;
02328 
02329    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
02330       if (!cur->pbx && 
02331          (cur != chan) &&
02332          (chan->pickupgroup & cur->callgroup) &&
02333          ((cur->_state == AST_STATE_RINGING) ||
02334           (cur->_state == AST_STATE_RING))) {
02335             break;
02336       }
02337       ast_channel_unlock(cur);
02338    }
02339    if (cur) {
02340       if (option_debug)
02341          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02342       res = ast_answer(chan);
02343       if (res)
02344          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02345       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02346       if (res)
02347          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02348       res = ast_channel_masquerade(cur, chan);
02349       if (res)
02350          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02351       ast_channel_unlock(cur);
02352    } else   {
02353       if (option_debug)
02354          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02355    }
02356    return res;
02357 }

char* ast_pickup_ext ( void   ) 

Determine system call pickup extension.

Definition at line 164 of file res_features.c.

Referenced by cb_events(), get_destination(), handle_request_invite(), handle_showfeatures(), mgcp_ss(), and ss_thread().

00165 {
00166    return pickup_ext;
00167 }

void ast_register_feature ( struct ast_call_feature feature  ) 

register new feature into feature_set

Parameters:
feature an ast_call_feature object which contains a keysequence and a callback function which is called when this keysequence is pressed during a call.

Definition at line 945 of file res_features.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_verbose(), LOG_NOTICE, option_verbose, ast_call_feature::sname, and VERBOSE_PREFIX_2.

00946 {
00947    if (!feature) {
00948       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00949          return;
00950    }
00951   
00952    AST_LIST_LOCK(&feature_list);
00953    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00954    AST_LIST_UNLOCK(&feature_list);
00955 
00956    if (option_verbose >= 2) 
00957       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00958 }

void ast_unregister_feature ( struct ast_call_feature feature  ) 

unregister feature from feature_set

Parameters:
feature the ast_call_feature object which was registered before

Definition at line 961 of file res_features.c.

References AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, and free.

00962 {
00963    if (!feature)
00964       return;
00965 
00966    AST_LIST_LOCK(&feature_list);
00967    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00968    AST_LIST_UNLOCK(&feature_list);
00969    free(feature);
00970 }


Generated on Mon Mar 31 07:40:37 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1