Index: channels/sig_pri.h =================================================================== --- channels/sig_pri.h (revision 295905) +++ channels/sig_pri.h (working copy) @@ -90,10 +90,10 @@ 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); Index: channels/chan_dahdi.c =================================================================== --- channels/chan_dahdi.c (revision 295905) +++ channels/chan_dahdi.c (working copy) @@ -1053,7 +1053,7 @@ 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) */ /*! \brief Analog caller ID waveform sample buffer */ unsigned char *cidspill; /*! \brief Position in the cidspill buffer to send out next. */ @@ -1074,7 +1074,12 @@ * 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,8 +1844,6 @@ return 0; } -static int send_callerid(struct dahdi_pvt *p); - static int my_stop_callwait(void *pvt) { struct dahdi_pvt *p = pvt; @@ -1850,7 +1853,9 @@ 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 +1865,11 @@ 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 +1908,8 @@ 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, @@ -1978,68 +1990,72 @@ 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 (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; + 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; @@ -2228,10 +2244,10 @@ 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 +3520,7 @@ .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, @@ -5049,13 +5065,11 @@ 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; @@ -5140,6 +5154,11 @@ 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 +5634,7 @@ 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) @@ -6342,8 +6359,7 @@ 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 +7053,23 @@ return AST_BRIDGE_RETRY; } + if (p0->callwaitingcallerid || 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 +7507,98 @@ 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 (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; + 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; @@ -7632,7 +7676,7 @@ p->subs[idx].f.frametype = AST_FRAME_DTMF_END; p->subs[idx].f.subclass.integer = res & 0xff; } - dahdi_handle_dtmfup(ast, idx, &f); + dahdi_handle_dtmf(ast, idx, &f); return f; } @@ -7642,6 +7686,7 @@ 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; } @@ -7959,11 +8004,12 @@ 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 +8174,11 @@ 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) { @@ -8781,22 +8832,27 @@ 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 (idx == SUB_REAL) { + /* Ensure the CW timers decrement only on a single subchannel */ + if (p->cidcwexpire) { + --p->cidcwexpire; + + /* Expire CID/CW */ + if (p->cidcwexpire == 1) { + ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n"); + restore_conference(p); + } + } + if (p->callwaitingrepeat) { + --p->callwaitingrepeat; + + /* Repeat callwaiting tone */ + if (p->callwaitingrepeat == 1) { + ++p->callwaitrings; + dahdi_callwait(ast); + } + } } - 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 (p->subs[idx].linear) { p->subs[idx].f.datalen = READ_SIZE * 2; } else @@ -8899,11 +8955,19 @@ } 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; + default: + break; + } } /* If we have a fake_event, trigger exception to handle it */ @@ -8968,7 +9032,8 @@ 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 +10945,9 @@ 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 +11024,12 @@ 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 */ Index: channels/sig_analog.c =================================================================== --- channels/sig_analog.c (revision 295905) +++ channels/sig_analog.c (working copy) @@ -624,10 +624,10 @@ 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); } } @@ -1574,35 +1574,45 @@ } } -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); } } @@ -2631,7 +2641,7 @@ 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 +2651,7 @@ 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 +2901,10 @@ 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 +3064,8 @@ 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 +3584,10 @@ 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 */ Index: channels/sig_analog.h =================================================================== --- channels/sig_analog.h (revision 295905) +++ channels/sig_analog.h (working copy) @@ -134,10 +134,10 @@ /* 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); @@ -360,7 +360,7 @@ 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);