[asterisk-commits] moy: branch moy/mfcr2 r176494 - in /team/moy/mfcr2: channels/ configs/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Feb 16 23:30:08 CST 2009
Author: moy
Date: Mon Feb 16 23:30:08 2009
New Revision: 176494
URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=176494
Log:
added mfcr2_accept_on_offer parameter and improved hangup cause management
Modified:
team/moy/mfcr2/channels/chan_dahdi.c
team/moy/mfcr2/configs/chan_dahdi.conf.sample
Modified: team/moy/mfcr2/channels/chan_dahdi.c
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/channels/chan_dahdi.c?view=diff&rev=176494&r1=176493&r2=176494
==============================================================================
--- team/moy/mfcr2/channels/chan_dahdi.c (original)
+++ team/moy/mfcr2/channels/chan_dahdi.c Mon Feb 16 23:30:08 2009
@@ -140,6 +140,23 @@
current channel.</para>
</description>
</application>
+ <application name="DAHDIAcceptR2Call" language="en_US">
+ <synopsis>
+ Accept an R2 call if its not already accepted (you still need to answer it)
+ </synopsis>
+ <syntax>
+ <parameter name="charge" required="true">
+ <para>Yes or No.</para>
+ <para>Whether you want to accept the call with charge or without charge.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>This application will Accept the R2 call either with charge or no charge.</para>
+ </description>
+ <description>
+ <para>This application will Accept the R2 call either with charge or no charge.</para>
+ </description>
+ </application>
***/
#define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
@@ -464,6 +481,7 @@
int call_files:1;
int allow_collect_calls:1;
int charge_calls:1;
+ int accept_on_offer:1;
int forced_release:1;
int double_answer:1;
int immediate_accept:1;
@@ -1191,17 +1209,20 @@
unsigned int loopedback:1;
#endif
#ifdef HAVE_OPENR2
- int mfcr2call;
struct dahdi_mfcr2 *mfcr2;
openr2_chan_t *r2chan;
openr2_calling_party_category_t mfcr2_recvd_category;
openr2_calling_party_category_t mfcr2_category;
- int mfcr2_charge_calls;
- int mfcr2_allow_collect_calls;
- int mfcr2_forced_release;
int mfcr2_dnis_index;
int mfcr2_ani_index;
- int mfcr2_dnis_matched;
+ int mfcr2call:1;
+ int mfcr2_answer_pending:1;
+ int mfcr2_charge_calls:1;
+ int mfcr2_allow_collect_calls:1;
+ int mfcr2_forced_release:1;
+ int mfcr2_dnis_matched:1;
+ int mfcr2_call_accepted:1;
+ int mfcr2_accept_on_offer:1;
#endif
/*! \brief DTMF digit in progress. 0 when no digit in progress. */
char begindigit;
@@ -1290,6 +1311,7 @@
.call_files = 0,
.allow_collect_calls = 0,
.charge_calls = 1,
+ .accept_on_offer = 1,
.forced_release = 0,
.double_answer = 0,
.immediate_accept = -1,
@@ -1624,7 +1646,9 @@
p->exten[0] = '\0';
p->mfcr2_ani_index = '\0';
p->mfcr2_dnis_index = '\0';
- p->mfcr2_dnis_matched = '\0';
+ p->mfcr2_dnis_matched = 0;
+ p->mfcr2_answer_pending = 0;
+ p->mfcr2_call_accepted = 0;
ast_mutex_unlock(&p->lock);
ast_log(LOG_NOTICE, "New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
}
@@ -1665,9 +1689,28 @@
ast_mutex_unlock(&p->lock);
}
+static void dahdi_r2_update_monitor_count(struct dahdi_mfcr2 *mfcr2, int increment)
+{
+ ast_mutex_lock(&mfcr2->monitored_count_lock);
+ if (increment) {
+ mfcr2->monitored_count++;
+ if (mfcr2->monitored_count == 1) {
+ ast_log(LOG_DEBUG, "At least one device needs monitoring, let's wake up the monitor thread.\n");
+ ast_cond_signal(&mfcr2->do_monitor);
+ }
+ } else {
+ mfcr2->monitored_count--;
+ if (mfcr2->monitored_count < 0) {
+ ast_log(LOG_ERROR, "we have a bug here!.\n");
+ }
+ }
+ ast_mutex_unlock(&mfcr2->monitored_count_lock);
+}
+
static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
{
struct dahdi_pvt *p;
+ struct ast_channel *c;
ast_log(LOG_NOTICE, "MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis,
openr2_proto_get_category_string(category));
@@ -1697,12 +1740,27 @@
ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
p->channel, p->exten, p->context);
openr2_chan_disconnect_call(r2chan, OR2_CAUSE_UNALLOCATED_NUMBER);
+ return;
+ }
+ if (!p->mfcr2_accept_on_offer) {
+ /* The user wants us to start the PBX thread right away without accepting the call first */
+ c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
+ if (c) {
+ dahdi_r2_update_monitor_count(p->mfcr2, 0);
+ pbx_builtin_setvar_helper(c, "MFCR2_CATEGORY", openr2_proto_get_category_string(p->mfcr2_recvd_category));
+ /* Done here, don't disable reading now since we still need to generate MF tones to accept
+ the call or reject it and detect the tone off condition of the other end, all of this
+ will be done in the PBX thread now */
+ return;
+ }
+ ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ } else if (p->mfcr2_charge_calls) {
+ ast_log(LOG_DEBUG, "Accepting MFC/R2 call with charge on chan %d\n", p->channel);
+ openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
} else {
- if (p->mfcr2_charge_calls) {
- openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
- } else {
- openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
- }
+ ast_log(LOG_DEBUG, "Accepting MFC/R2 call with no charge on chan %d\n", p->channel);
+ openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
}
}
@@ -1715,23 +1773,6 @@
ast_mutex_unlock(&p->lock);
}
-static void dahdi_r2_update_monitor_count(struct dahdi_mfcr2 *mfcr2, int increment)
-{
- ast_mutex_lock(&mfcr2->monitored_count_lock);
- if (increment) {
- mfcr2->monitored_count++;
- if (mfcr2->monitored_count == 1) {
- ast_log(LOG_DEBUG, "At least one device needs monitoring, let's wake up the monitor thread.\n");
- ast_cond_signal(&mfcr2->do_monitor);
- }
- } else {
- mfcr2->monitored_count--;
- if (mfcr2->monitored_count < 0) {
- ast_log(LOG_ERROR, "we have a bug here!.\n");
- }
- }
- ast_mutex_unlock(&mfcr2->monitored_count_lock);
-}
static void dahdi_enable_ec(struct dahdi_pvt *p);
static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
{
@@ -1740,24 +1781,42 @@
ast_log(LOG_NOTICE, "MFC/R2 call has been accepted on chan %d\n", openr2_chan_get_number(r2chan));
p = openr2_chan_get_client_data(r2chan);
dahdi_enable_ec(p);
+ p->mfcr2_call_accepted = 1;
+ /* if it's an incoming call ... */
if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
+ /* If accept on offer is not set, it means at this point the PBX thread is already
+ launched (was launched in the 'on call offered' handler) and therefore this callback
+ is being executed already in the PBX thread rather than the monitor thread, don't launch
+ any other thread, just disable the openr2 reading and answer the call if needed */
+ if (!p->mfcr2_accept_on_offer) {
+ openr2_chan_disable_read(r2chan);
+ if (p->mfcr2_answer_pending) {
+ ast_log(LOG_DEBUG, "Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
+ openr2_chan_answer_call(r2chan);
+ }
+ return;
+ }
c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
if (c) {
dahdi_r2_update_monitor_count(p->mfcr2, 0);
- /* chan_dahdi will take care of reading from now on, tell the library to forget about it */
+ /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
+ library to forget about it */
openr2_chan_disable_read(r2chan);
- } else {
- openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ pbx_builtin_setvar_helper(c, "MFCR2_CATEGORY", openr2_proto_get_category_string(p->mfcr2_recvd_category));
return;
}
- pbx_builtin_setvar_helper(c, "MFCR2_CATEGORY", openr2_proto_get_category_string(p->mfcr2_recvd_category));
- } else {
- ast_log(LOG_NOTICE, "Call accepted on forward channel %d\n", p->channel);
- p->subs[SUB_REAL].needringing = 1;
- p->dialing = 0;
- /* chan_dahdi will take care of reading from now on, tell the library to forget about it */
- openr2_chan_disable_read(r2chan);
- }
+ ast_log(LOG_WARNING, "Unable to create PBX channel in DAHDI channel %d\n", p->channel);
+ /* failed to create the channel, bail out and report it as an out of order line */
+ openr2_chan_disconnect_call(r2chan, OR2_CAUSE_OUT_OF_ORDER);
+ return;
+ }
+ /* this is an outgoing call, no need to launch the PBX thread, most likely we're in one already */
+ ast_log(LOG_NOTICE, "Call accepted on forward channel %d\n", p->channel);
+ p->subs[SUB_REAL].needringing = 1;
+ p->dialing = 0;
+ /* chan_dahdi will take care of reading from now on in the PBX thread, tell the
+ library to forget about it */
+ openr2_chan_disable_read(r2chan);
}
static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
@@ -4080,6 +4139,149 @@
}
#endif /* defined(HAVE_PRI) */
+#if defined(HAVE_OPENR2)
+static const char *dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
+
+static int dahdi_accept_r2_call_exec(struct ast_channel *chan, void *data)
+{
+ /* data is whether to accept with charge or no charge */
+ openr2_call_mode_t accept_mode;
+ int res, timeout, maxloops;
+ struct ast_frame *f;
+ struct dahdi_pvt *p;
+ char *parse;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(charge);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_DEBUG, "No data sent to application!\n");
+ return -1;
+ }
+
+ if (chan->tech != &dahdi_tech) {
+ ast_log(LOG_DEBUG, "Only DAHDI technology accepted!\n");
+ return -1;
+ }
+
+ p = (struct dahdi_pvt *)chan->tech_pvt;
+ if (!p) {
+ ast_log(LOG_DEBUG, "Unable to find technology private!\n");
+ return -1;
+ }
+
+ parse = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, parse);
+
+ if (ast_strlen_zero(args.charge)) {
+ ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
+ return -1;
+ }
+
+ ast_mutex_lock(&p->lock);
+ if (!p->mfcr2 || !p->mfcr2call) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_DEBUG, "Channel %s does not seems to be an R2 active channel!\n", chan->name);
+ return -1;
+ }
+
+ if (p->mfcr2_call_accepted) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_DEBUG, "MFC/R2 call already accepted on channel %s!\n", chan->name);
+ return 0;
+ }
+ accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
+ if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
+ return -1;
+ }
+ ast_mutex_unlock(&p->lock);
+
+ res = 0;
+ timeout = 100;
+ maxloops = 50; /* wait up to 5 seconds */
+ /* we need to read() until the call is accepted */
+ while (maxloops > 0) {
+ maxloops--;
+ if (ast_check_hangup(chan)) {
+ break;
+ }
+ res = ast_waitfor(chan, timeout);
+ if (res < 0) {
+ ast_log(LOG_DEBUG, "ast_waitfor failed on channel %s, going out ...\n", chan->name);
+ res = -1;
+ break;
+ }
+ if (res == 0) {
+ continue;
+ }
+ f = ast_read(chan);
+ if (!f) {
+ ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
+ res = -1;
+ break;
+ }
+ if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
+ ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
+ ast_frfree(f);
+ res = -1;
+ break;
+ }
+ ast_frfree(f);
+ ast_mutex_lock(&p->lock);
+ if (p->mfcr2_call_accepted) {
+ ast_mutex_unlock(&p->lock);
+ ast_log(LOG_DEBUG, "Accepted MFC/R2 call!\n");
+ break;
+ }
+ ast_mutex_unlock(&p->lock);
+ }
+ if (res == -1) {
+ ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
+ }
+ return res;
+}
+
+static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
+{
+ openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
+ switch (cause) {
+ case AST_CAUSE_USER_BUSY:
+ case AST_CAUSE_CALL_REJECTED:
+ case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
+ r2cause = OR2_CAUSE_BUSY_NUMBER;
+ break;
+
+ case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+ case AST_CAUSE_SWITCH_CONGESTION:
+ r2cause = OR2_CAUSE_NETWORK_CONGESTION;
+ break;
+
+ case AST_CAUSE_UNALLOCATED:
+ r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
+ break;
+
+ case AST_CAUSE_NETWORK_OUT_OF_ORDER:
+ case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
+ r2cause = OR2_CAUSE_OUT_OF_ORDER;
+ break;
+
+ case AST_CAUSE_NO_ANSWER:
+ case AST_CAUSE_NO_USER_RESPONSE:
+ r2cause = OR2_CAUSE_NO_ANSWER;
+ break;
+
+ default:
+ r2cause = OR2_CAUSE_NORMAL_CLEARING;
+ break;
+ }
+ ast_log(LOG_DEBUG, "dahdi_ast_cause_to_r2_cause returned %d/%s for ast cause %d\n",
+ r2cause, openr2_proto_get_disconnect_string(r2cause), cause);
+ return r2cause;
+}
+#endif
+
static int dahdi_hangup(struct ast_channel *ast)
{
int res;
@@ -4298,10 +4500,15 @@
#ifdef HAVE_OPENR2
if (p->mfcr2) {
ast_log(LOG_DEBUG, "disconnecting MFC/R2 call on chan %d\n", p->channel);
+ /* If it's an incoming call, check the mfcr2_forced_release setting */
if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
openr2_chan_disconnect_call(p->r2chan, OR2_CAUSE_FORCED_RELEASE);
} else {
- openr2_chan_disconnect_call(p->r2chan, OR2_CAUSE_NORMAL_CLEARING);
+ const char *r2causestr = pbx_builtin_getvar_helper(ast, "MFCR2_CAUSE");
+ int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
+ openr2_call_disconnect_cause_t r2cause = r2cause_user ? dahdi_ast_cause_to_r2_cause(r2cause_user)
+ : dahdi_ast_cause_to_r2_cause(ast->hangupcause);
+ openr2_chan_disconnect_call(p->r2chan, r2cause);
}
dahdi_r2_update_monitor_count(p->mfcr2, 1);
}
@@ -4558,8 +4765,21 @@
#endif
#ifdef HAVE_OPENR2
case SIG_MFCR2:
- ast_log(LOG_DEBUG, "Accepting MFC/R2 call on chan %d\n", p->channel);
- openr2_chan_answer_call(p->r2chan);
+ if (!p->mfcr2_call_accepted) {
+ /* The call was not accepted on offer nor the user, so it must be accepted now before answering,
+ openr2_chan_answer_call will be called when the callback on_call_accepted is executed */
+ p->mfcr2_answer_pending = 1;
+ if (p->mfcr2_charge_calls) {
+ ast_log(LOG_DEBUG, "Accepting MFC/R2 call with charge before answering on chan %d\n", p->channel);
+ openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
+ } else {
+ ast_log(LOG_DEBUG, "Accepting MFC/R2 call with no charge before answering on chan %d\n", p->channel);
+ openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
+ }
+ } else {
+ ast_log(LOG_DEBUG, "Answering MFC/R2 call on chan %d\n", p->channel);
+ openr2_chan_answer_call(p->r2chan);
+ }
break;
#endif
case 0:
@@ -6871,6 +7091,14 @@
ast_mutex_lock(&p->lock);
idx = dahdi_get_index(chan, p, 0);
ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name);
+#ifdef HAVE_OPENR2
+ if (p->mfcr2 && !p->mfcr2_call_accepted) {
+ ast_mutex_unlock(&p->lock);
+ /* if this is an R2 call and the call is not yet accepted, we don't want the
+ tone indications to mess up with the MF tones */
+ return 0;
+ }
+#endif
if (idx == SUB_REAL) {
switch (condition) {
case AST_CONTROL_BUSY:
@@ -9821,6 +10049,7 @@
tmp->mfcr2_charge_calls = conf->mfcr2.charge_calls;
tmp->mfcr2_allow_collect_calls = conf->mfcr2.allow_collect_calls;
tmp->mfcr2_forced_release = conf->mfcr2.forced_release;
+ tmp->mfcr2_accept_on_offer = conf->mfcr2.accept_on_offer;
tmp->mfcr2call = 0;
tmp->mfcr2_dnis_index = 0;
tmp->mfcr2_ani_index = 0;
@@ -14336,6 +14565,7 @@
ast_cli(a->fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
ast_cli(a->fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
ast_cli(a->fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
+ ast_cli(a->fd, "MFC/R2 Accept on Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
ast_cli(a->fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
ast_cli(a->fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
ast_cli(a->fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
@@ -15453,6 +15683,7 @@
#if defined(HAVE_OPENR2)
dahdi_r2_destroy_links();
ast_cli_unregister_multiple(dahdi_mfcr2_cli, ARRAY_LEN(dahdi_mfcr2_cli));
+ ast_unregister_application(dahdi_accept_r2_call_app);
#endif
ast_cli_unregister_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
@@ -16443,6 +16674,8 @@
confp->mfcr2.double_answer = ast_true(v->value);
} else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
confp->mfcr2.charge_calls = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
+ confp->mfcr2.accept_on_offer = ast_true(v->value);
} else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
confp->mfcr2.allow_collect_calls = ast_true(v->value);
} else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
@@ -16922,6 +17155,7 @@
#endif
#ifdef HAVE_OPENR2
ast_cli_register_multiple(dahdi_mfcr2_cli, sizeof(dahdi_mfcr2_cli)/sizeof(dahdi_mfcr2_cli[0]));
+ ast_register_application_xml(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec);
#endif
ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
Modified: team/moy/mfcr2/configs/chan_dahdi.conf.sample
URL: http://svn.digium.com/svn-view/asterisk/team/moy/mfcr2/configs/chan_dahdi.conf.sample?view=diff&rev=176494&r1=176493&r2=176494
==============================================================================
--- team/moy/mfcr2/configs/chan_dahdi.conf.sample (original)
+++ team/moy/mfcr2/configs/chan_dahdi.conf.sample Mon Feb 16 23:30:08 2009
@@ -1104,6 +1104,18 @@
; to the accepted state for incoming calls
; mfcr2_immediate_accept=no
+; You most likely dont need this feature. Default is yes.
+; When this is set to yes, all calls that are offered (incoming calls) which
+; DNIS is valid (exists in extensions.conf) and pass collect call validation
+; will be accepted with a Group B tone (either call with charge or not, depending on mfcr2_charge_calls)
+; with this set to 'no' then the call will NOT be accepted on offered, and the call will start its
+; execution in extensions.conf without being accepted until the channel is answered (either with Answer() or
+; any other application resulting in the channel being answered).
+; This can be set to 'no' if your telco or PBX needs the hangup cause to be set accurately
+; when this option is set to no you must explicitly accept the call with DAHDIAcceptR2Call
+; or implicitly through the Answer() application.
+; mfcr2_accept_on_offer=yes
+
; WARNING: advanced users only! I really mean it
; this parameter is commented by default because
; YOU DON'T NEED IT UNLESS YOU REALLY GROK MFC/R2
@@ -1124,6 +1136,8 @@
; leave the default (yes), but once in a while when interconnecting with
; old PBXs this may be useful.
; Concretely this affects the Group B signal used to accept calls
+; The application DAHDIAcceptR2Call can also be used to decide this
+; in the dial plan in a per-call basis instead of doing it here for all calls
; mfcr2_charge_calls=yes
; ---------------- END of options to be used with signalling=mfcr2
More information about the asterisk-commits
mailing list