diff --git a/libs/openzap/mod_openzap/mod_openzap.c b/libs/openzap/mod_openzap/mod_openzap.c index 72060facba..19530cf755 100644 --- a/libs/openzap/mod_openzap/mod_openzap.c +++ b/libs/openzap/mod_openzap/mod_openzap.c @@ -52,7 +52,8 @@ typedef enum { TFLAG_OUTBOUND = (1 << 1), TFLAG_DTMF = (1 << 2), TFLAG_CODEC = (1 << 3), - TFLAG_BREAK = (1 << 4) + TFLAG_BREAK = (1 << 4), + TFLAG_HOLD = (1 << 5) } TFLAGS; static struct { @@ -76,6 +77,8 @@ struct private_object { switch_codec_t write_codec; switch_frame_t read_frame; unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + switch_frame_t cng_frame; + unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_core_session_t *session; switch_caller_profile_t *caller_profile; unsigned int codec; @@ -84,6 +87,7 @@ struct private_object { switch_mutex_t *mutex; switch_mutex_t *flag_mutex; zap_channel_t *zchan; + int32_t token_id; }; typedef struct private_object private_t; @@ -111,6 +115,9 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses tech_pvt->zchan = zchan; tech_pvt->read_frame.data = tech_pvt->databuf; tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf); + tech_pvt->cng_frame.data = tech_pvt->cng_databuf; + tech_pvt->cng_frame.buflen = sizeof(tech_pvt->cng_databuf); + 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)); switch_core_session_set_private(session, tech_pvt); @@ -241,7 +248,7 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session) tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - zap_channel_set_token(tech_pvt->zchan, NULL); + zap_channel_clear_token(tech_pvt->zchan, tech_pvt->token_id); switch (tech_pvt->zchan->type) { case ZAP_CHAN_TYPE_FXO: @@ -367,6 +374,17 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch assert(tech_pvt->zchan != NULL); + if (switch_test_flag(tech_pvt, TFLAG_HOLD)) { + switch_yield(tech_pvt->zchan->effective_interval * 1000); + *frame = &tech_pvt->cng_frame; + tech_pvt->cng_frame.datalen = tech_pvt->zchan->packet_len; + tech_pvt->cng_frame.samples = tech_pvt->cng_frame.datalen; + if (tech_pvt->zchan->effective_codec == ZAP_CODEC_SLIN) { + tech_pvt->cng_frame.samples /= 2; + } + return SWITCH_STATUS_SUCCESS; + } + if (!switch_test_flag(tech_pvt, TFLAG_IO)) { return SWITCH_STATUS_FALSE; } @@ -420,6 +438,10 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc assert(tech_pvt->zchan != NULL); + if (switch_test_flag(tech_pvt, TFLAG_HOLD)) { + return SWITCH_STATUS_SUCCESS; + } + if (!switch_test_flag(tech_pvt, TFLAG_IO)) { return SWITCH_STATUS_FALSE; } @@ -593,12 +615,26 @@ zap_status_t zap_channel_from_event(zap_sigmsg_t *sigmsg, switch_core_session_t return ZAP_FAIL; } - switch_copy_string(sigmsg->channel->token, switch_core_session_get_uuid(session), sizeof(sigmsg->channel->token)); + if ((tech_pvt->token_id = zap_channel_add_token(sigmsg->channel, switch_core_session_get_uuid(session))) < 0) { + switch_core_session_destroy(&session); + return ZAP_FAIL; + } *sp = session; return ZAP_SUCCESS; } +static switch_core_session_t *zap_channel_get_session(zap_channel_t *channel, int32_t id) +{ + switch_core_session_t *session = NULL; + + if (!switch_strlen_zero(channel->tokens[id])) { + session = switch_core_session_locate(channel->tokens[id]); + } + + return session; +} + static ZIO_SIGNAL_CB_FUNCTION(on_fxo_signal) { zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id)); @@ -609,18 +645,11 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal) { switch_core_session_t *session = NULL; switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; zap_status_t status; - int rwlock = 0; zap_log(ZAP_LOG_DEBUG, "got sig [%s]\n", zap_signal_event2str(sigmsg->event_id)); - if (!switch_strlen_zero(sigmsg->channel->token)) { - if ((session = switch_core_session_locate(sigmsg->channel->token))) { - channel = switch_core_session_get_channel(session); - rwlock++; - } - } - switch(sigmsg->event_id) { case ZAP_SIGEVENT_START: { @@ -632,16 +661,48 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxs_signal) break; case ZAP_SIGEVENT_STOP: { - if (channel) { + while((session = zap_channel_get_session(sigmsg->channel, 0))) { + zap_channel_clear_token(sigmsg->channel, 0); + channel = switch_core_session_get_channel(session); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); - zap_channel_set_token(sigmsg->channel, NULL); + switch_core_session_rwunlock(session); } } break; - } - if (session && rwlock) { - switch_core_session_rwunlock(session); + case ZAP_SIGEVENT_FLASH: + { + uint32_t i = 0; + for (i = 0; i < sigmsg->channel->token_count; i++) { + if ((session = zap_channel_get_session(sigmsg->channel, i))) { + tech_pvt = switch_core_session_get_private(session); + if (i) { + switch_set_flag_locked(tech_pvt, TFLAG_HOLD); + } else { + switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); + } + switch_core_session_rwunlock(session); + } + } + } + case ZAP_SIGEVENT_HOLD: + { + if ((session = zap_channel_get_session(sigmsg->channel, sigmsg->channel->token_count-1))) { + tech_pvt = switch_core_session_get_private(session); + switch_set_flag_locked(tech_pvt, TFLAG_HOLD); + switch_core_session_rwunlock(session); + } + } + break; + case ZAP_SIGEVENT_UNHOLD: + { + if ((session = zap_channel_get_session(sigmsg->channel, sigmsg->channel->token_count-1))) { + tech_pvt = switch_core_session_get_private(session); + switch_clear_flag_locked(tech_pvt, TFLAG_HOLD); + switch_core_session_rwunlock(session); + } + } + break; } return status; diff --git a/libs/openzap/src/include/openzap.h b/libs/openzap/src/include/openzap.h index a4e24f2394..3f47bc7a68 100644 --- a/libs/openzap/src/include/openzap.h +++ b/libs/openzap/src/include/openzap.h @@ -157,6 +157,7 @@ #define zap_channel_test_feature(obj, flag) ((obj)->features & flag) #define zap_channel_set_feature(obj, flag) (obj)->features |= (flag) #define zap_channel_clear_feature(obj, flag) (obj)->features &= ~(flag) +#define zap_channel_set_member_locked(obj, _m, _v) zap_mutex_lock(obj->mutex); obj->_m = _v; zap_mutex_unlock(obj->mutex) /*! \brief Test for the existance of a flag on an arbitary object @@ -218,6 +219,9 @@ struct zap_event { void *data; }; +#define ZAP_TOKEN_STRLEN 128 +#define ZAP_MAX_TOKENS 10 + struct zap_channel { uint32_t span_id; uint32_t chan_id; @@ -245,7 +249,8 @@ struct zap_channel { uint32_t dtmf_off; teletone_generation_session_t tone_session; zap_time_t last_event_time; - char token[128]; + char tokens[ZAP_MAX_TOKENS+1][ZAP_TOKEN_STRLEN]; + uint32_t token_count; char chan_name[128]; char chan_number[32]; struct zap_span *span; @@ -322,7 +327,9 @@ struct zap_io_interface { struct zap_span spans[ZAP_MAX_SPANS_INTERFACE]; }; -zap_status_t zap_channel_set_token(zap_channel_t *zchan, char *token); +void zap_channel_rotate_tokens(zap_channel_t *zchan); +zap_status_t zap_channel_clear_token(zap_channel_t *zchan, int32_t token_id); +zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token); zap_status_t zap_channel_set_state(zap_channel_t *zchan, zap_channel_state_t state); zap_status_t zap_span_load_tones(zap_span_t *span, char *mapname); zap_size_t zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len); diff --git a/libs/openzap/src/include/zap_types.h b/libs/openzap/src/include/zap_types.h index 236217278f..d1fcb9248d 100644 --- a/libs/openzap/src/include/zap_types.h +++ b/libs/openzap/src/include/zap_types.h @@ -101,13 +101,16 @@ typedef enum { ZAP_SIGEVENT_TRANSFER, ZAP_SIGEVENT_ANSWER, ZAP_SIGEVENT_UP, + ZAP_SIGEVENT_HOLD, + ZAP_SIGEVENT_UNHOLD, + ZAP_SIGEVENT_FLASH, ZAP_SIGEVENT_PROGRESS, ZAP_SIGEVENT_PROGRESS_MEDIA, ZAP_SIGEVENT_NOTIFY, ZAP_SIGEVENT_MISC, ZAP_SIGEVENT_INVALID } zap_signal_event_t; -#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "PROGRESS", "PROGRESS_MEDIA", "NOTIFY", "MISC", "INVALID" +#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "UP", "HOLD", "UNHOLD", "FLASH", "PROGRESS", "PROGRESS_MEDIA", "NOTIFY", "MISC", "INVALID" ZAP_STR2ENUM_P(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t) typedef enum { @@ -193,6 +196,7 @@ typedef enum { ZAP_CHANNEL_STATE_DOWN, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_HANGUP, + ZAP_CHANNEL_STATE_HOLD, ZAP_CHANNEL_STATE_DIALTONE, ZAP_CHANNEL_STATE_COLLECT, ZAP_CHANNEL_STATE_RING, @@ -201,7 +205,7 @@ typedef enum { ZAP_CHANNEL_STATE_IDLE, ZAP_CHANNEL_STATE_INVALID } zap_channel_state_t; -#define CHANNEL_STATE_STRINGS "DOWN", "UP", "HANGUP", "DIALTONE", "COLLECT", "RING", "BUSY", "ATTN", "IDLE", "INVALID" +#define CHANNEL_STATE_STRINGS "DOWN", "UP", "HANGUP", "HOLD", "DIALTONE", "COLLECT", "RING", "BUSY", "ATTN", "IDLE", "INVALID" ZAP_STR2ENUM_P(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t) typedef enum { @@ -216,7 +220,8 @@ typedef enum { ZAP_CHANNEL_INTHREAD = (1 << 8), ZAP_CHANNEL_WINK = (1 << 9), ZAP_CHANNEL_FLASH = (1 << 10), - ZAP_CHANNEL_STATE_CHANGE = (1 << 11) + ZAP_CHANNEL_STATE_CHANGE = (1 << 11), + ZAP_CHANNEL_HOLD = (1 << 12) } zap_channel_flag_t; diff --git a/libs/openzap/src/zap_analog.c b/libs/openzap/src/zap_analog.c index 3032e0200b..b6314dc339 100644 --- a/libs/openzap/src/zap_analog.c +++ b/libs/openzap/src/zap_analog.c @@ -87,7 +87,7 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) uint8_t frame[1024]; zap_size_t len, rlen; zap_tone_type_t tt = ZAP_TONE_DTMF; - char dtmf[128]; + char dtmf[128] = ""; zap_size_t dtmf_offset = 0; zap_analog_data_t *data = chan->span->analog_data; zap_channel_t *closed_chan; @@ -119,6 +119,12 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) zap_channel_command(chan, ZAP_COMMAND_GET_INTERVAL, &interval); zap_buffer_set_loops(dt_buffer, -1); + + memset(&sig, 0, sizeof(sig)); + sig.chan_id = chan->chan_id; + sig.span_id = chan->span_id; + sig.channel = chan; + sig.span = chan->span; while (zap_test_flag(chan, ZAP_CHANNEL_INTHREAD)) { zap_wait_flag_t flags = ZAP_READ; @@ -169,20 +175,18 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) switch(chan->state) { case ZAP_CHANNEL_STATE_UP: { - sig.event_id = ZAP_SIGEVENT_UP; + if (zap_test_flag(chan, ZAP_CHANNEL_HOLD)) { + sig.event_id = ZAP_SIGEVENT_UNHOLD; + } else { + sig.event_id = ZAP_SIGEVENT_UP; + } data->sig_cb(&sig); - continue; } break; case ZAP_CHANNEL_STATE_IDLE: { - memset(&sig, 0, sizeof(sig)); sig.event_id = ZAP_SIGEVENT_START; - sig.chan_id = chan->chan_id; - sig.span_id = chan->span_id; - sig.channel = chan; - sig.span = chan->span; zap_copy_string(sig.dnis, dtmf, sizeof(sig.dnis)); data->sig_cb(&sig); continue; @@ -195,8 +199,18 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) goto done; } break; + case ZAP_CHANNEL_STATE_HOLD: + { + sig.event_id = ZAP_SIGEVENT_HOLD; + data->sig_cb(&sig); + zap_set_flag_locked(chan, ZAP_CHANNEL_HOLD); + zap_set_state_locked(chan, ZAP_CHANNEL_STATE_DIALTONE); + } + break; case ZAP_CHANNEL_STATE_DIALTONE: { + *dtmf = '\0'; + dtmf_offset = 0; zap_buffer_zero(dt_buffer); teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_DIAL]); indicate = 1; @@ -245,8 +259,8 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) last_digit = 0; } - if (zap_channel_wait(chan, &flags, interval * 2) == ZAP_FAIL) { - goto done; + if (zap_channel_wait(chan, &flags, interval * 2) != ZAP_SUCCESS) { + continue; } if (!(flags & ZAP_READ)) { @@ -313,12 +327,41 @@ static zap_status_t process_event(zap_span_t *span, zap_event_t *event) { zap_log(ZAP_LOG_DEBUG, "EVENT [%s][%d:%d]\n", zap_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id); + zap_mutex_lock(event->channel->mutex); + + switch(event->enum_id) { case ZAP_OOB_ONHOOK: { zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN); } break; + case ZAP_OOB_FLASH: + { + zap_sigmsg_t sig; + zap_analog_data_t *data = event->channel->span->analog_data; + memset(&sig, 0, sizeof(sig)); + sig.chan_id = event->channel->chan_id; + sig.span_id = event->channel->span_id; + sig.channel = event->channel; + sig.span = event->channel->span; + + if (event->channel->state == ZAP_CHANNEL_STATE_UP) { + if (event->channel->token_count > 1) { + zap_channel_rotate_tokens(event->channel); + sig.event_id = ZAP_SIGEVENT_FLASH; + data->sig_cb(&sig); + } else { + if (zap_test_flag(event->channel, ZAP_CHANNEL_HOLD)) { + zap_clear_flag_locked(event->channel, ZAP_CHANNEL_HOLD); + zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_UP); + } else { + zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_HOLD); + } + } + } + } + break; case ZAP_OOB_OFFHOOK: { if (!zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) { @@ -328,7 +371,7 @@ static zap_status_t process_event(zap_span_t *span, zap_event_t *event) } } - + zap_mutex_unlock(event->channel->mutex); return ZAP_SUCCESS; } diff --git a/libs/openzap/src/zap_io.c b/libs/openzap/src/zap_io.c index 1c3da3c2c7..845cba7ef9 100644 --- a/libs/openzap/src/zap_io.c +++ b/libs/openzap/src/zap_io.c @@ -370,16 +370,54 @@ zap_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t return ZAP_SUCCESS; } -zap_status_t zap_channel_set_token(zap_channel_t *zchan, char *token) +zap_status_t zap_channel_clear_token(zap_channel_t *zchan, int32_t token_id) { + zap_status_t status = ZAP_FAIL; + zap_mutex_lock(zchan->mutex); - if (token) { - zap_copy_string(zchan->token, token, sizeof(zchan->token)); - } else { - *zchan->token = '\0'; + if (token_id == -1) { + memset(zchan->tokens, 0, sizeof(zchan->tokens)); + zchan->token_count = 0; + } else if (*zchan->tokens[token_id] != '\0') { + char tokens[ZAP_MAX_TOKENS][ZAP_TOKEN_STRLEN]; + int32_t i, count = zchan->token_count; + memcpy(tokens, zchan->tokens, sizeof(tokens)); + memset(zchan->tokens, 0, sizeof(zchan->tokens)); + zchan->token_count = 0; + + for (i = 0; i < count; i++) { + if (i != token_id) { + zap_copy_string(zchan->tokens[zchan->token_count], tokens[i], sizeof(zchan->tokens[zchan->token_count])); + zchan->token_count++; + } + } + + status = ZAP_SUCCESS; } zap_mutex_unlock(zchan->mutex); - return ZAP_SUCCESS; + + return status; +} + +void zap_channel_rotate_tokens(zap_channel_t *zchan) +{ + memmove(zchan->tokens[1], zchan->tokens[0], zchan->token_count * ZAP_TOKEN_STRLEN); + zap_copy_string(zchan->tokens[0], zchan->tokens[zchan->token_count], ZAP_TOKEN_STRLEN); + *zchan->tokens[zchan->token_count] = '\0'; +} + +zap_status_t zap_channel_add_token(zap_channel_t *zchan, char *token) +{ + zap_status_t status = ZAP_FAIL; + + zap_mutex_lock(zchan->mutex); + if (zchan->token_count < ZAP_MAX_TOKENS) { + zap_copy_string(zchan->tokens[zchan->token_count], token, sizeof(zchan->tokens[zchan->token_count])); + zchan->token_count++; + } + zap_mutex_unlock(zchan->mutex); + + return status; } @@ -523,6 +561,10 @@ static zap_status_t zap_channel_reset(zap_channel_t *zchan) zchan->event_callback = NULL; zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT); zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF); + zap_clear_flag_locked(zchan, ZAP_CHANNEL_HOLD); + memset(zchan->tokens, 0, sizeof(zchan->tokens)); + zchan->token_count = 0; + if (zchan->tone_session.buffer) { teletone_destroy_session(&zchan->tone_session); memset(&zchan->tone_session, 0, sizeof(zchan->tone_session)); @@ -605,6 +647,7 @@ zap_status_t zap_channel_close(zap_channel_t **zchan) assert(check != NULL); *zchan = NULL; + zap_mutex_lock(check->mutex); if (zap_test_flag(check, ZAP_CHANNEL_OPEN)) { status = check->zio->close(check);