|
|
|
@ -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;
|
|
|
|
|