diff --git a/libs/openzap/mod_openzap/mod_openzap.c b/libs/openzap/mod_openzap/mod_openzap.c index 5323715ab2..b9de0281b5 100644 --- a/libs/openzap/mod_openzap/mod_openzap.c +++ b/libs/openzap/mod_openzap/mod_openzap.c @@ -48,7 +48,7 @@ struct span_config { char context[80]; char dial_regex[256]; char fail_dial_regex[256]; - + char hold_music[256]; }; static struct span_config SPAN_CONFIG[ZAP_MAX_SPANS_INTERFACE] = {{0}}; @@ -73,6 +73,7 @@ static struct { unsigned int flags; int fd; int calls; + char hold_music[256]; switch_mutex_t *mutex; } 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])) { - 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; } -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; switch_core_session_t *session; switch_channel_t *channel; private_t *tech_pvt; + if (!bcast) { + bcast = SPAN_CONFIG[zchan->span->span_id].hold_music; + } + for (i = 0; i < zchan->token_count; i++) { if ((session = zap_channel_get_session(zchan, i))) { + const char *buuid; tech_pvt = switch_core_session_get_private(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 (switch_test_flag(tech_pvt, TFLAG_HOLD)) { + stop_hold(buuid); switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); } else { + start_hold(buuid, bcast); switch_set_flag_locked(tech_pvt, TFLAG_HOLD); } } else if (i) { + start_hold(buuid, bcast); switch_set_flag_locked(tech_pvt, TFLAG_HOLD); } else { + stop_hold(buuid); switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); if (!switch_channel_test_flag(channel, CF_ANSWERED)) { 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.buflen = sizeof(tech_pvt->cng_databuf); 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); 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)); @@ -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->token_count) { - cycle_foreground(tech_pvt->zchan, 0); + cycle_foreground(tech_pvt->zchan, 0, NULL); } else { 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"); 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; } - + *sigmsg->channel->caller_data.collected = '\0'; + if (switch_strlen_zero(sigmsg->channel->caller_data.cid_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; 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))) { 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)); switch_core_session_rwunlock(session); } + zap_channel_clear_token(sigmsg->channel, NULL); + } break; + case ZAP_SIGEVENT_ADD_CALL: + { + cycle_foreground(sigmsg->channel, 1, NULL); + } + break; 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; @@ -1013,7 +1163,9 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal) if (switch_strlen_zero(fail_regex)) { fail_regex = NULL; } - + + switch_set_string(sigmsg->channel->caller_data.collected, dtmf); + if ((regex || fail_regex) && !switch_strlen_zero(dtmf)) { switch_regex_t *re = NULL; int ovector[30]; @@ -1171,6 +1323,8 @@ static switch_status_t load_config(void) if (!strcasecmp(var, "debug")) { 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 *max_digits = NULL; char *dial_regex = NULL; + char *hold_music = NULL; char *fail_dial_regex = NULL; uint32_t span_id = 0, to = 0, max = 0; zap_span_t *span = NULL; @@ -1204,6 +1359,8 @@ static switch_status_t load_config(void) dial_regex = val; } else if (!strcasecmp(var, "fail-dial-regex")) { fail_dial_regex = val; + } else if (!strcasecmp(var, "hold-music")) { + hold_music = val; } else if (!strcasecmp(var, "max_digits") || !strcasecmp(var, "max-digits")) { 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); } + if (hold_music) { + switch_set_string(SPAN_CONFIG[span->span_id].hold_music, hold_music); + } + zap_analog_start(span); } } diff --git a/libs/openzap/src/include/openzap.h b/libs/openzap/src/include/openzap.h index 14b46b7167..866c665251 100644 --- a/libs/openzap/src/include/openzap.h +++ b/libs/openzap/src/include/openzap.h @@ -313,6 +313,7 @@ struct zap_caller_data { char aniII[25]; char dnis[25]; char rdnis[25]; + char collected[25]; int CRV; int hangup_cause; uint8_t raw_data[1024]; diff --git a/libs/openzap/src/include/zap_types.h b/libs/openzap/src/include/zap_types.h index aac07d19f4..dfcf339026 100644 --- a/libs/openzap/src/include/zap_types.h +++ b/libs/openzap/src/include/zap_types.h @@ -181,10 +181,11 @@ typedef enum { ZAP_SIGEVENT_ALARM_CLEAR, ZAP_SIGEVENT_MISC, ZAP_SIGEVENT_COLLECTED_DIGIT, + ZAP_SIGEVENT_ADD_CALL, ZAP_SIGEVENT_INVALID } zap_signal_event_t; #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) typedef enum { @@ -326,7 +327,8 @@ typedef enum { ZAP_CHANNEL_PROGRESS_DETECT = (1 << 16), ZAP_CHANNEL_CALLERID_DETECT = (1 << 17), ZAP_CHANNEL_OUTBOUND = (1 << 18), - ZAP_CHANNEL_SUSPENDED = (1 << 19) + ZAP_CHANNEL_SUSPENDED = (1 << 19), + ZAP_CHANNEL_3WAY = (1 << 20) } zap_channel_flag_t; typedef struct zap_channel zap_channel_t; diff --git a/libs/openzap/src/zap_analog.c b/libs/openzap/src/zap_analog.c index 2cb06d0d91..ccbea0b32b 100644 --- a/libs/openzap/src/zap_analog.c +++ b/libs/openzap/src/zap_analog.c @@ -372,7 +372,7 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) if (zap_test_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 { 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 { sig.event_id = ZAP_SIGEVENT_FLASH; 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; diff --git a/libs/openzap/src/zap_pika.c b/libs/openzap/src/zap_pika.c index b78710054c..2081867255 100644 --- a/libs/openzap/src/zap_pika.c +++ b/libs/openzap/src/zap_pika.c @@ -558,7 +558,7 @@ static ZIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span) { int items, i; char *mydata, *item_list[10]; - char *bd, *sp, *ch, *mx; + char *bd, *sp, *ch = NULL, *mx; int boardno; int channo; int spanno; @@ -978,7 +978,7 @@ static ZIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_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++) { if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) { diff --git a/libs/openzap/src/zap_zt.c b/libs/openzap/src/zap_zt.c index b2ee4c95b8..0513333e91 100644 --- a/libs/openzap/src/zap_zt.c +++ b/libs/openzap/src/zap_zt.c @@ -568,8 +568,8 @@ ZIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event) ZIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event) { - uint32_t i, event_id; - zap_oob_event_t zt_event_id; + uint32_t i, event_id = 0; + zap_oob_event_t zt_event_id = 0; for(i = 1; i <= span->chan_count; i++) { if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {