Skip to content
Snippets Groups Projects
Commit 757441b6 authored by Adam Borowski's avatar Adam Borowski Committed by Sukru Senli
Browse files

Feature 4599 - Integration of call clearing tones into iopsys voice

Play howler tone in case user forgot to put handset on hook
as a reminder to end the call properly.
parent e69fcb62
No related branches found
No related tags found
No related merge requests found
...@@ -105,6 +105,7 @@ static void *pe_base_run(void *unused); ...@@ -105,6 +105,7 @@ static void *pe_base_run(void *unused);
static int brcm_create_connection(struct brcm_subchannel *p); static int brcm_create_connection(struct brcm_subchannel *p);
static int brcm_signal_congestion(struct brcm_pvt *p); static int brcm_signal_congestion(struct brcm_pvt *p);
static int brcm_stop_dialtone(struct brcm_pvt *p); static int brcm_stop_dialtone(struct brcm_pvt *p);
static void brcm_signal_howler(struct brcm_pvt *p);
static int brcm_signal_ringing(struct brcm_pvt *p); static int brcm_signal_ringing(struct brcm_pvt *p);
static int brcm_stop_ringing(struct brcm_pvt *p); static int brcm_stop_ringing(struct brcm_pvt *p);
static int brcm_signal_ringing_callerid_pending(struct brcm_pvt *p); static int brcm_signal_ringing_callerid_pending(struct brcm_pvt *p);
...@@ -122,6 +123,7 @@ static int brcm_should_relay_dtmf(const struct brcm_subchannel *sub); ...@@ -122,6 +123,7 @@ static int brcm_should_relay_dtmf(const struct brcm_subchannel *sub);
static struct ast_channel *brcm_new(struct brcm_subchannel *subchan, int state, const char *ext, const char *context, static struct ast_channel *brcm_new(struct brcm_subchannel *subchan, int state, const char *ext, const char *context,
const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor,
struct ast_format_cap *format); struct ast_format_cap *format);
static int handle_dialtone_timeout(const void *data);
/* Global brcm channel parameters */ /* Global brcm channel parameters */
static const char tdesc[] = "Broadcom SLIC Driver"; static const char tdesc[] = "Broadcom SLIC Driver";
...@@ -832,7 +834,9 @@ static int brcm_hangup(struct ast_channel *ast) ...@@ -832,7 +834,9 @@ static int brcm_hangup(struct ast_channel *ast)
p = sub->parent; p = sub->parent;
sub_peer = brcm_subchannel_get_peer(sub); sub_peer = brcm_subchannel_get_peer(sub);
ast_debug(1, "brcm_hangup(%s) line_id=%d connection_id=%d\n", ast_channel_name(ast), p->line_id, sub->connection_id); ast_debug(1, "brcm_hangup(%s) line_id=%d connection_id=%d dialtone=%s channel_state=%s\n",
ast_channel_name(ast), p->line_id, sub->connection_id, dialtone_map[p->dialtone].str,
state2str(sub->channel_state));
if (sub->channel_state == CALLWAITING) { if (sub->channel_state == CALLWAITING) {
brcm_stop_callwaiting(p); brcm_stop_callwaiting(p);
...@@ -877,7 +881,18 @@ static int brcm_hangup(struct ast_channel *ast) ...@@ -877,7 +881,18 @@ static int brcm_hangup(struct ast_channel *ast)
p->lastformat = NULL; p->lastformat = NULL;
p->lastinput = NULL; p->lastinput = NULL;
p->hf_detected = 0; p->hf_detected = 0;
sub->channel_state = CALLENDED;
/**
* Howler tone is played using a media file on an active channel
* Treated like a normal call but we want to preserve the channel state
* Additional check for ONHOOK channel state so that handle_dialtone_timeout()
* isn't called again when going on-hook
*/
if(p->dialtone != DIALTONE_HOWLER && sub->channel_state != ONHOOK) {
sub->channel_state = CALLENDED;
ast_debug(6, "Setting channel state to %s\n", state2str(sub->channel_state));
}
if (terminate_conference && sub->conference_initiator && brcm_in_conference(p)) { if (terminate_conference && sub->conference_initiator && brcm_in_conference(p)) {
/* Switch still active call leg out of conference mode */ /* Switch still active call leg out of conference mode */
brcm_stop_conference(sub); brcm_stop_conference(sub);
...@@ -895,6 +910,12 @@ static int brcm_hangup(struct ast_channel *ast) ...@@ -895,6 +910,12 @@ static int brcm_hangup(struct ast_channel *ast)
ast_channel_tech_pvt_set(ast, NULL); ast_channel_tech_pvt_set(ast, NULL);
brcm_close_connection(sub); brcm_close_connection(sub);
if(sub->channel_state == CALLENDED) {
/* If we hangup but not playing howler, start playing timeout tones */
p->dialtone = DIALTONE_ON;
handle_dialtone_timeout(p);
}
pvt_unlock(p); pvt_unlock(p);
return 0; return 0;
} }
...@@ -927,7 +948,15 @@ static int brcm_answer(struct ast_channel *ast) ...@@ -927,7 +948,15 @@ static int brcm_answer(struct ast_channel *ast)
ast_debug(2, "brcm_answer(%s) set state to up\n", ast_channel_name(ast)); ast_debug(2, "brcm_answer(%s) set state to up\n", ast_channel_name(ast));
} }
ast_channel_rings_set(ast, 0); ast_channel_rings_set(ast, 0);
sub->channel_state = INCALL;
/**
* Howler tone is played using a media file on an active channel
* Treated like a normal call but we want to preserve the channel_state
*/
if(pvt->dialtone != DIALTONE_HOWLER) {
sub->channel_state = INCALL;
}
endpt_signal(pvt->line_id, "ringback", "off", NULL); endpt_signal(pvt->line_id, "ringback", "off", NULL);
pvt_unlock(pvt); pvt_unlock(pvt);
...@@ -1130,11 +1159,13 @@ struct brcm_subchannel *brcm_subchannel_get_peer(const struct brcm_subchannel *s ...@@ -1130,11 +1159,13 @@ struct brcm_subchannel *brcm_subchannel_get_peer(const struct brcm_subchannel *s
/* Tell endpoint to play country specific dialtone. */ /* Tell endpoint to play country specific dialtone. */
static int brcm_signal_dialtone(struct brcm_pvt *p) { static int brcm_signal_dialtone(struct brcm_pvt *p) {
ast_verbose("Setting dialtone to %s\n", dialtone_map[p->dialtone].str);
switch (p->dialtone) { switch (p->dialtone) {
case DIALTONE_OFF: case DIALTONE_OFF:
endpt_signal(p->line_id, "dial", "off", NULL); endpt_signal(p->line_id, "dial", "off", NULL);
endpt_signal(p->line_id, "stutter", "off", NULL); endpt_signal(p->line_id, "stutter", "off", NULL);
endpt_signal(p->line_id, "unobtainable", "off", NULL);
break; break;
case DIALTONE_ON: case DIALTONE_ON:
endpt_signal(p->line_id, "dial", "on", NULL); endpt_signal(p->line_id, "dial", "on", NULL);
...@@ -1145,6 +1176,13 @@ static int brcm_signal_dialtone(struct brcm_pvt *p) { ...@@ -1145,6 +1176,13 @@ static int brcm_signal_dialtone(struct brcm_pvt *p) {
case DIALTONE_SPECIAL_CONDITION: case DIALTONE_SPECIAL_CONDITION:
endpt_signal(p->line_id, "stutter", "on", NULL); endpt_signal(p->line_id, "stutter", "on", NULL);
break; break;
case DIALTONE_UNOBTAINABLE:
endpt_signal(p->line_id, "unobtainable", "on", NULL);
break;
case DIALTONE_HOWLER:
ast_debug(9, "Trigger howler tone from Asterisk\n");
brcm_signal_howler(p);
break;
default: default:
ast_log(LOG_ERROR, "Requested to signal unknown dialtone\n"); ast_log(LOG_ERROR, "Requested to signal unknown dialtone\n");
return -1; return -1;
...@@ -1152,10 +1190,29 @@ static int brcm_signal_dialtone(struct brcm_pvt *p) { ...@@ -1152,10 +1190,29 @@ static int brcm_signal_dialtone(struct brcm_pvt *p) {
return 0; return 0;
} }
static void brcm_signal_howler(struct brcm_pvt *p) {
struct brcm_subchannel *sub = brcm_get_active_subchannel(p);
if(!sub) {
ast_debug(9, "Unable to find active subchannel\n");
return;
}
/* Start the pbx */
if (!sub->connection_init) {
sub->connection_id = ast_atomic_fetchadd_int((int *)&current_connection_id, +1);
brcm_create_connection(sub);
}
/* Create a new channel to context 'howler' handled by extensions.conf */
brcm_new(sub, AST_STATE_RING, "0", "howler", NULL, NULL, NULL);
}
int brcm_stop_dialtone(struct brcm_pvt *p) { int brcm_stop_dialtone(struct brcm_pvt *p) {
endpt_signal(p->line_id, "dial", "off", NULL); endpt_signal(p->line_id, "dial", "off", NULL);
endpt_signal(p->line_id, "stutter", "off", NULL); endpt_signal(p->line_id, "stutter", "off", NULL);
p->dialtone = DIALTONE_OFF;
brcm_signal_dialtone(p);
return 0; return 0;
} }
...@@ -1537,10 +1594,29 @@ static int handle_dialtone_timeout(const void *data) ...@@ -1537,10 +1594,29 @@ static int handle_dialtone_timeout(const void *data)
p->dialtone_timeout_timer_id = -1; p->dialtone_timeout_timer_id = -1;
struct brcm_subchannel *sub = brcm_get_active_subchannel(p); struct brcm_subchannel *sub = brcm_get_active_subchannel(p);
if (sub && sub->channel_state == OFFHOOK) { if (sub && (sub->channel_state == OFFHOOK || sub->channel_state == AWAITONHOOK || sub->channel_state == CALLENDED)) {
/* Enter state where nothing else than ONHOOK is accepted and play congestion tone */ /* Enter state where nothing else other than ONHOOK is accepted and play series of tones */
sub->channel_state = AWAITONHOOK; sub->channel_state = AWAITONHOOK;
brcm_signal_congestion(p); line_settings *s = &line_config[p->line_id];
switch (p->dialtone) {
case DIALTONE_ON:
p->dialtone = DIALTONE_UNOBTAINABLE;
p->dialtone_timeout_timer_id = ast_sched_add(sched, s->offhook_nu_timeoutmsec, handle_dialtone_timeout, p);
break;
case DIALTONE_UNOBTAINABLE:
p->dialtone = DIALTONE_OFF;
p->dialtone_timeout_timer_id = ast_sched_add(sched, s->offhook_silence_timeoutmsec, handle_dialtone_timeout, p);
break;
case DIALTONE_OFF:
p->dialtone = DIALTONE_HOWLER;
break;
default:
p->dialtone = DIALTONE_OFF;
ast_log(LOG_ERROR, "Invalid dialtone timeout state\n");
break;
}
brcm_signal_dialtone(p);
} }
//ast_mutex_unlock(&p->lock); //ast_mutex_unlock(&p->lock);
...@@ -1638,6 +1714,7 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel ...@@ -1638,6 +1714,7 @@ static void handle_hookflash(struct brcm_subchannel *sub, struct brcm_subchannel
} }
/* Provide new line */ /* Provide new line */
p->dialtone = DIALTONE_ON;
brcm_signal_dialtone(p); brcm_signal_dialtone(p);
sub_peer->channel_state = OFFHOOK; sub_peer->channel_state = OFFHOOK;
...@@ -2140,7 +2217,7 @@ static void *brcm_process_event(struct endpt_event *ev) { ...@@ -2140,7 +2217,7 @@ static void *brcm_process_event(struct endpt_event *ev) {
struct brcm_pvt *p = NULL; struct brcm_pvt *p = NULL;
struct brcm_subchannel *sub = NULL; struct brcm_subchannel *sub = NULL;
ast_debug(9, "Event %s detected\n", ev->name); ast_debug(9, "Event %s detected from line %d\n", ev->name, ev->line);
p = brcm_get_pvt_from_lineid(iflist, ev->line); p = brcm_get_pvt_from_lineid(iflist, ev->line);
if (!p) { if (!p) {
ast_debug(3, "No pvt with the correct line_id %d found!\n", ev->line); ast_debug(3, "No pvt with the correct line_id %d found!\n", ev->line);
...@@ -2234,21 +2311,21 @@ static void *brcm_process_event(struct endpt_event *ev) { ...@@ -2234,21 +2311,21 @@ static void *brcm_process_event(struct endpt_event *ev) {
} }
else if (sub->channel_state == OFFHOOK) { else if (sub->channel_state == OFFHOOK) {
/* EVENT_OFFHOOK changed endpoint state to OFFHOOK, apply dialtone */ /* EVENT_OFFHOOK changed endpoint state to OFFHOOK, apply dialtone */
ast_debug(9, "Resetting dial tones.\n"); if ( p->context[0] != '\0' && is_sip_account_registered(p->context)) {
if ( p->context[0] != '\0' && is_sip_account_registered(p->context)) { ast_debug(9, "Resetting dial tones.\n");
p->dialtone = DIALTONE_ON; p->dialtone = DIALTONE_ON;
brcm_signal_dialtone(p); brcm_signal_dialtone(p);
} line_settings *s = &line_config[p->line_id];
if (strlen(s->autodial_ext)) {
line_settings *s = &line_config[p->line_id]; /* Schedule autodial timeout if autodial extension is set */
p->autodial_timer_id = ast_sched_add(sched, s->autodial_timeoutmsec, handle_autodial_timeout, p);
if (strlen(s->autodial_ext)) { } else {
/* Schedule autodial timeout if autodial extension is set */ /* No autodial, schedule dialtone timeout */
p->autodial_timer_id = ast_sched_add(sched, s->autodial_timeoutmsec, handle_autodial_timeout, p); ast_verbose("Scheduling dialtone timeout in %dms\n", s->dialtone_timeoutmsec);
} p->dialtone_timeout_timer_id = ast_sched_add(sched, s->dialtone_timeoutmsec, handle_dialtone_timeout, p);
else { }
/* No autodial, schedule dialtone timeout */ } else {
p->dialtone_timeout_timer_id = ast_sched_add(sched, s->dialtone_timeoutmsec, handle_dialtone_timeout, p); ast_debug(9, "OFFHOOK but SIP account not registered\n");
} }
} }
break; break;
...@@ -2678,6 +2755,7 @@ static void brcm_show_pvts(struct ast_cli_args *a) ...@@ -2678,6 +2755,7 @@ static void brcm_show_pvts(struct ast_cli_args *a)
dialtone++; dialtone++;
} }
ast_cli(a->fd, "%s\n", dialtone->str); ast_cli(a->fd, "%s\n", dialtone->str);
ast_cli(a->fd, "Dialtone Timer id : %d\n", p->dialtone_timeout_timer_id);
/* Print status for subchannels */ /* Print status for subchannels */
brcm_show_subchannels(a, p); brcm_show_subchannels(a, p);
...@@ -3014,6 +3092,8 @@ static line_settings line_settings_create(void) ...@@ -3014,6 +3092,8 @@ static line_settings line_settings_create(void)
.period = 20, .period = 20,
.hangup_xfer = 0, .hangup_xfer = 0,
.dialtone_timeoutmsec = 20000, .dialtone_timeoutmsec = 20000,
.offhook_nu_timeoutmsec = 60000,
.offhook_silence_timeoutmsec = 180000,
.callwaiting = 1, .callwaiting = 1,
.do_not_disturb = 0, .do_not_disturb = 0,
.clir = 0, .clir = 0,
...@@ -3052,6 +3132,10 @@ static void line_settings_load(line_settings *line_config, struct ast_variable * ...@@ -3052,6 +3132,10 @@ static void line_settings_load(line_settings *line_config, struct ast_variable *
line_config->autodial_timeoutmsec = atoi(v->value); line_config->autodial_timeoutmsec = atoi(v->value);
} else if (!strcasecmp(v->name, "dialtone_timeoutmsec")) { } else if (!strcasecmp(v->name, "dialtone_timeoutmsec")) {
line_config->dialtone_timeoutmsec = atoi(v->value); line_config->dialtone_timeoutmsec = atoi(v->value);
} else if (!strcasecmp(v->name, "offhook_nu_timeoutmsec")) {
line_config->offhook_nu_timeoutmsec = atoi(v->value);
} else if (!strcasecmp(v->name, "offhook_silence_timeoutmsec")) {
line_config->offhook_silence_timeoutmsec = atoi(v->value);
} }
else if (!strcasecmp(v->name, "hangup_xfer")) { else if (!strcasecmp(v->name, "hangup_xfer")) {
line_config->hangup_xfer = ast_true(v->value)?1:0; line_config->hangup_xfer = ast_true(v->value)?1:0;
......
...@@ -86,6 +86,8 @@ typedef enum dialtone_state { ...@@ -86,6 +86,8 @@ typedef enum dialtone_state {
DIALTONE_ON, DIALTONE_ON,
DIALTONE_CONGESTION, DIALTONE_CONGESTION,
DIALTONE_SPECIAL_CONDITION, DIALTONE_SPECIAL_CONDITION,
DIALTONE_UNOBTAINABLE,
DIALTONE_HOWLER,
DIALTONE_UNKNOWN, DIALTONE_UNKNOWN,
DIALTONE_LAST, DIALTONE_LAST,
} dialtone_state; } dialtone_state;
...@@ -175,7 +177,7 @@ typedef struct DTMF_CHARNAME_MAP ...@@ -175,7 +177,7 @@ typedef struct DTMF_CHARNAME_MAP
typedef struct DIALTONE_MAP typedef struct DIALTONE_MAP
{ {
dialtone_state state; dialtone_state state;
char str[11]; char str[24];
} DIALTONE_MAP; } DIALTONE_MAP;
static const DIALTONE_MAP dialtone_map[] = static const DIALTONE_MAP dialtone_map[] =
...@@ -184,6 +186,8 @@ static const DIALTONE_MAP dialtone_map[] = ...@@ -184,6 +186,8 @@ static const DIALTONE_MAP dialtone_map[] =
{DIALTONE_ON, "on"}, {DIALTONE_ON, "on"},
{DIALTONE_CONGESTION, "congestion"}, {DIALTONE_CONGESTION, "congestion"},
{DIALTONE_SPECIAL_CONDITION, "special"}, {DIALTONE_SPECIAL_CONDITION, "special"},
{DIALTONE_UNOBTAINABLE, "number unobtainable"},
{DIALTONE_HOWLER, "howler"},
{DIALTONE_UNKNOWN, "unknown"}, {DIALTONE_UNKNOWN, "unknown"},
{DIALTONE_LAST, "-"}, {DIALTONE_LAST, "-"},
}; };
...@@ -205,6 +209,8 @@ typedef struct { ...@@ -205,6 +209,8 @@ typedef struct {
int period; int period;
int hangup_xfer; int hangup_xfer;
int dialtone_timeoutmsec; int dialtone_timeoutmsec;
int offhook_nu_timeoutmsec;
int offhook_silence_timeoutmsec;
int callwaiting; int callwaiting;
int do_not_disturb; int do_not_disturb;
int clir; int clir;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment