add hold-music 3way blind and attended transfer to openzap

git-svn-id: http://svn.openzap.org/svn/openzap/trunk@361 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
Anthony Minessale 2008-01-10 00:47:04 +00:00
parent 2fddaf7465
commit 169c074bcf
6 changed files with 180 additions and 20 deletions

View File

@ -48,7 +48,7 @@ struct span_config {
char context[80]; char context[80];
char dial_regex[256]; char dial_regex[256];
char fail_dial_regex[256]; char fail_dial_regex[256];
char hold_music[256];
}; };
static struct span_config SPAN_CONFIG[ZAP_MAX_SPANS_INTERFACE] = {{0}}; static struct span_config SPAN_CONFIG[ZAP_MAX_SPANS_INTERFACE] = {{0}};
@ -73,6 +73,7 @@ static struct {
unsigned int flags; unsigned int flags;
int fd; int fd;
int calls; int calls;
char hold_music[256];
switch_mutex_t *mutex; switch_mutex_t *mutex;
} globals; } globals;
@ -122,32 +123,93 @@ static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, in
} }
if (!switch_strlen_zero(channel->tokens[id])) { if (!switch_strlen_zero(channel->tokens[id])) {
session = switch_core_session_locate(channel->tokens[id]); if (!(session = switch_core_session_locate(channel->tokens[id]))) {
zap_channel_clear_token(channel, channel->tokens[id]);
}
} }
return session; return session;
} }
static void cycle_foreground(zap_channel_t *zchan, int flash) { static void stop_hold(const char *uuid)
{
switch_core_session_t *session;
switch_channel_t *channel;
if (!uuid) {
return;
}
if ((session = switch_core_session_locate(uuid))) {
channel = switch_core_session_get_channel(session);
switch_channel_stop_broadcast(channel);
switch_channel_wait_for_flag(channel, CF_BROADCAST, SWITCH_FALSE, 2000);
switch_core_session_rwunlock(session);
}
}
static void start_hold(const char *uuid, const char *music)
{
switch_core_session_t *session;
switch_channel_t *channel;
const char *stream = NULL;
if (!uuid) {
return;
}
if ((session = switch_core_session_locate(uuid))) {
channel = switch_core_session_get_channel(session);
if (!(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
stream = music;
if (switch_strlen_zero(stream)) {
stream = globals.hold_music;
}
}
if (!switch_strlen_zero(stream)) {
switch_ivr_broadcast(switch_core_session_get_uuid(session), stream, SMF_ECHO_ALEG | SMF_LOOP);
}
switch_core_session_rwunlock(session);
}
}
static void cycle_foreground(zap_channel_t *zchan, int flash, const char *bcast) {
uint32_t i = 0; uint32_t i = 0;
switch_core_session_t *session; switch_core_session_t *session;
switch_channel_t *channel; switch_channel_t *channel;
private_t *tech_pvt; private_t *tech_pvt;
if (!bcast) {
bcast = SPAN_CONFIG[zchan->span->span_id].hold_music;
}
for (i = 0; i < zchan->token_count; i++) { for (i = 0; i < zchan->token_count; i++) {
if ((session = zap_channel_get_session(zchan, i))) { if ((session = zap_channel_get_session(zchan, i))) {
const char *buuid;
tech_pvt = switch_core_session_get_private(session); tech_pvt = switch_core_session_get_private(session);
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
buuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
if (zchan->token_count == 1 && flash) { if (zchan->token_count == 1 && flash) {
if (switch_test_flag(tech_pvt, TFLAG_HOLD)) { if (switch_test_flag(tech_pvt, TFLAG_HOLD)) {
stop_hold(buuid);
switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
} else { } else {
start_hold(buuid, bcast);
switch_set_flag_locked(tech_pvt, TFLAG_HOLD); switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
} }
} else if (i) { } else if (i) {
start_hold(buuid, bcast);
switch_set_flag_locked(tech_pvt, TFLAG_HOLD); switch_set_flag_locked(tech_pvt, TFLAG_HOLD);
} else { } else {
stop_hold(buuid);
switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
if (!switch_channel_test_flag(channel, CF_ANSWERED)) { if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
switch_channel_mark_answered(channel); switch_channel_mark_answered(channel);
@ -173,6 +235,7 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
tech_pvt->cng_frame.data = tech_pvt->cng_databuf; tech_pvt->cng_frame.data = tech_pvt->cng_databuf;
tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf); tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf);
tech_pvt->cng_frame.flags = SFF_CNG; tech_pvt->cng_frame.flags = SFF_CNG;
tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.buflen); memset(tech_pvt->cng_frame.data, 255, tech_pvt->cng_frame.buflen);
switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session)); switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
@ -320,7 +383,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
{ {
if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_BUSY && tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) { if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_BUSY && tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
if (tech_pvt->zchan->token_count) { if (tech_pvt->zchan->token_count) {
cycle_foreground(tech_pvt->zchan, 0); cycle_foreground(tech_pvt->zchan, 0, NULL);
} else { } else {
zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP); zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
} }
@ -739,7 +802,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
} }
} }
if (!switch_strlen_zero(dest)) { if (switch_strlen_zero(dest)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid dial string\n");
return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
} }
@ -849,7 +912,8 @@ zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t
return ZAP_FAIL; return ZAP_FAIL;
} }
*sigmsg->channel->caller_data.collected = '\0';
if (switch_strlen_zero(sigmsg->channel->caller_data.cid_name)) { if (switch_strlen_zero(sigmsg->channel->caller_data.cid_name)) {
switch_set_string(sigmsg->channel->caller_data.cid_name, sigmsg->channel->chan_name); switch_set_string(sigmsg->channel->caller_data.cid_name, sigmsg->channel->chan_name);
} }
@ -985,18 +1049,104 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
break; break;
case ZAP_SIGEVENT_STOP: case ZAP_SIGEVENT_STOP:
{ {
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
if (sigmsg->channel->token_count) {
switch_core_session_t *session_a, *session_b, *session_t = NULL;
switch_channel_t *channel_a = NULL, *channel_b = NULL;
int digits = !switch_strlen_zero(sigmsg->channel->caller_data.collected);
const char *br_a_uuid = NULL, *br_b_uuid = NULL;
private_t *tech_pvt = NULL;
if ((session_a = switch_core_session_locate(sigmsg->channel->tokens[0]))) {
channel_a = switch_core_session_get_channel(session_a);
br_a_uuid = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
tech_pvt = switch_core_session_get_private(session_a);
stop_hold(switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE));
switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
}
if ((session_b = switch_core_session_locate(sigmsg->channel->tokens[1]))) {
channel_b = switch_core_session_get_channel(session_b);
br_b_uuid = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE);
tech_pvt = switch_core_session_get_private(session_b);
stop_hold(switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_VARIABLE));
switch_clear_flag_locked(tech_pvt, TFLAG_HOLD);
}
if (channel_a && channel_b && !switch_channel_test_flag(channel_a, CF_OUTBOUND) && !switch_channel_test_flag(channel_b, CF_OUTBOUND)) {
cause = SWITCH_CAUSE_ATTENDED_TRANSFER;
if (br_a_uuid && br_b_uuid) {
switch_ivr_uuid_bridge(br_a_uuid, br_b_uuid);
} else if (br_a_uuid && digits) {
session_t = switch_core_session_locate(br_a_uuid);
} else if (br_b_uuid && digits) {
session_t = switch_core_session_locate(br_b_uuid);
}
}
if (session_t) {
switch_ivr_session_transfer(session_t, sigmsg->channel->caller_data.collected, NULL, NULL);
switch_core_session_rwunlock(session_t);
}
if (session_a) {
switch_core_session_rwunlock(session_a);
}
if (session_b) {
switch_core_session_rwunlock(session_b);
}
}
while((session = zap_channel_get_session(sigmsg->channel, 0))) { while((session = zap_channel_get_session(sigmsg->channel, 0))) {
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); switch_channel_hangup(channel, cause);
zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session)); zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
switch_core_session_rwunlock(session); switch_core_session_rwunlock(session);
} }
zap_channel_clear_token(sigmsg->channel, NULL);
} }
break; break;
case ZAP_SIGEVENT_ADD_CALL:
{
cycle_foreground(sigmsg->channel, 1, NULL);
}
break;
case ZAP_SIGEVENT_FLASH: case ZAP_SIGEVENT_FLASH:
{ {
cycle_foreground(sigmsg->channel, 1);
if (sigmsg->channel->token_count == 2) {
if (zap_test_flag(sigmsg->channel, ZAP_CHANNEL_3WAY)) {
zap_clear_flag(sigmsg->channel, ZAP_CHANNEL_3WAY);
if ((session = zap_channel_get_session(sigmsg->channel, 1))) {
channel = switch_core_session_get_channel(session);
switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
zap_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
switch_core_session_rwunlock(session);
}
cycle_foreground(sigmsg->channel, 1, NULL);
} else {
char *cmd;
cmd = switch_mprintf("three_way::%s", sigmsg->channel->tokens[0]);
zap_set_flag(sigmsg->channel, ZAP_CHANNEL_3WAY);
cycle_foreground(sigmsg->channel, 1, cmd);
free(cmd);
}
} else {
cycle_foreground(sigmsg->channel, 1, NULL);
if (sigmsg->channel->token_count == 1) {
zap_set_flag_locked(sigmsg->channel, ZAP_CHANNEL_HOLD);
zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_DIALTONE);
}
}
} }
break; break;
@ -1013,7 +1163,9 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
if (switch_strlen_zero(fail_regex)) { if (switch_strlen_zero(fail_regex)) {
fail_regex = NULL; fail_regex = NULL;
} }
switch_set_string(sigmsg->channel->caller_data.collected, dtmf);
if ((regex || fail_regex) && !switch_strlen_zero(dtmf)) { if ((regex || fail_regex) && !switch_strlen_zero(dtmf)) {
switch_regex_t *re = NULL; switch_regex_t *re = NULL;
int ovector[30]; int ovector[30];
@ -1171,6 +1323,8 @@ static switch_status_t load_config(void)
if (!strcasecmp(var, "debug")) { if (!strcasecmp(var, "debug")) {
globals.debug = atoi(val); globals.debug = atoi(val);
} else if (!strcasecmp(var, "hold-music")) {
switch_set_string(globals.hold_music, val);
} }
} }
} }
@ -1184,6 +1338,7 @@ static switch_status_t load_config(void)
char *digit_timeout = NULL; char *digit_timeout = NULL;
char *max_digits = NULL; char *max_digits = NULL;
char *dial_regex = NULL; char *dial_regex = NULL;
char *hold_music = NULL;
char *fail_dial_regex = NULL; char *fail_dial_regex = NULL;
uint32_t span_id = 0, to = 0, max = 0; uint32_t span_id = 0, to = 0, max = 0;
zap_span_t *span = NULL; zap_span_t *span = NULL;
@ -1204,6 +1359,8 @@ static switch_status_t load_config(void)
dial_regex = val; dial_regex = val;
} else if (!strcasecmp(var, "fail-dial-regex")) { } else if (!strcasecmp(var, "fail-dial-regex")) {
fail_dial_regex = val; fail_dial_regex = val;
} else if (!strcasecmp(var, "hold-music")) {
hold_music = val;
} else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) { } else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) {
digit_timeout = val; digit_timeout = val;
} }
@ -1249,6 +1406,10 @@ static switch_status_t load_config(void)
switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex); switch_set_string(SPAN_CONFIG[span->span_id].fail_dial_regex, fail_dial_regex);
} }
if (hold_music) {
switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music);
}
zap_analog_start(span); zap_analog_start(span);
} }
} }

