aboutsummaryrefslogtreecommitdiffstats
path: root/channels
diff options
context:
space:
mode:
Diffstat (limited to 'channels')
-rw-r--r--channels/chan_dahdi.c449
-rw-r--r--channels/sig_analog.c84
-rw-r--r--channels/sig_analog.h26
-rw-r--r--channels/sig_pri.h4
4 files changed, 349 insertions, 214 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 8319161ee..ee71909ec 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);
@@ -5590,9 +5624,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)
@@ -6314,11 +6346,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);
@@ -7012,6 +7044,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)
@@ -7449,87 +7499,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;
@@ -7603,20 +7664,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;
}
@@ -7788,6 +7861,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)
@@ -7934,11 +8008,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) {
@@ -8103,6 +8178,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) {
@@ -8122,6 +8202,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,
@@ -8454,6 +8535,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);
@@ -8485,6 +8567,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;
@@ -8756,21 +8839,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;
@@ -8874,11 +8961,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 */
@@ -8943,7 +9050,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 */
@@ -10855,11 +10963,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 {
@@ -10936,11 +11042,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 */
diff --git a/channels/sig_analog.c b/channels/sig_analog.c
index ba6ed45c8..7c35f6b5e 100644
--- a/channels/sig_analog.c
+++ b/channels/sig_analog.c
@@ -624,10 +624,10 @@ static int analog_dsp_set_digitmode(struct analog_pvt *p, enum analog_dsp_digitm
return -1;
}
-static void analog_cb_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+static void analog_cb_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
{
- if (p->calls->handle_dtmfup) {
- p->calls->handle_dtmfup(p->chan_pvt, ast, analog_index, dest);
+ if (p->calls->handle_dtmf) {
+ p->calls->handle_dtmf(p->chan_pvt, ast, analog_index, dest);
}
}
@@ -859,10 +859,7 @@ int analog_available(struct analog_pvt *p)
static int analog_stop_callwait(struct analog_pvt *p)
{
- if (p->callwaitingcallerid) {
- p->callwaitcas = 0;
- }
-
+ p->callwaitcas = 0;
if (p->calls->stop_callwait) {
return p->calls->stop_callwait(p->chan_pvt);
}
@@ -871,15 +868,21 @@ static int analog_stop_callwait(struct analog_pvt *p)
static int analog_callwait(struct analog_pvt *p)
{
- if (p->callwaitingcallerid) {
- p->callwaitcas = 1;
- }
+ p->callwaitcas = p->callwaitingcallerid;
if (p->calls->callwait) {
return p->calls->callwait(p->chan_pvt);
}
return 0;
}
+static void analog_set_callwaiting(struct analog_pvt *p, int callwaiting_enable)
+{
+ p->callwaiting = callwaiting_enable;
+ if (p->calls->set_callwaiting) {
+ p->calls->set_callwaiting(p->chan_pvt, callwaiting_enable);
+ }
+}
+
static void analog_set_cadence(struct analog_pvt *p, struct ast_channel *chan)
{
if (p->calls->set_cadence) {
@@ -1456,7 +1459,7 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
p->callwaitcas = 0;
- p->callwaiting = p->permcallwaiting;
+ analog_set_callwaiting(p, p->permcallwaiting);
p->hidecallerid = p->permhidecallerid;
analog_set_dialing(p, 0);
analog_update_conf(p);
@@ -1574,35 +1577,45 @@ static int analog_handles_digit(struct ast_frame *f)
}
}
-void analog_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
+void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub idx, struct ast_frame **dest)
{
struct ast_frame *f = *dest;
- 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 (analog_check_confirmanswer(p)) {
- 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 */
+ analog_set_confirmanswer(p, 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 */
- analog_set_confirmanswer(p, 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");
- p->caller.id.name.str = p->callwait_name;
- p->caller.id.number.str = p->callwait_num;
- analog_send_callerid(p, 1, &p->caller);
+ 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");
+ p->caller.id.name.str = p->callwait_name;
+ p->caller.id.number.str = p->callwait_num;
+ analog_send_callerid(p, 1, &p->caller);
+ }
+ if (analog_handles_digit(f)) {
+ p->callwaitcas = 0;
+ }
}
- if (analog_handles_digit(f))
- p->callwaitcas = 0;
p->subs[idx].f.frametype = AST_FRAME_NULL;
p->subs[idx].f.subclass.integer = 0;
*dest = &p->subs[idx].f;
} else {
- analog_cb_handle_dtmfup(p, ast, idx, dest);
+ analog_cb_handle_dtmf(p, ast, idx, dest);
}
}
@@ -2122,7 +2135,7 @@ static void *__analog_ss_thread(void *data)
} else if (p->callwaiting && !strcmp(exten, "*70")) {
ast_verb(3, "Disabling call waiting on %s\n", chan->name);
/* Disable call waiting if enabled */
- p->callwaiting = 0;
+ analog_set_callwaiting(p, 0);
res = analog_play_tone(p, idx, ANALOG_TONE_DIALRECALL);
if (res) {
ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
@@ -2631,7 +2644,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
analog_confmute(p, 0);
p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
p->subs[idx].f.subclass.integer = res & 0xff;
- analog_handle_dtmfup(p, ast, idx, &f);
+ analog_handle_dtmf(p, ast, idx, &f);
return f;
}
@@ -2641,6 +2654,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
analog_confmute(p, 1);
p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
p->subs[idx].f.subclass.integer = res & 0xff;
+ analog_handle_dtmf(p, ast, idx, &f);
return f;
}
@@ -2890,7 +2904,10 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
analog_set_needringing(p, 0);
analog_off_hook(p);
ast_debug(1, "channel %d answered\n", p->channel);
+
+ /* Cancel any running CallerID spill */
analog_cancel_cidspill(p);
+
analog_set_dialing(p, 0);
p->callwaitcas = 0;
if (analog_check_confirmanswer(p)) {
@@ -3050,6 +3067,8 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
idx, analog_get_sub_fd(p, ANALOG_SUB_REAL), analog_get_sub_fd(p, ANALOG_SUB_CALLWAIT), analog_get_sub_fd(p, ANALOG_SUB_THREEWAY));
+ /* Cancel any running CallerID spill */
+ analog_cancel_cidspill(p);
p->callwaitcas = 0;
if (idx != ANALOG_SUB_REAL) {
@@ -3568,7 +3587,10 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
if (res && (errno == EBUSY)) {
break;
}
+
+ /* Cancel VMWI spill */
analog_cancel_cidspill(i);
+
if (i->immediate) {
analog_set_echocanceller(i, 1);
/* The channel is immediately up. Start right away */
@@ -3826,7 +3848,7 @@ int analog_config_complete(struct analog_pvt *p)
p->permcallwaiting = 0;
}
- p->callwaiting = p->permcallwaiting;
+ analog_set_callwaiting(p, p->permcallwaiting);
return 0;
}
diff --git a/channels/sig_analog.h b/channels/sig_analog.h
index d7b6011a3..0f1a6563d 100644
--- a/channels/sig_analog.h
+++ b/channels/sig_analog.h
@@ -134,10 +134,10 @@ struct analog_callback {
/* Do deadlock avoidance for the private signaling structure lock. */
void (* const deadlock_avoidance_private)(void *pvt);
- /* Function which is called back to handle any other DTMF up events that are received. Called by analog_handle_event. Why is this
+ /* Function which is called back to handle any other DTMF events that are received. Called by analog_handle_event. Why is this
* important to use, instead of just directly using events received before they are passed into the library? Because sometimes,
* (CWCID) the library absorbs DTMF events received. */
- void (* const handle_dtmfup)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
+ void (* const handle_dtmf)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
int (* const get_event)(void *pvt);
int (* const wait_event)(void *pvt);
@@ -228,6 +228,7 @@ struct analog_callback {
int (* const check_waitingfordt)(void *pvt);
void (* const set_confirmanswer)(void *pvt, int flag);
int (* const check_confirmanswer)(void *pvt);
+ void (* const set_callwaiting)(void *pvt, int callwaiting_enable);
void (* const cancel_cidspill)(void *pvt);
int (* const confmute)(void *pvt, int mute);
void (* const set_pulsedial)(void *pvt, int flag);
@@ -271,14 +272,14 @@ struct analog_pvt {
unsigned int dahditrcallerid:1; /*!< should we use the callerid from incoming call on dahdi transfer or not */
unsigned int hanguponpolarityswitch:1;
unsigned int immediate:1;
- unsigned int permcallwaiting:1;
+ unsigned int permcallwaiting:1; /*!< TRUE if call waiting is enabled. (Configured option) */
unsigned int permhidecallerid:1; /*!< Whether to hide our outgoing caller ID or not */
unsigned int pulse:1;
unsigned int threewaycalling:1;
unsigned int transfer:1;
unsigned int transfertobusy:1; /*!< allow flash-transfers to busy channels */
unsigned int use_callerid:1; /*!< Whether or not to use caller id on this channel */
- unsigned int callwaitingcallerid:1;
+ unsigned int callwaitingcallerid:1; /*!< TRUE if send caller ID for Call Waiting */
/*!
* \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
*/
@@ -289,6 +290,7 @@ struct analog_pvt {
/* Not used for anything but log messages. Could be just the TCID */
int channel; /*!< Channel Number */
+
enum analog_sigtype outsigmod;
int echotraining;
int cid_signalling; /*!< Asterisk callerid type we're using */
@@ -301,13 +303,21 @@ struct analog_pvt {
/* XXX: All variables after this are internal */
- unsigned int callwaiting:1;
+ unsigned int callwaiting:1; /*!< TRUE if call waiting is enabled. (Active option) */
unsigned int dialednone:1;
unsigned int dialing:1; /*!< TRUE if in the process of dialing digits or sending something */
unsigned int dnd:1; /*!< TRUE if Do-Not-Disturb is enabled. */
unsigned int echobreak:1;
unsigned int hidecallerid:1;
unsigned int outgoing:1;
+ unsigned int inalarm:1;
+ /*!
+ * \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.
+ */
+ unsigned int callwaitcas:1;
char callwait_num[AST_MAX_EXTENSION];
char callwait_name[AST_MAX_EXTENSION];
@@ -331,10 +341,6 @@ struct analog_pvt {
struct ast_channel *ss_astchan;
/* All variables after this are definitely going to be audited */
- unsigned int inalarm:1;
-
- int callwaitcas;
-
int ringt;
int ringt_base;
};
@@ -360,7 +366,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event);
int analog_config_complete(struct analog_pvt *p);
-void analog_handle_dtmfup(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest);
+void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum analog_sub index, struct ast_frame **dest);
enum analog_cid_start analog_str_to_cidstart(const char *value);
diff --git a/channels/sig_pri.h b/channels/sig_pri.h
index 06dad4ea7..8f2ee20e4 100644
--- a/channels/sig_pri.h
+++ b/channels/sig_pri.h
@@ -90,10 +90,10 @@ struct sig_pri_callback {
void (* const unlock_private)(void *pvt);
/* Lock the private in the signalling private structure. ... */
void (* const lock_private)(void *pvt);
- /* Function which is called back to handle any other DTMF up events that are received. Called by analog_handle_event. Why is this
+ /* Function which is called back to handle any other DTMF events that are received. Called by analog_handle_event. Why is this
* important to use, instead of just directly using events received before they are passed into the library? Because sometimes,
* (CWCID) the library absorbs DTMF events received. */
- //void (* const handle_dtmfup)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
+ //void (* const handle_dtmf)(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest);
//int (* const dial_digits)(void *pvt, enum analog_sub sub, struct analog_dialoperation *dop);
int (* const play_tone)(void *pvt, enum sig_pri_tone tone);