#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;
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. */
* 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;
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)
{
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);
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,
p->cidlen += READ_SIZE * 4;
}
p->cidpos = 0;
+ p->cid_suppress_expire = 0;
send_callerid(p);
}
return 0;
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;
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)
.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,
.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,
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));
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;
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);
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)
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);
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)
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;
} 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;
}
#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)
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) {
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) {
}
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,
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);
}
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;
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;
} 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 */
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 */
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 {
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 */
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);
}
}
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);
}
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) {
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);
}
}
-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);
}
}
} 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",
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;
}
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;
}
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)) {
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) {
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 */
p->permcallwaiting = 0;
}
- p->callwaiting = p->permcallwaiting;
+ analog_set_callwaiting(p, p->permcallwaiting);
return 0;
}