diff options
Diffstat (limited to 'channels/chan_dahdi.c')
-rw-r--r-- | channels/chan_dahdi.c | 449 |
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 */ |