diff -r -u asterisk-1.2.10/channel.c asterisk-1.2.10-aoc/channel.c --- asterisk-1.2.10/channel.c 2006-07-10 23:01:35.000000000 +0200 +++ asterisk-1.2.10-aoc/channel.c 2006-07-31 10:56:40.000000000 +0200 @@ -599,6 +599,9 @@ tmp->tech = &null_tech; + tmp->aocd_units=-1; + tmp->aocd_units_type=-1; + ast_mutex_lock(&chlock); tmp->next = channels; channels = tmp; @@ -2016,6 +2019,11 @@ int ast_indicate(struct ast_channel *chan, int condition) { + return ast_indicate_data(chan, condition, NULL, 0); +} + +int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen) +{ int res = -1; ast_mutex_lock(&chan->lock); @@ -2025,7 +2033,7 @@ return -1; } if (chan->tech->indicate) - res = chan->tech->indicate(chan, condition); + res = chan->tech->indicate(chan, condition, data, datalen); ast_mutex_unlock(&chan->lock); if (!chan->tech->indicate || res) { /* diff -r -u asterisk-1.2.10/channels/chan_agent.c asterisk-1.2.10-aoc/channels/chan_agent.c --- asterisk-1.2.10/channels/chan_agent.c 2006-07-06 22:38:45.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_agent.c 2006-07-31 11:19:16.000000000 +0200 @@ -249,7 +249,7 @@ static int agent_write(struct ast_channel *ast, struct ast_frame *f); static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); static int agent_sendtext(struct ast_channel *ast, const char *text); -static int agent_indicate(struct ast_channel *ast, int condition); +static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge); @@ -610,7 +610,7 @@ return 0; } -static int agent_indicate(struct ast_channel *ast, int condition) +static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) { struct agent_pvt *p = ast->tech_pvt; int res = -1; diff -r -u asterisk-1.2.10/channels/chan_alsa.c asterisk-1.2.10-aoc/channels/chan_alsa.c --- asterisk-1.2.10/channels/chan_alsa.c 2005-12-21 21:01:16.000000000 +0100 +++ asterisk-1.2.10-aoc/channels/chan_alsa.c 2006-07-31 11:19:28.000000000 +0200 @@ -178,7 +178,7 @@ static struct ast_frame *alsa_read(struct ast_channel *chan); static int alsa_call(struct ast_channel *c, char *dest, int timeout); static int alsa_write(struct ast_channel *chan, struct ast_frame *f); -static int alsa_indicate(struct ast_channel *chan, int cond); +static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen); static int alsa_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static const struct ast_channel_tech alsa_tech = { @@ -745,7 +745,7 @@ return 0; } -static int alsa_indicate(struct ast_channel *chan, int cond) +static int alsa_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen) { int res = 0; ast_mutex_lock(&alsalock); diff -r -u asterisk-1.2.10/channels/chan_features.c asterisk-1.2.10-aoc/channels/chan_features.c --- asterisk-1.2.10/channels/chan_features.c 2006-07-03 06:19:09.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_features.c 2006-07-31 11:19:45.000000000 +0200 @@ -101,7 +101,7 @@ static int features_answer(struct ast_channel *ast); static struct ast_frame *features_read(struct ast_channel *ast); static int features_write(struct ast_channel *ast, struct ast_frame *f); -static int features_indicate(struct ast_channel *ast, int condition); +static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); static int features_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static const struct ast_channel_tech features_tech = { @@ -286,7 +286,7 @@ return 0; } -static int features_indicate(struct ast_channel *ast, int condition) +static int features_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) { struct feature_pvt *p = ast->tech_pvt; int res = -1; diff -r -u asterisk-1.2.10/channels/chan_h323.c asterisk-1.2.10-aoc/channels/chan_h323.c --- asterisk-1.2.10/channels/chan_h323.c 2006-07-03 06:19:09.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_h323.c 2006-07-31 11:19:53.000000000 +0200 @@ -200,7 +200,7 @@ static int oh323_answer(struct ast_channel *c); static struct ast_frame *oh323_read(struct ast_channel *c); static int oh323_write(struct ast_channel *c, struct ast_frame *frame); -static int oh323_indicate(struct ast_channel *c, int condition); +static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen); static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static const struct ast_channel_tech oh323_tech = { @@ -627,7 +627,7 @@ return res; } -static int oh323_indicate(struct ast_channel *c, int condition) +static int oh323_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen) { struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt; diff -r -u asterisk-1.2.10/channels/chan_iax2.c asterisk-1.2.10-aoc/channels/chan_iax2.c --- asterisk-1.2.10/channels/chan_iax2.c 2006-07-12 17:23:59.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_iax2.c 2006-07-31 11:20:01.000000000 +0200 @@ -744,7 +744,7 @@ static int iax2_answer(struct ast_channel *c); static struct ast_frame *iax2_read(struct ast_channel *c); static int iax2_write(struct ast_channel *c, struct ast_frame *f); -static int iax2_indicate(struct ast_channel *c, int condition); +static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen); static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen); static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms); static int iax2_transfer(struct ast_channel *c, const char *dest); @@ -3362,7 +3362,7 @@ return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1); } -static int iax2_indicate(struct ast_channel *c, int condition) +static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen) { unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); if (option_debug && iaxdebug) diff -r -u asterisk-1.2.10/channels/chan_local.c asterisk-1.2.10-aoc/channels/chan_local.c --- asterisk-1.2.10/channels/chan_local.c 2006-07-03 06:19:09.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_local.c 2006-07-31 11:20:10.000000000 +0200 @@ -77,7 +77,7 @@ static int local_answer(struct ast_channel *ast); static struct ast_frame *local_read(struct ast_channel *ast); static int local_write(struct ast_channel *ast, struct ast_frame *f); -static int local_indicate(struct ast_channel *ast, int condition); +static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); @@ -278,7 +278,7 @@ return 0; } -static int local_indicate(struct ast_channel *ast, int condition) +static int local_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) { struct local_pvt *p = ast->tech_pvt; int res = -1; diff -r -u asterisk-1.2.10/channels/chan_mgcp.c asterisk-1.2.10-aoc/channels/chan_mgcp.c --- asterisk-1.2.10/channels/chan_mgcp.c 2006-07-03 06:19:09.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_mgcp.c 2006-07-31 11:20:20.000000000 +0200 @@ -493,7 +493,7 @@ static int mgcp_answer(struct ast_channel *ast); static struct ast_frame *mgcp_read(struct ast_channel *ast); static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame); -static int mgcp_indicate(struct ast_channel *ast, int ind); +static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen); static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int mgcp_senddigit(struct ast_channel *ast, char digit); @@ -1344,7 +1344,7 @@ return "UNKNOWN"; } -static int mgcp_indicate(struct ast_channel *ast, int ind) +static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen) { struct mgcp_subchannel *sub = ast->tech_pvt; int res = 0; diff -r -u asterisk-1.2.10/channels/chan_misdn.c asterisk-1.2.10-aoc/channels/chan_misdn.c --- asterisk-1.2.10/channels/chan_misdn.c 2006-07-03 06:19:09.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_misdn.c 2006-07-31 12:00:26.000000000 +0200 @@ -1481,7 +1481,7 @@ -int misdn_indication(struct ast_channel *ast, int cond) +int misdn_indication(struct ast_channel *ast, int cond, const void *data, size_t datalen) { struct chan_list *p; diff -r -u asterisk-1.2.10/channels/chan_oss.c asterisk-1.2.10-aoc/channels/chan_oss.c --- asterisk-1.2.10/channels/chan_oss.c 2006-07-05 17:31:01.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_oss.c 2006-07-31 11:22:07.000000000 +0200 @@ -324,7 +324,7 @@ static struct ast_frame *oss_read(struct ast_channel *chan); static int oss_call(struct ast_channel *c, char *dest, int timeout); static int oss_write(struct ast_channel *chan, struct ast_frame *f); -static int oss_indicate(struct ast_channel *chan, int cond); +static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen); static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static const struct ast_channel_tech oss_tech = { @@ -835,7 +835,7 @@ return 0; } -static int oss_indicate(struct ast_channel *c, int cond) +static int oss_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen) { struct chan_oss_pvt *o = c->tech_pvt; int res; diff -r -u asterisk-1.2.10/channels/chan_oss_old.c asterisk-1.2.10-aoc/channels/chan_oss_old.c --- asterisk-1.2.10/channels/chan_oss_old.c 2005-11-29 19:24:39.000000000 +0100 +++ asterisk-1.2.10-aoc/channels/chan_oss_old.c 2006-07-31 11:22:14.000000000 +0200 @@ -142,7 +142,7 @@ static struct ast_frame *oss_read(struct ast_channel *chan); static int oss_call(struct ast_channel *c, char *dest, int timeout); static int oss_write(struct ast_channel *chan, struct ast_frame *f); -static int oss_indicate(struct ast_channel *chan, int cond); +static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen); static int oss_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static const struct ast_channel_tech oss_tech = { @@ -733,7 +733,7 @@ return 0; } -static int oss_indicate(struct ast_channel *chan, int cond) +static int oss_indicate(struct ast_channel *chan, int cond, const void *data, size_t datalen) { int res; switch(cond) { diff -r -u asterisk-1.2.10/channels/chan_sip.c asterisk-1.2.10-aoc/channels/chan_sip.c --- asterisk-1.2.10/channels/chan_sip.c 2006-07-13 18:44:23.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_sip.c 2006-07-31 12:17:21.000000000 +0200 @@ -916,7 +916,7 @@ static int sip_answer(struct ast_channel *ast); static struct ast_frame *sip_read(struct ast_channel *ast); static int sip_write(struct ast_channel *ast, struct ast_frame *frame); -static int sip_indicate(struct ast_channel *ast, int condition); +static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); static int sip_transfer(struct ast_channel *ast, const char *dest); static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int sip_senddigit(struct ast_channel *ast, char digit); @@ -2652,7 +2652,7 @@ /*! \brief sip_indicate: Play indication to user * With SIP a lot of indications is sent as messages, letting the device play the indication - busy signal, congestion etc */ -static int sip_indicate(struct ast_channel *ast, int condition) +static int sip_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) { struct sip_pvt *p = ast->tech_pvt; int res = 0; diff -r -u asterisk-1.2.10/channels/chan_skinny.c asterisk-1.2.10-aoc/channels/chan_skinny.c --- asterisk-1.2.10/channels/chan_skinny.c 2006-07-03 06:19:09.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_skinny.c 2006-07-31 11:22:38.000000000 +0200 @@ -903,7 +903,7 @@ static int skinny_answer(struct ast_channel *ast); static struct ast_frame *skinny_read(struct ast_channel *ast); static int skinny_write(struct ast_channel *ast, struct ast_frame *frame); -static int skinny_indicate(struct ast_channel *ast, int ind); +static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen); static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int skinny_senddigit(struct ast_channel *ast, char digit); @@ -2169,7 +2169,7 @@ } -static int skinny_indicate(struct ast_channel *ast, int ind) +static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen) { struct skinny_subchannel *sub = ast->tech_pvt; struct skinny_line *l = sub->parent; diff -r -u asterisk-1.2.10/channels/chan_vpb.c asterisk-1.2.10-aoc/channels/chan_vpb.c --- asterisk-1.2.10/channels/chan_vpb.c 2005-11-29 19:24:39.000000000 +0100 +++ asterisk-1.2.10-aoc/channels/chan_vpb.c 2006-07-31 11:22:47.000000000 +0200 @@ -345,7 +345,7 @@ static struct ast_frame *vpb_read(struct ast_channel *ast); static int vpb_write(struct ast_channel *ast, struct ast_frame *frame); static enum ast_bridge_result vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms); -static int vpb_indicate(struct ast_channel *ast, int condition); +static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static struct ast_channel_tech vpb_tech = { @@ -1709,7 +1709,7 @@ return tmp; } -static int vpb_indicate(struct ast_channel *ast, int condition) +static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) { struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; int res = 0; diff -r -u asterisk-1.2.10/channels/chan_zap.c asterisk-1.2.10-aoc/channels/chan_zap.c --- asterisk-1.2.10/channels/chan_zap.c 2006-07-12 15:54:10.000000000 +0200 +++ asterisk-1.2.10-aoc/channels/chan_zap.c 2006-07-31 12:31:09.000000000 +0200 @@ -220,6 +220,8 @@ static ast_group_t cur_pickupgroup = 0; static int relaxdtmf = 0; +static int allow_aoc = 0; + static int immediate = 0; static int stripmsd = 0; @@ -465,6 +467,11 @@ static int dialplan = PRI_NATIONAL_ISDN + 1; static int localdialplan = PRI_NATIONAL_ISDN + 1; +struct aocd_data { + int units; + int units_type; +}; + #else /*! Shut up the compiler */ struct zt_pri; @@ -566,6 +573,7 @@ unsigned int hardwaredtmf:1; unsigned int hidecallerid; unsigned int ignoredtmf:1; + unsigned int allow_aoc:1; /*!< Handle and generate AOC messages? */ unsigned int immediate:1; /*!< Answer before getting digits? */ unsigned int inalarm:1; unsigned int mate:1; /*!< flag to say its in MATE mode */ @@ -698,7 +706,7 @@ struct ast_frame *zt_read(struct ast_channel *ast); static int zt_write(struct ast_channel *ast, struct ast_frame *frame); struct ast_frame *zt_exception(struct ast_channel *ast); -static int zt_indicate(struct ast_channel *chan, int condition); +static int zt_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen); static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int zt_setoption(struct ast_channel *chan, int option, void *data, int datalen); @@ -3285,7 +3293,7 @@ p->subs[x].owner = newchan; } if (newchan->_state == AST_STATE_RINGING) - zt_indicate(newchan, AST_CONTROL_RINGING); + zt_indicate(newchan, AST_CONTROL_RINGING, NULL, 0); update_conf(p); ast_mutex_unlock(&p->lock); return 0; @@ -4802,7 +4810,7 @@ return 0; } -static int zt_indicate(struct ast_channel *chan, int condition) +static int zt_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen) { struct zt_pvt *p = chan->tech_pvt; int res=-1; @@ -4958,6 +4966,63 @@ } else res = 0; break; + case AST_CONTROL_AOCD: + /* generate a FACILITY message with AOC-D */ + if (!p->allow_aoc) { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "AOC deactivated, ignoring AOCD control frame for channel '%s'\n", chan->name); + break; + } + if (p->sig == SIG_PRI) { /* Only SIG_PRI supports AOC-D */ + if(!pri_grab(p, p->pri)) { + struct aocd_data *aocd; + aocd = (struct aocd_data *)data; + ast_verbose(VERBOSE_PREFIX_3 "klaus:AST_CONTROL_AOCD: sending AOC-D FACILITY on q931_call %p\n", p->call); + aoc_aocd_charging_unit_encode(p->pri->pri, p->call, aocd->units, aocd->units_type); + if (option_verbose > 2) { + if ( aocd->units == -2) + ast_verbose(VERBOSE_PREFIX_3 "AST_CONTROL_AOCD: generated freeOfCharge AOC-D on %s\n", chan->name); + else + ast_verbose(VERBOSE_PREFIX_3 "AST_CONTROL_AOCD: generated %i unit(s) %s AOC-D on %s\n", aocd->units, aocd->units_type==0?"SUBTOTAL":"TOTAL", chan->name); + } + pri_rel(p->pri); + } else { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "AST_CONTROL_AOCD: Unable to grab PRI for AOC-D on span %d\n", p->span); + } + res=0; + } else { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "AST_CONTROL_AOCD: can't passthrough to channel %s (wrong type)\n", chan->name); + res=0; + } + break; + case AST_CONTROL_AOCE: + /* handle the AOC-E units over to libpri to store inside the q931_call structure. this will be used by + libpri when hanging up this call. */ + if (!p->allow_aoc) { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "AOC deactivated, ignoring AOCE control frame for channel '%s'\n", chan->name); + break; + } + if (p->sig == SIG_PRI) { /* Only SIG_PRI supports AOC-E */ + int aoce_units; + aoce_units = *(int *)data; + ast_verbose(VERBOSE_PREFIX_3 "klaus: AST_CONTROL_AOCE: adding aoce units to q931_call %p\n", p->call); + aoc_aoce_add_units_to_call(p->call, aoce_units); + if (option_verbose > 2) { + if ( aoce_units == -2) + ast_verbose(VERBOSE_PREFIX_3 "AST_CONTROL_AOCE: marked channel %s with freeOfCharge AOC-E\n", chan->name); + else + ast_verbose(VERBOSE_PREFIX_3 "AST_CONTROL_AOCE: marked channel %s with %i unit(s) AOC-E\n", chan->name, aoce_units); + } + res=0; + } else { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "AST_CONTROL_AOCE: can't mark channel %s with AOC-E: wrong type\n", chan->name); + res=0; + } + break; case -1: res = tone_zone_play_tone(p->subs[index].zfd, -1); break; @@ -7097,6 +7162,7 @@ ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d\n", channel); } #endif + tmp->allow_aoc = allow_aoc; tmp->immediate = immediate; tmp->transfertobusy = transfertobusy; tmp->sig = signalling; @@ -8711,6 +8777,42 @@ PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span); chanpos = -1; } else { + + /* Q.956 AOC-D bridging */ + ast_verbose(VERBOSE_PREFIX_3 "klaus: PRI_EVENT_FACNAME: e->facname.aocd_units = %d\n",e->facname.aocd_units); + if ( (e->facname.aocd_units > -1) || (e->facname.aocd_units == -2) ) { /* an AOC-D was received ... */ + if (!pri->pvts[chanpos]->allow_aoc) { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "AOC deactivated, ignoring AOCD in FACILITY event on channel '%s'\n", pri->pvts[chanpos]->owner->name); + } else { + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_FACNAME: received AOC-D FACILITY on q931_call %p\n", pri->pvts[chanpos]->call); + ast_mutex_lock(&pri->pvts[chanpos]->lock); + if (pri->pvts[chanpos]->owner) { + /* store AOC-D data in call structure, can be used to fake AOC-E */ + pri->pvts[chanpos]->owner->aocd_units = e->facname.aocd_units; + pri->pvts[chanpos]->owner->aocd_units_type = e->facname.aocd_units_type; + struct ast_channel *otherchan; + otherchan = ast_bridged_channel(pri->pvts[chanpos]->owner); + if (otherchan && (!strcmp(otherchan->tech->type, "Zap"))) { /* Only for Zap channels */ + struct aocd_data aocd; + aocd.units = e->facname.aocd_units; + aocd.units_type = e->facname.aocd_units_type; + if (option_verbose > 2) { + if (e->facname.aocd_units == -2) + ast_verbose(VERBOSE_PREFIX_3 "AOC-D: passing freeOfCharge AOC-D from %s to %s\n", pri->pvts[chanpos]->owner->name, otherchan->name); + else + ast_verbose(VERBOSE_PREFIX_3 "AOC-D: passing %i unit(s) %s AOC-D from %s to %s\n", aocd.units, aocd.units_type==0?"SUBTOTAL":"TOTAL", pri->pvts[chanpos]->owner->name, otherchan->name); + } + ast_verbose(VERBOSE_PREFIX_3 "klaus: PRI_EVENT_FACNAME: prepare to indicate units to q931_call %p\n", ((struct zt_pvt*)otherchan->tech_pvt)->call); + ast_indicate_data(otherchan, AST_CONTROL_AOCD, &aocd, sizeof(struct aocd_data)); + } else { + ast_verbose(VERBOSE_PREFIX_3 "no bridged called found for passing the AOC-D\n"); + } + } + ast_mutex_unlock(&pri->pvts[chanpos]->lock); + } + } /* end AOC-D code */ + /* Re-use *69 field for PRI */ ast_mutex_lock(&pri->pvts[chanpos]->lock); ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num)); @@ -8831,10 +8933,10 @@ pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos])); pri->pvts[chanpos]->resetting = 1; } - if (e->hangup.aoc_units > -1) + if (e->hangup.aoce_units > -1) if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E charging %d unit%s\n", - pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s"); + ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E on hangup charging %d unit%s\n", + pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoce_units, (e->hangup.aoce_units == 1) ? "" : "s"); #ifdef SUPPORT_USERUSER if (!ast_strlen_zero(e->hangup.useruserinfo)) { @@ -8884,10 +8986,69 @@ } if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d got hangup request\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span); - if (e->hangup.aoc_units > -1) + ast_verbose(VERBOSE_PREFIX_3 "klaus: PRI_EVENT_HANGUP_REQ: received PRI_EVENT_HANGUP_REQ on q931_call %p\n", pri->pvts[chanpos]->call); + if ( (e->hangup.aoce_units > -1) || (e->hangup.aoce_units == -2) ) { + /* hangup-request contained AOC-E */ if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E charging %d unit%s\n", - pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s"); + ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received AOC-E on hangup-req charging %d unit%s\n", + pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoce_units, (e->hangup.aoce_units == 1) ? "" : "s"); + if (!pri->pvts[chanpos]->allow_aoc) { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "PRI_EVENT_HANGUP_REQ: AOC deactivated, ignoring AOCE in hangup-req event on channel '%s'\n", pri->pvts[chanpos]->owner->name); + } else { + struct ast_channel *otherchan; + otherchan = ast_bridged_channel(pri->pvts[chanpos]->owner); + if (otherchan && (!strcmp(otherchan->tech->type, "Zap"))) { /* Only for Zap channels */ + if ( ((struct zt_pvt *)otherchan->tech_pvt)->sig == SIG_PRI ) { /* Only SIG_PRI supports AOC-D */ + ast_verbose(VERBOSE_PREFIX_3 "klaus: PRI_EVENT_HANGUP_REQ: prepare to indicate units to q931_call %p\n", ((struct zt_pvt*)otherchan->tech_pvt)->call); + ast_indicate_data(otherchan, AST_CONTROL_AOCE, &(e->hangup.aoce_units), sizeof(int)); + if (option_verbose > 2) { + if (e->hangup.aoce_units == -2) + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_HANGUP_REQ: passing freeOfCharge AOC-E from %s to %s\n", pri->pvts[chanpos]->owner->name, otherchan->name); + else + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_HANGUP_REQ: passing %i unit(s) AOC-E from %s to %s\n", e->hangup.aoce_units, pri->pvts[chanpos]->owner->name, otherchan->name); + } + } else { + ast_verbose(VERBOSE_PREFIX_3 "AOC-E: can't passthrough to channel %s (wrong type)\n", otherchan->name); + } + } else { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_HANGUP_REQ: no bridged called found for passing the AOC-E\n"); + } + } + } else { + /* No AOC-E received, check if there is AOC-D on other call leg which + can be used to fake an AOC-E on this call leg */ + if (pri->pvts[chanpos]->allow_aoc) { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "PRI_EVENT_HANGUP_REQ: AOC activated, try to fake AOCE on channel '%s'\n", pri->pvts[chanpos]->owner->name); + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Channel %d/%d, span %d received hangup-req without AOC-E, checking for AOC-D on bridged call leg\n", + pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span); + struct ast_channel *otherchan; + otherchan = ast_bridged_channel(pri->pvts[chanpos]->owner); + if (otherchan && (!strcmp(otherchan->tech->type, "Zap"))) { /* Only for Zap channels */ + if ( ((struct zt_pvt *)otherchan->tech_pvt)->sig == SIG_PRI) { /* Only SIG_PRI supports AOC */ + if (otherchan->aocd_units != -1 ) { + /* fetch aocd from bridged channel and send it currents channels as aoce */ + ast_verbose(VERBOSE_PREFIX_3 "klaus: PRI_EVENT_HANGUP_REQ: fake AOC-E: adding AOCE to q931_call %p\n", pri->pvts[chanpos]->call); + aoc_aoce_add_units_to_call(pri->pvts[chanpos]->call, otherchan->aocd_units); + if (option_verbose > 2) { + if ( otherchan->aocd_units == -2) + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_HANGUP_REQ: fake AOC-E: marked channel %s with freeOfCharge AOC-E\n", pri->pvts[chanpos]->owner->name); + else + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_HANGUP_REQ: fake AOC-E: marked channel %s with %i unit(s) AOC-E\n", pri->pvts[chanpos]->owner->name, otherchan->aocd_units); + } + } + } else { + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_HANGUP_REQ: can't fake AOC-E, wrong type on channel %s\n", otherchan->name); + } + } else { + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_HANGUP_REQ: no bridged ZAP call found for faking AOC-E\n"); + } + + } + } } else { pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause); pri->pvts[chanpos]->call = NULL; @@ -9040,6 +9201,46 @@ ast_mutex_unlock(&pri->pvts[chanpos]->lock); } break; + case PRI_EVENT_CONNECT_ACK: + chanpos = pri_find_principle(pri, e->connect_ack.channel); + if (chanpos < 0) { + ast_log(LOG_WARNING, "Received CONNECT_ACK on unconfigured channel %d/%d span %d\n", + PRI_SPAN(e->connect_ack.channel), PRI_CHANNEL(e->connect_ack.channel), pri->span); + } else { + chanpos = pri_fixup_principle(pri, chanpos, e->connect_ack.call); + if (chanpos > -1) { + if (pri->pvts[chanpos]->allow_aoc) { + if (option_verbose > 3) + ast_verbose( VERBOSE_PREFIX_4 "PRI_EVENT_CONNECT_ACK: AOC activated, try to relay AOCD on channel '%s'\n", pri->pvts[chanpos]->owner->name); + ast_mutex_lock(&pri->pvts[chanpos]->lock); + /* Send AOC-D if available, check if bridged call leg has received AOC-D yet */ + struct ast_channel *otherchan; + otherchan = ast_bridged_channel(pri->pvts[chanpos]->owner); + if (otherchan && (!strcmp(otherchan->tech->type, "Zap"))) { /* Only for Zap channels */ + if (otherchan->aocd_units != -1) { + ast_verbose(VERBOSE_PREFIX_3 "klaus: PRI_EVENT_CONNECT_ACK: bridged ZAP has %d unit(s) %s AOC-D to send\n", otherchan->aocd_units, otherchan->aocd_units_type==0?"SUBTOTAL":"TOTAL"); + if (option_verbose > 2) { + if (otherchan->aocd_units == -2) + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_CONNECT_ACK: passing freeOfCharge AOC-D from %s to %s\n", otherchan->name, pri->pvts[chanpos]->owner->name); + else + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_CONNECT_ACK: passing %i unit(s) %s AOC-D from %s to %s\n", otherchan->aocd_units, otherchan->aocd_units_type==0?"SUBTOTAL":"TOTAL", otherchan->name, pri->pvts[chanpos]->owner->name); + } + ast_verbose(VERBOSE_PREFIX_3 "klaus: PRI_EVENT_CONNECT_ACK: sending AOC-D FACILITY on q931_call %p\n", pri->pvts[chanpos]->call); + aoc_aocd_charging_unit_encode(pri->pri, pri->pvts[chanpos]->call, otherchan->aocd_units, otherchan->aocd_units_type); + } else { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_CONNECT_ACK: bridged ZAP has no AOC-D to send\n"); + } + } else { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "PRI_EVENT_CONNECT_ACK: no bridged ZAP call found for retrieving AOC-D data\n"); + } + ast_mutex_unlock(&pri->pvts[chanpos]->lock); + } + } else + ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->connect_ack.channel); + } + break; default: ast_log(LOG_DEBUG, "Event: %d\n", e->e); } @@ -9226,7 +9427,7 @@ } for (x=0;xvalue); } else if (!strcasecmp(v->name, "pickupgroup")) { cur_pickupgroup = ast_get_group(v->value); + } else if (!strcasecmp(v->name, "allow_aoc")) { + allow_aoc = ast_true(v->value); } else if (!strcasecmp(v->name, "immediate")) { immediate = ast_true(v->value); } else if (!strcasecmp(v->name, "transfertobusy")) { diff -r -u asterisk-1.2.10/cli.c asterisk-1.2.10-aoc/cli.c --- asterisk-1.2.10/cli.c 2006-02-27 16:20:48.000000000 +0100 +++ asterisk-1.2.10-aoc/cli.c 2006-07-31 10:45:30.000000000 +0200 @@ -776,7 +776,10 @@ " Pickup Group: %d\n" " Application: %s\n" " Data: %s\n" - " Blocking in: %s\n", + " Blocking in: %s\n" + " -- AOC --\n" + " AOCD units: %d\n" + " AOCD type: %s\n", c->name, c->type, c->uniqueid, (c->cid.cid_num ? c->cid.cid_num : "(N/A)"), (c->cid.cid_name ? c->cid.cid_name : "(N/A)"), @@ -786,7 +789,10 @@ cdrtime, c->_bridge ? c->_bridge->name : "", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "", c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ), ( c-> data ? (!ast_strlen_zero(c->data) ? c->data : "(Empty)") : "(None)"), - (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)")); + (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"), + c->aocd_units, + c->aocd_units_type==0?"SUBTOTAL":(c->aocd_units_type==1?"TOTAL":"not available") + ); if(pbx_builtin_serialize_variables(c,buf,sizeof(buf))) ast_cli(fd," Variables:\n%s\n",buf); diff -r -u asterisk-1.2.10/include/asterisk/channel.h asterisk-1.2.10-aoc/include/asterisk/channel.h --- asterisk-1.2.10/include/asterisk/channel.h 2006-06-01 22:27:50.000000000 +0200 +++ asterisk-1.2.10-aoc/include/asterisk/channel.h 2006-07-31 12:08:39.000000000 +0200 @@ -223,7 +223,7 @@ struct ast_frame **fo, struct ast_channel **rc, int timeoutms); /*! Indicate a particular condition (e.g. AST_CONTROL_BUSY or AST_CONTROL_RINGING or AST_CONTROL_CONGESTION */ - int (* const indicate)(struct ast_channel *c, int condition); + int (* const indicate)(struct ast_channel *c, int condition, const void *data, size_t datalen); /*! Fix up a channel: If a channel is consumed, this is called. Basically update any ->owner links */ int (* const fixup)(struct ast_channel *oldchan, struct ast_channel *newchan); @@ -414,6 +414,10 @@ /*! For easy linking */ struct ast_channel *next; + + /*! Advice-of-Charge data */ + int aocd_units; /*!< The actual AOC-D units */ + int aocd_units_type; /*!< Type of the AOC-D units (total or subtotal) */ }; /* \defgroup chanprop Channel tech properties: @@ -683,6 +687,16 @@ */ int ast_indicate(struct ast_channel *chan, int condition); +/*! \brief Indicates condition of channel, with payload + * \note Indicate a condition such as AST_CONTROL_BUSY, AST_CONTROL_RINGING, or AST_CONTROL_CONGESTION on a channel + * \param chan channel to change the indication + * \param condition which condition to indicate on the channel + * \param data pointer to payload data + * \param datalen size of payload data + * \return Returns 0 on success, -1 on failure + */ +int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen); + /* Misc stuff ------------------------------------------------ */ /*! \brief Wait for input on a channel diff -r -u asterisk-1.2.10/include/asterisk/frame.h asterisk-1.2.10-aoc/include/asterisk/frame.h --- asterisk-1.2.10/include/asterisk/frame.h 2005-11-29 19:24:39.000000000 +0100 +++ asterisk-1.2.10-aoc/include/asterisk/frame.h 2006-07-31 10:42:49.000000000 +0200 @@ -243,6 +243,10 @@ #define AST_CONTROL_UNHOLD 17 /*! Indicate video frame update */ #define AST_CONTROL_VIDUPDATE 18 +/*! Indicate an AOC-D update */ +#define AST_CONTROL_AOCD 19 +/*! Indicate an AOC-E update */ +#define AST_CONTROL_AOCE 20 #define AST_SMOOTHER_FLAG_G729 (1 << 0)