diff --git a/src/pstn/pstn.c b/src/pstn/pstn.c index 954468b..69f4cc9 100644 --- a/src/pstn/pstn.c +++ b/src/pstn/pstn.c @@ -1262,9 +1262,65 @@ static void swap_active_hold(pstn_t *pstn) jitter_reset(&pstn->tx_dejitter); } +/* process hookflash from various events: short hangup, off-hook-pulse, pulse digit 1 ... */ +static void hookflash(pstn_t *pstn) +{ + /* stop tone (CW tone) */ + tone_off(pstn); + /* clear dialing */ + pstn->dialing[0] = '\0'; + /* if call on hold, swap calls */ + if (pstn->call[PSTN_CALL_HOLD]->cc_callref) { + PDEBUG(DTEL, DEBUG_INFO, "There is a call on hold, so swap both calls.\n"); + /* swap ACTIVE call and call on HOLD */ + swap_active_hold(pstn); + /* send notify to call on hold */ + notify_ind(pstn->call[PSTN_CALL_HOLD], OSMO_CC_NOTIFY_REMOTE_HOLD); + /* if waiting call, answer it */ + if (pstn->call[PSTN_CALL_ACTIVE]->state != CALL_STATE_ACTIVE + && pstn->call[PSTN_CALL_ACTIVE]->state != CALL_STATE_HOLD) { + /* setup confirm */ + setup_cnf(pstn, PSTN_CALL_ACTIVE); + } + /* change state */ + pstn_call_state(pstn->call[PSTN_CALL_ACTIVE], CALL_STATE_ACTIVE); + pstn_call_state(pstn->call[PSTN_CALL_HOLD], CALL_STATE_HOLD); + /* send notify to active call */ + notify_ind(pstn->call[PSTN_CALL_ACTIVE], OSMO_CC_NOTIFY_REMOTE_RETRIEVAL); + return; + } + /* if active call, put it on hold and setup new call, if not en-block dialing */ + if (pstn->call[PSTN_CALL_ACTIVE]->cc_callref) { + PDEBUG(DTEL, DEBUG_INFO, "There is an active call only, so put it on hold and start a new one.\n"); + /* swap ACTIVE call and call on HOLD */ + swap_active_hold(pstn); + /* change state */ + pstn_call_state(pstn->call[PSTN_CALL_HOLD], CALL_STATE_HOLD); + /* send notify to call on hold */ + notify_ind(pstn->call[PSTN_CALL_HOLD], OSMO_CC_NOTIFY_REMOTE_HOLD); + /* start DTMF */ + dtmf_on(pstn); + /* start pulse */ + pulse_on(pstn); + if (!pstn->enblock) { + /* setup */ + setup_ind(pstn, PSTN_CALL_ACTIVE, "", 0); + } else { + /* start dial timer */ + timer_on(pstn, DIALTONE_TO, TIMER_IDENT_DIALING); + /* dial tone */ + tone_on(pstn, TONE_DIALTONE, "dial"); + /* change state */ + pstn_call_state(pstn->call[PSTN_CALL_ACTIVE], CALL_STATE_ENBLOCK); + } + return; + } +} + static void v5_sig_ind(pstn_t *pstn, uint8_t *data, int len) { osmo_cc_msg_t *new_msg; + int pulses; if (len < 3 && data[1] < 1) { PDEBUG(DTEL, DEBUG_ERROR, "Received short V5 signal message, ignoring!\n"); @@ -1277,10 +1333,10 @@ static void v5_sig_ind(pstn_t *pstn, uint8_t *data, int len) case PSTN_V5_STEADY_SIGNAL_OFF_HOOK: PDEBUG(DTEL, DEBUG_INFO, "Received steady off-kook signal.\n"); if (timer_running(&pstn->timer) && pstn->timer_ident == TIMER_IDENT_HOOKFLASH) { - PDEBUG(DTEL, DEBUG_INFO, "This was short, so this was a hookflash..\n"); + PDEBUG(DTEL, DEBUG_INFO, "Performing hookflash, because on-hook was too short for hangup.\n"); /* stop timer */ timer_off(pstn); - goto hookflash; + hookflash(pstn); } /* clear dialing */ pstn->dialing[0] = '\0'; @@ -1346,60 +1402,21 @@ static void v5_sig_ind(pstn_t *pstn, uint8_t *data, int len) switch ((data[2] & 0x7f)) { case PSTN_V5_PULSED_SIGNAL_ON_HOOK: PDEBUG(DTEL, DEBUG_INFO, "Received pulsed on-kook signal.\n"); -hookflash: - /* clear dialing */ - pstn->dialing[0] = '\0'; - /* if call on hold, swap calls */ - if (pstn->call[PSTN_CALL_HOLD]->cc_callref) { - PDEBUG(DTEL, DEBUG_INFO, "There is a call on hold, so swap both calls.\n"); - /* swap ACTIVE call and call on HOLD */ - swap_active_hold(pstn); - /* send notify to call on hold */ - notify_ind(pstn->call[PSTN_CALL_HOLD], OSMO_CC_NOTIFY_REMOTE_HOLD); - /* if waiting call, answer it */ - if (pstn->call[PSTN_CALL_ACTIVE]->state != CALL_STATE_ACTIVE - && pstn->call[PSTN_CALL_ACTIVE]->state != CALL_STATE_HOLD) { - /* setup confirm */ - setup_cnf(pstn, PSTN_CALL_ACTIVE); - } - /* change state */ - pstn_call_state(pstn->call[PSTN_CALL_ACTIVE], CALL_STATE_ACTIVE); - pstn_call_state(pstn->call[PSTN_CALL_HOLD], CALL_STATE_HOLD); - /* send notify to active call */ - notify_ind(pstn->call[PSTN_CALL_ACTIVE], OSMO_CC_NOTIFY_REMOTE_RETRIEVAL); - break; - } - /* if active call, put it on hold and setup new call, if not en-block dialing */ - if (pstn->call[PSTN_CALL_ACTIVE]->cc_callref) { - PDEBUG(DTEL, DEBUG_INFO, "There is a only an active call, so put it on hold and start a new one.\n"); - /* swap ACTIVE call and call on HOLD */ - swap_active_hold(pstn); - /* change state */ - pstn_call_state(pstn->call[PSTN_CALL_HOLD], CALL_STATE_HOLD); - /* send notify to call on hold */ - notify_ind(pstn->call[PSTN_CALL_HOLD], OSMO_CC_NOTIFY_REMOTE_HOLD); - /* start DTMF */ - dtmf_on(pstn); - /* start pulse */ - pulse_on(pstn); - if (!pstn->enblock) { - /* setup */ - setup_ind(pstn, PSTN_CALL_ACTIVE, "", 0); - } else { - /* start dial timer */ - timer_on(pstn, DIALTONE_TO, TIMER_IDENT_DIALING); - /* dial tone */ - tone_on(pstn, TONE_DIALTONE, "dial"); - /* change state */ - pstn_call_state(pstn->call[PSTN_CALL_ACTIVE], CALL_STATE_ENBLOCK); - } - break; + if (pstn->recall && pstn->call[PSTN_CALL_ACTIVE]->state == CALL_STATE_ACTIVE) { + PDEBUG(DTEL, DEBUG_INFO, "Performing hookflash, on-hook pulse was received.\n"); + hookflash(pstn); } break; } break; case PSTN_V5_IE_DIGIT_SIGNAL: - PDEBUG(DTEL, DEBUG_INFO, "Received digit signal.\n"); + pulses = data[2] & 0x0f; + PDEBUG(DTEL, DEBUG_INFO, "Received digit signal: %d pulses\n", pulses); + if (pulses == 1 && pstn->recall && pstn->call[PSTN_CALL_ACTIVE]->state == CALL_STATE_ACTIVE) { + PDEBUG(DTEL, DEBUG_INFO, "Performing hookflash, because digit '1' was dialled. (short hookflash)\n"); + hookflash(pstn); + break; + } if (!pstn->pulse_on) break; /* stop timer */ @@ -1410,7 +1427,7 @@ hookflash: tone_off(pstn); /* convert pulses -> digit */ char called[2] = { '\0', '\0' }; - switch (data[2] & 0x0f) { + switch (pulses) { case 0: PDEBUG(DTEL, DEBUG_ERROR, "Received 0 pulses, ignoring!\n"); break;