summaryrefslogtreecommitdiff
path: root/channels/chan_dahdi.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels/chan_dahdi.c')
-rw-r--r--channels/chan_dahdi.c449
1 files changed, 278 insertions, 171 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index b6f91f7c6..a0d0bbe11 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -492,11 +492,12 @@ static inline int dahdi_wait_event(int fd)
#define MASK_AVAIL (1 << 0) /*!< Channel available for PRI use */
#define MASK_INUSE (1 << 1) /*!< Channel currently in use */
-#define CALLWAITING_SILENT_SAMPLES ( (300 * 8) / READ_SIZE) /*!< 300 ms */
-#define CALLWAITING_REPEAT_SAMPLES ( (10000 * 8) / READ_SIZE) /*!< 10,000 ms */
-#define CIDCW_EXPIRE_SAMPLES ( (500 * 8) / READ_SIZE) /*!< 500 ms */
-#define MIN_MS_SINCE_FLASH ( (2000) ) /*!< 2000 ms */
-#define DEFAULT_RINGT ( (8000 * 8) / READ_SIZE) /*!< 8,000 ms */
+#define CALLWAITING_SILENT_SAMPLES ((300 * 8) / READ_SIZE) /*!< 300 ms */
+#define CALLWAITING_REPEAT_SAMPLES ((10000 * 8) / READ_SIZE) /*!< 10,000 ms */
+#define CALLWAITING_SUPPRESS_SAMPLES ((100 * 8) / READ_SIZE) /*!< 100 ms */
+#define CIDCW_EXPIRE_SAMPLES ((500 * 8) / READ_SIZE) /*!< 500 ms */
+#define MIN_MS_SINCE_FLASH ((2000) ) /*!< 2000 ms */
+#define DEFAULT_RINGT ((8000 * 8) / READ_SIZE) /*!< 8,000 ms */
struct dahdi_pvt;
@@ -1053,7 +1054,8 @@ struct dahdi_pvt {
struct timeval dtmfcid_delay; /*!< Time value used for allow line to settle */
int callingpres; /*!< The value of calling presentation that we're going to use when placing a PRI call */
int callwaitingrepeat; /*!< How many samples to wait before repeating call waiting */
- int cidcwexpire; /*!< When to expire our muting for CID/CW */
+ int cidcwexpire; /*!< When to stop waiting for CID/CW CAS response (In samples) */
+ int cid_suppress_expire; /*!< How many samples to suppress after a CID spill. */
/*! \brief Analog caller ID waveform sample buffer */
unsigned char *cidspill;
/*! \brief Position in the cidspill buffer to send out next. */
@@ -1074,7 +1076,12 @@ struct dahdi_pvt {
* characters are processed.
*/
int stripmsd;
- /*! \brief BOOLEAN. XXX Meaning what?? */
+ /*!
+ * \brief TRUE if Call Waiting (CW) CPE Alert Signal (CAS) is being sent.
+ * \note
+ * After CAS is sent, the call waiting caller id will be sent if the phone
+ * gives a positive reply.
+ */
int callwaitcas;
/*! \brief Number of call waiting rings. */
int callwaitrings;
@@ -1839,18 +1846,19 @@ static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int
return 0;
}
-static int send_callerid(struct dahdi_pvt *p);
-
static int my_stop_callwait(void *pvt)
{
struct dahdi_pvt *p = pvt;
p->callwaitingrepeat = 0;
p->cidcwexpire = 0;
+ p->cid_suppress_expire = 0;
return 0;
}
+static int send_callerid(struct dahdi_pvt *p);
static int save_conference(struct dahdi_pvt *p);
+static int restore_conference(struct dahdi_pvt *p);
static int my_callwait(void *pvt)
{
@@ -1860,6 +1868,11 @@ static int my_callwait(void *pvt)
ast_log(LOG_WARNING, "Spill already exists?!?\n");
ast_free(p->cidspill);
}
+
+ /*
+ * SAS: Subscriber Alert Signal, 440Hz for 300ms
+ * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
+ */
if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
return -1;
save_conference(p);
@@ -1898,6 +1911,8 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle
caller->id.number.str,
AST_LAW(p));
} else {
+ ast_verb(3, "CPE supports Call Waiting Caller*ID. Sending '%s/%s'\n",
+ caller->id.name.str, caller->id.number.str);
p->callwaitcas = 0;
p->cidcwexpire = 0;
p->cidlen = ast_callerid_callwaiting_generate(p->cidspill,
@@ -1907,6 +1922,7 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_party_caller *calle
p->cidlen += READ_SIZE * 4;
}
p->cidpos = 0;
+ p->cid_suppress_expire = 0;
send_callerid(p);
}
return 0;
@@ -1978,68 +1994,72 @@ static int reset_conf(struct dahdi_pvt *p);
static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
-static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+static void my_handle_dtmf(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
{
struct ast_frame *f = *dest;
struct dahdi_pvt *p = pvt;
int idx = analogsub_to_dahdisub(analog_index);
- ast_debug(1, "DTMF digit: %c on %s\n", f->subclass.integer, ast->name);
+ ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
+ f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
+ f->subclass.integer, f->subclass.integer, ast->name);
if (f->subclass.integer == 'f') {
- /* Fax tone -- Handle and return NULL */
- if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
- /* If faxbuffers are configured, use them for the fax transmission */
- if (p->usefaxbuffers && !p->bufferoverrideinuse) {
- struct dahdi_bufferinfo bi = {
- .txbufpolicy = p->faxbuf_policy,
- .bufsize = p->bufsize,
- .numbufs = p->faxbuf_no
- };
- int res;
-
- if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
- ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
- } else {
- p->bufferoverrideinuse = 1;
+ if (f->frametype == AST_FRAME_DTMF_END) {
+ /* Fax tone -- Handle and return NULL */
+ if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+ /* If faxbuffers are configured, use them for the fax transmission */
+ if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+ struct dahdi_bufferinfo bi = {
+ .txbufpolicy = p->faxbuf_policy,
+ .bufsize = p->bufsize,
+ .numbufs = p->faxbuf_no
+ };
+ int res;
+
+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+ ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+ } else {
+ p->bufferoverrideinuse = 1;
+ }
}
- }
- p->faxhandled = 1;
- if (p->dsp) {
- p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
- ast_dsp_set_features(p->dsp, p->dsp_features);
- ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
- }
- if (strcmp(ast->exten, "fax")) {
- const char *target_context = S_OR(ast->macrocontext, ast->context);
+ p->faxhandled = 1;
+ if (p->dsp) {
+ p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
+ ast_dsp_set_features(p->dsp, p->dsp_features);
+ ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
+ }
+ if (strcmp(ast->exten, "fax")) {
+ const char *target_context = S_OR(ast->macrocontext, ast->context);
- /* We need to unlock 'ast' here because ast_exists_extension has the
- * potential to start autoservice on the channel. Such action is prone
- * to deadlock.
- */
- ast_mutex_unlock(&p->lock);
- ast_channel_unlock(ast);
- if (ast_exists_extension(ast, target_context, "fax", 1,
- S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
- ast_channel_lock(ast);
- ast_mutex_lock(&p->lock);
- ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
- /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
- pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
- if (ast_async_goto(ast, target_context, "fax", 1))
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+ /* We need to unlock 'ast' here because ast_exists_extension has the
+ * potential to start autoservice on the channel. Such action is prone
+ * to deadlock.
+ */
+ ast_mutex_unlock(&p->lock);
+ ast_channel_unlock(ast);
+ if (ast_exists_extension(ast, target_context, "fax", 1,
+ S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
+ /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+ if (ast_async_goto(ast, target_context, "fax", 1))
+ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+ } else {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+ }
} else {
- ast_channel_lock(ast);
- ast_mutex_lock(&p->lock);
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+ ast_debug(1, "Already in a fax extension, not redirecting\n");
}
} else {
- ast_debug(1, "Already in a fax extension, not redirecting\n");
+ ast_debug(1, "Fax already handled\n");
}
- } else {
- ast_debug(1, "Fax already handled\n");
+ dahdi_confmute(p, 0);
}
- dahdi_confmute(p, 0);
p->subs[idx].f.frametype = AST_FRAME_NULL;
p->subs[idx].f.subclass.integer = 0;
*dest = &p->subs[idx].f;
@@ -2225,13 +2245,20 @@ static int my_check_confirmanswer(void *pvt)
return 0;
}
+static void my_set_callwaiting(void *pvt, int callwaiting_enable)
+{
+ struct dahdi_pvt *p = pvt;
+
+ p->callwaiting = callwaiting_enable;
+}
+
static void my_cancel_cidspill(void *pvt)
{
struct dahdi_pvt *p = pvt;
- if (p->cidspill) {
- ast_free(p->cidspill);
- p->cidspill = NULL;
- }
+
+ ast_free(p->cidspill);
+ p->cidspill = NULL;
+ restore_conference(p);
}
static int my_confmute(void *pvt, int mute)
@@ -3504,7 +3531,7 @@ static struct analog_callback dahdi_analog_callbacks =
.lock_private = my_lock_private,
.unlock_private = my_unlock_private,
.deadlock_avoidance_private = my_deadlock_avoidance_private,
- .handle_dtmfup = my_handle_dtmfup,
+ .handle_dtmf = my_handle_dtmf,
.wink = my_wink,
.new_ast_channel = my_new_analog_ast_channel,
.dsp_set_digitmode = my_dsp_set_digitmode,
@@ -3532,6 +3559,7 @@ static struct analog_callback dahdi_analog_callbacks =
.check_waitingfordt = my_check_waitingfordt,
.set_confirmanswer = my_set_confirmanswer,
.check_confirmanswer = my_check_confirmanswer,
+ .set_callwaiting = my_set_callwaiting,
.cancel_cidspill = my_cancel_cidspill,
.confmute = my_confmute,
.set_pulsedial = my_set_pulsedial,
@@ -5049,17 +5077,16 @@ static int restore_conference(struct dahdi_pvt *p)
ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
return -1;
}
+ ast_debug(1, "Restored conferencing\n");
}
- ast_debug(1, "Restored conferencing\n");
return 0;
}
-static int send_callerid(struct dahdi_pvt *p);
-
static int send_cwcidspill(struct dahdi_pvt *p)
{
p->callwaitcas = 0;
p->cidcwexpire = 0;
+ p->cid_suppress_expire = 0;
if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE)))
return -1;
p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p));
@@ -5122,11 +5149,13 @@ static int send_callerid(struct dahdi_pvt *p)
return 0;
p->cidpos += res;
}
+ p->cid_suppress_expire = CALLWAITING_SUPPRESS_SAMPLES;
ast_free(p->cidspill);
p->cidspill = NULL;
if (p->callwaitcas) {
/* Wait for CID/CW to expire */
p->cidcwexpire = CIDCW_EXPIRE_SAMPLES;
+ p->cid_suppress_expire = p->cidcwexpire;
} else
restore_conference(p);
return 0;
@@ -5140,6 +5169,11 @@ static int dahdi_callwait(struct ast_channel *ast)
ast_log(LOG_WARNING, "Spill already exists?!?\n");
ast_free(p->cidspill);
}
+
+ /*
+ * SAS: Subscriber Alert Signal, 440Hz for 300ms
+ * CAS: CPE Alert Signal, 2130Hz * 2750Hz sine waves
+ */
if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
return -1;
save_conference(p);
@@ -5615,9 +5649,7 @@ static void destroy_dahdi_pvt(struct dahdi_pvt *pvt)
break;
}
}
- if (p->cidspill) {
- ast_free(p->cidspill);
- }
+ ast_free(p->cidspill);
if (p->use_smdi)
ast_smdi_interface_unref(p->smdi_iface);
if (p->mwi_event_sub)
@@ -6339,11 +6371,11 @@ static int dahdi_hangup(struct ast_channel *ast)
p->callwaitingrepeat = 0;
p->cidcwexpire = 0;
+ p->cid_suppress_expire = 0;
p->oprmode = 0;
ast->tech_pvt = NULL;
hangup_out:
- if (p->cidspill)
- ast_free(p->cidspill);
+ ast_free(p->cidspill);
p->cidspill = NULL;
ast_mutex_unlock(&p->lock);
@@ -7037,6 +7069,24 @@ static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_ch
return AST_BRIDGE_RETRY;
}
+ if ((p0->callwaiting && p0->callwaitingcallerid)
+ || (p1->callwaiting && p1->callwaitingcallerid)) {
+ /*
+ * Call Waiting Caller ID requires DTMF detection to know if it
+ * can send the CID spill.
+ *
+ * For now, don't attempt to native bridge if either channel
+ * needs DTMF detection. There is code below to handle it
+ * properly until DTMF is actually seen, but due to currently
+ * unresolved issues it's ignored...
+ */
+ ast_mutex_unlock(&p0->lock);
+ ast_mutex_unlock(&p1->lock);
+ ast_channel_unlock(c0);
+ ast_channel_unlock(c1);
+ return AST_BRIDGE_FAILED_NOWARN;
+ }
+
#if defined(HAVE_PRI)
if ((dahdi_sig_pri_lib_handles(p0->sig)
&& ((struct sig_pri_chan *) p0->sig_pvt)->no_b_channel)
@@ -7474,87 +7524,98 @@ static int get_alarms(struct dahdi_pvt *p)
return DAHDI_ALARM_NONE;
}
-static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_frame **dest)
+static void dahdi_handle_dtmf(struct ast_channel *ast, int idx, struct ast_frame **dest)
{
struct dahdi_pvt *p = ast->tech_pvt;
struct ast_frame *f = *dest;
- ast_debug(1, "DTMF digit: %c on %s\n", (int) f->subclass.integer, ast->name);
+ ast_debug(1, "%s DTMF digit: 0x%02X '%c' on %s\n",
+ f->frametype == AST_FRAME_DTMF_BEGIN ? "Begin" : "End",
+ f->subclass.integer, f->subclass.integer, ast->name);
if (p->confirmanswer) {
- ast_debug(1, "Confirm answer on %s!\n", ast->name);
- /* Upon receiving a DTMF digit, consider this an answer confirmation instead
- of a DTMF digit */
- p->subs[idx].f.frametype = AST_FRAME_CONTROL;
- p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
+ if (f->frametype == AST_FRAME_DTMF_END) {
+ ast_debug(1, "Confirm answer on %s!\n", ast->name);
+ /* Upon receiving a DTMF digit, consider this an answer confirmation instead
+ of a DTMF digit */
+ p->subs[idx].f.frametype = AST_FRAME_CONTROL;
+ p->subs[idx].f.subclass.integer = AST_CONTROL_ANSWER;
+ /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
+ p->confirmanswer = 0;
+ } else {
+ p->subs[idx].f.frametype = AST_FRAME_NULL;
+ p->subs[idx].f.subclass.integer = 0;
+ }
*dest = &p->subs[idx].f;
- /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
- p->confirmanswer = 0;
} else if (p->callwaitcas) {
- if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
- ast_debug(1, "Got some DTMF, but it's for the CAS\n");
- if (p->cidspill)
+ if (f->frametype == AST_FRAME_DTMF_END) {
+ if ((f->subclass.integer == 'A') || (f->subclass.integer == 'D')) {
+ ast_debug(1, "Got some DTMF, but it's for the CAS\n");
ast_free(p->cidspill);
- send_cwcidspill(p);
+ p->cidspill = NULL;
+ send_cwcidspill(p);
+ }
+ p->callwaitcas = 0;
}
- p->callwaitcas = 0;
p->subs[idx].f.frametype = AST_FRAME_NULL;
p->subs[idx].f.subclass.integer = 0;
*dest = &p->subs[idx].f;
} else if (f->subclass.integer == 'f') {
- /* Fax tone -- Handle and return NULL */
- if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
- /* If faxbuffers are configured, use them for the fax transmission */
- if (p->usefaxbuffers && !p->bufferoverrideinuse) {
- struct dahdi_bufferinfo bi = {
- .txbufpolicy = p->faxbuf_policy,
- .bufsize = p->bufsize,
- .numbufs = p->faxbuf_no
- };
- int res;
-
- if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
- ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
- } else {
- p->bufferoverrideinuse = 1;
+ if (f->frametype == AST_FRAME_DTMF_END) {
+ /* Fax tone -- Handle and return NULL */
+ if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+ /* If faxbuffers are configured, use them for the fax transmission */
+ if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+ struct dahdi_bufferinfo bi = {
+ .txbufpolicy = p->faxbuf_policy,
+ .bufsize = p->bufsize,
+ .numbufs = p->faxbuf_no
+ };
+ int res;
+
+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+ ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+ } else {
+ p->bufferoverrideinuse = 1;
+ }
}
- }
- p->faxhandled = 1;
- if (p->dsp) {
- p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
- ast_dsp_set_features(p->dsp, p->dsp_features);
- ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
- }
- if (strcmp(ast->exten, "fax")) {
- const char *target_context = S_OR(ast->macrocontext, ast->context);
+ p->faxhandled = 1;
+ if (p->dsp) {
+ p->dsp_features &= ~DSP_FEATURE_FAX_DETECT;
+ ast_dsp_set_features(p->dsp, p->dsp_features);
+ ast_debug(1, "Disabling FAX tone detection on %s after tone received\n", ast->name);
+ }
+ if (strcmp(ast->exten, "fax")) {
+ const char *target_context = S_OR(ast->macrocontext, ast->context);
- /* We need to unlock 'ast' here because ast_exists_extension has the
- * potential to start autoservice on the channel. Such action is prone
- * to deadlock.
- */
- ast_mutex_unlock(&p->lock);
- ast_channel_unlock(ast);
- if (ast_exists_extension(ast, target_context, "fax", 1,
- S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
- ast_channel_lock(ast);
- ast_mutex_lock(&p->lock);
- ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
- /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
- pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
- if (ast_async_goto(ast, target_context, "fax", 1))
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+ /* We need to unlock 'ast' here because ast_exists_extension has the
+ * potential to start autoservice on the channel. Such action is prone
+ * to deadlock.
+ */
+ ast_mutex_unlock(&p->lock);
+ ast_channel_unlock(ast);
+ if (ast_exists_extension(ast, target_context, "fax", 1,
+ S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, NULL))) {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
+ /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+ if (ast_async_goto(ast, target_context, "fax", 1))
+ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+ } else {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+ }
} else {
- ast_channel_lock(ast);
- ast_mutex_lock(&p->lock);
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+ ast_debug(1, "Already in a fax extension, not redirecting\n");
}
} else {
- ast_debug(1, "Already in a fax extension, not redirecting\n");
+ ast_debug(1, "Fax already handled\n");
}
- } else {
- ast_debug(1, "Fax already handled\n");
+ dahdi_confmute(p, 0);
}
- dahdi_confmute(p, 0);
p->subs[idx].f.frametype = AST_FRAME_NULL;
p->subs[idx].f.subclass.integer = 0;
*dest = &p->subs[idx].f;
@@ -7628,20 +7689,32 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
} else
#endif /* defined(HAVE_PRI) */
{
+ /* Unmute conference */
dahdi_confmute(p, 0);
p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
p->subs[idx].f.subclass.integer = res & 0xff;
+ dahdi_handle_dtmf(ast, idx, &f);
}
- dahdi_handle_dtmfup(ast, idx, &f);
return f;
}
if (res & DAHDI_EVENT_DTMFDOWN) {
ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
- /* Mute conference */
- dahdi_confmute(p, 1);
- p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
- p->subs[idx].f.subclass.integer = res & 0xff;
+#if defined(HAVE_PRI)
+ if (dahdi_sig_pri_lib_handles(p->sig)
+ && !((struct sig_pri_chan *) p->sig_pvt)->proceeding
+ && p->pri
+ && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
+ /* absorb event */
+ } else
+#endif /* defined(HAVE_PRI) */
+ {
+ /* Mute conference */
+ dahdi_confmute(p, 1);
+ p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
+ p->subs[idx].f.subclass.integer = res & 0xff;
+ dahdi_handle_dtmf(ast, idx, &f);
+ }
return &p->subs[idx].f;
}
@@ -7813,6 +7886,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
#endif
p->callwaitingrepeat = 0;
p->cidcwexpire = 0;
+ p->cid_suppress_expire = 0;
p->owner = NULL;
/* Don't start streaming audio yet if the incoming call isn't up yet */
if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
@@ -7959,11 +8033,12 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
p->subs[SUB_REAL].needringing = 0;
dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
ast_debug(1, "channel %d answered\n", p->channel);
- if (p->cidspill) {
- /* Cancel any running CallerID spill */
- ast_free(p->cidspill);
- p->cidspill = NULL;
- }
+
+ /* Cancel any running CallerID spill */
+ ast_free(p->cidspill);
+ p->cidspill = NULL;
+ restore_conference(p);
+
p->dialing = 0;
p->callwaitcas = 0;
if (p->confirmanswer) {
@@ -8128,6 +8203,11 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
case SIG_FXOKS:
ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
+
+ /* Cancel any running CallerID spill */
+ ast_free(p->cidspill);
+ p->cidspill = NULL;
+ restore_conference(p);
p->callwaitcas = 0;
if (idx != SUB_REAL) {
@@ -8147,6 +8227,7 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
}
p->callwaitingrepeat = 0;
p->cidcwexpire = 0;
+ p->cid_suppress_expire = 0;
/* Start music on hold if appropriate */
if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
@@ -8479,6 +8560,7 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
dahdi_ring_phone(p);
p->callwaitingrepeat = 0;
p->cidcwexpire = 0;
+ p->cid_suppress_expire = 0;
} else
ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
update_conf(p);
@@ -8510,6 +8592,7 @@ static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
}
p->callwaitingrepeat = 0;
p->cidcwexpire = 0;
+ p->cid_suppress_expire = 0;
if (ast_bridged_channel(p->owner))
ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
p->subs[SUB_REAL].needunhold = 1;
@@ -8781,21 +8864,25 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
return &p->subs[idx].f;
}
}
- /* Ensure the CW timer decrements only on a single subchannel */
- if (p->callwaitingrepeat && dahdi_get_index(ast, p, 1) == SUB_REAL) {
- p->callwaitingrepeat--;
- }
- if (p->cidcwexpire)
- p->cidcwexpire--;
- /* Repeat callwaiting */
- if (p->callwaitingrepeat == 1) {
- p->callwaitrings++;
- dahdi_callwait(ast);
- }
- /* Expire CID/CW */
- if (p->cidcwexpire == 1) {
- ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
- restore_conference(p);
+ if (idx == SUB_REAL) {
+ /* Ensure the CW timers decrement only on a single subchannel */
+ if (p->cidcwexpire) {
+ if (!--p->cidcwexpire) {
+ /* Expired CID/CW */
+ ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
+ restore_conference(p);
+ }
+ }
+ if (p->cid_suppress_expire) {
+ --p->cid_suppress_expire;
+ }
+ if (p->callwaitingrepeat) {
+ if (!--p->callwaitingrepeat) {
+ /* Expired, Repeat callwaiting tone */
+ ++p->callwaitrings;
+ dahdi_callwait(ast);
+ }
+ }
}
if (p->subs[idx].linear) {
p->subs[idx].f.datalen = READ_SIZE * 2;
@@ -8899,11 +8986,31 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
} else
f = &p->subs[idx].f;
- if (f && (f->frametype == AST_FRAME_DTMF)) {
- if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
- analog_handle_dtmfup(p->sig_pvt, ast, idx, &f);
- } else
- dahdi_handle_dtmfup(ast, idx, &f);
+ if (f) {
+ switch (f->frametype) {
+ case AST_FRAME_DTMF_BEGIN:
+ case AST_FRAME_DTMF_END:
+ if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+ analog_handle_dtmf(p->sig_pvt, ast, idx, &f);
+ } else {
+ dahdi_handle_dtmf(ast, idx, &f);
+ }
+ break;
+ case AST_FRAME_VOICE:
+ if (p->cidspill || p->cid_suppress_expire) {
+ /* We are/were sending a caller id spill. Suppress any echo. */
+ p->subs[idx].f.frametype = AST_FRAME_NULL;
+ p->subs[idx].f.subclass.integer = 0;
+ p->subs[idx].f.samples = 0;
+ p->subs[idx].f.mallocd = 0;
+ p->subs[idx].f.offset = 0;
+ p->subs[idx].f.data.ptr = NULL;
+ p->subs[idx].f.datalen= 0;
+ }
+ break;
+ default:
+ break;
+ }
}
/* If we have a fake_event, trigger exception to handle it */
@@ -8968,7 +9075,8 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
return 0;
}
if (p->cidspill) {
- ast_debug(1, "Dropping frame since I've still got a callerid spill\n");
+ ast_debug(1, "Dropping frame since I've still got a callerid spill on %s...\n",
+ ast->name);
return 0;
}
/* Return if it's not valid data */
@@ -10880,11 +10988,9 @@ static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
handled = 1;
if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
- ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s mwi send aborted\n", strerror(errno));
- if(pvt->cidspill) {
- ast_free(pvt->cidspill);
- pvt->cidspill = NULL;
- }
+ ast_log(LOG_WARNING, "Unable to finish RP-AS: %s mwi send aborted\n", strerror(errno));
+ ast_free(pvt->cidspill);
+ pvt->cidspill = NULL;
pvt->mwisend_data.mwisend_current = MWI_SEND_DONE;
pvt->mwisendactive = 0;
} else {
@@ -10961,11 +11067,12 @@ static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
if (res && (errno == EBUSY))
break;
- if (i->cidspill) {
- /* Cancel VMWI spill */
- ast_free(i->cidspill);
- i->cidspill = NULL;
- }
+
+ /* Cancel VMWI spill */
+ ast_free(i->cidspill);
+ i->cidspill = NULL;
+ restore_conference(i);
+
if (i->immediate) {
dahdi_enable_ec(i);
/* The channel is immediately up. Start right away */