View File

@ -313,6 +313,7 @@ struct zap_caller_data {
char aniII[25]; char aniII[25];
char dnis[25]; char dnis[25];
char rdnis[25]; char rdnis[25];
char collected[25];
int CRV; int CRV;
int hangup_cause; int hangup_cause;
uint8_t raw_data[1024]; uint8_t raw_data[1024];

View File

@ -181,10 +181,11 @@ typedef enum {
ZAP_SIGEVENT_ALARM_CLEAR, ZAP_SIGEVENT_ALARM_CLEAR,
ZAP_SIGEVENT_MISC, ZAP_SIGEVENT_MISC,
ZAP_SIGEVENT_COLLECTED_DIGIT, ZAP_SIGEVENT_COLLECTED_DIGIT,
ZAP_SIGEVENT_ADD_CALL,
ZAP_SIGEVENT_INVALID ZAP_SIGEVENT_INVALID
} zap_signal_event_t; } zap_signal_event_t;
#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "FLASH", "PROGRESS", \ #define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "FLASH", "PROGRESS", \
"PROGRESS_MEDIA", "NOTIFY", "TONE_DETECTED", "ALARM_TRAP", "ALARM_CLEAR", "MISC", "COLLECTED_DIGIT", "INVALID" "PROGRESS_MEDIA", "NOTIFY", "TONE_DETECTED", "ALARM_TRAP", "ALARM_CLEAR", "MISC", "COLLECTED_DIGIT", "ADD_CALL", "INVALID"
ZAP_STR2ENUM_P(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t) ZAP_STR2ENUM_P(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t)
typedef enum { typedef enum {
@ -326,7 +327,8 @@ typedef enum {
ZAP_CHANNEL_PROGRESS_DETECT = (1 << 16), ZAP_CHANNEL_PROGRESS_DETECT = (1 << 16),
ZAP_CHANNEL_CALLERID_DETECT = (1 << 17), ZAP_CHANNEL_CALLERID_DETECT = (1 << 17),
ZAP_CHANNEL_OUTBOUND = (1 << 18), ZAP_CHANNEL_OUTBOUND = (1 << 18),
ZAP_CHANNEL_SUSPENDED = (1 << 19) ZAP_CHANNEL_SUSPENDED = (1 << 19),
ZAP_CHANNEL_3WAY = (1 << 20)
} zap_channel_flag_t; } zap_channel_flag_t;
typedef struct zap_channel zap_channel_t; typedef struct zap_channel zap_channel_t;

View File

@ -372,7 +372,7 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
if (zap_test_flag(zchan, ZAP_CHANNEL_HOLD)) { if (zap_test_flag(zchan, ZAP_CHANNEL_HOLD)) {
zap_clear_flag(zchan, ZAP_CHANNEL_HOLD); zap_clear_flag(zchan, ZAP_CHANNEL_HOLD);
sig.event_id = ZAP_SIGEVENT_FLASH; sig.event_id = ZAP_SIGEVENT_ADD_CALL;
} else { } else {
sig.event_id = ZAP_SIGEVENT_UP; sig.event_id = ZAP_SIGEVENT_UP;
} }
@ -707,10 +707,6 @@ static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *even
} else { } else {
sig.event_id = ZAP_SIGEVENT_FLASH; sig.event_id = ZAP_SIGEVENT_FLASH;
analog_data->sig_cb(&sig); analog_data->sig_cb(&sig);
if (event->channel->token_count == 1) {
zap_set_flag_locked(event->channel, ZAP_CHANNEL_HOLD);
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE);
}
} }
} }
break; break;

View File

@ -558,7 +558,7 @@ static ZIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
{ {
int items, i; int items, i;
char *mydata, *item_list[10]; char *mydata, *item_list[10];
char *bd, *sp, *ch, *mx; char *bd, *sp, *ch = NULL, *mx;
int boardno; int boardno;
int channo; int channo;
int spanno; int spanno;
@ -978,7 +978,7 @@ static ZIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
static ZIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event) static ZIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
{ {
uint32_t i, event_id; uint32_t i, event_id = 0;
for(i = 1; i <= span->chan_count; i++) { for(i = 1; i <= span->chan_count; i++) {
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) { if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {

View File

@ -568,8 +568,8 @@ ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
{ {
uint32_t i, event_id; uint32_t i, event_id = 0;
zap_oob_event_t zt_event_id; zap_oob_event_t zt_event_id = 0;
for(i = 1; i <= span->chan_count; i++) { for(i = 1; i <= span->chan_count; i++) {
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) { if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {