From 6b2f8b77cbe023602ed3b87e9e651b48c9429998 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 24 May 2007 21:57:03 +0000 Subject: [PATCH] state machine and echo test git-svn-id: http://svn.openzap.org/svn/openzap/trunk@148 a93c3328-9c30-0410-af19-c9cd2b2d52af --- libs/openzap/src/include/openzap.h | 20 ++- libs/openzap/src/include/zap_analog.h | 3 +- libs/openzap/src/include/zap_types.h | 25 +++- libs/openzap/src/testanalog.c | 55 +++++++- libs/openzap/src/zap_analog.c | 192 +++++++++++++++++++++----- libs/openzap/src/zap_io.c | 8 +- 6 files changed, 256 insertions(+), 47 deletions(-) diff --git a/libs/openzap/src/include/openzap.h b/libs/openzap/src/include/openzap.h index cb7e4178be..dca0bc3d06 100644 --- a/libs/openzap/src/include/openzap.h +++ b/libs/openzap/src/include/openzap.h @@ -131,6 +131,12 @@ #define XX if (0) +#ifdef WIN32 +#define zap_sleep(x) Sleep(x) +#else +#define zap_sleep(x) usleep(x * 1000) +#endif + #ifdef NDEBUG #undef assert #define assert(_Expression) ((void)(_Expression)) @@ -177,7 +183,10 @@ #define zap_clear_flag_locked(obj, flag) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); (obj)->flags &= ~(flag); zap_mutex_unlock(obj->mutex); -#define zap_set_state_locked(obj, s) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex); obj->state = s; zap_mutex_unlock(obj->mutex); +#define zap_set_state_locked(obj, s) assert(obj->mutex != NULL); zap_mutex_lock(obj->mutex);\ + zap_log(ZAP_LOG_DEBUG, "Changing state from %s to %s\n", zap_channel_state2str(obj->state), zap_channel_state2str(s));\ + zap_set_flag(obj, ZAP_CHANNEL_STATE_CHANGE);\ + obj->last_state = obj->state; obj->state = s; zap_mutex_unlock(obj->mutex); #define zap_is_dtmf(key) ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119) @@ -218,6 +227,7 @@ struct zap_channel { uint32_t native_interval; uint32_t packet_len; zap_channel_state_t state; + zap_channel_state_t last_state; zap_mutex_t *mutex; teletone_dtmf_detect_state_t dtmf_detect; zap_event_t event_header; @@ -239,10 +249,15 @@ struct zap_channel { struct zap_sigmsg { zap_signal_event_t event_id; uint32_t chan_id; + uint32_t span_id; + zap_channel_t *channel; + zap_span_t *span; char cid_name[80]; char ani[25]; char aniII[25]; char dnis[25]; + void *raw_data; + uint32_t raw_data_len; }; @@ -258,6 +273,9 @@ struct zap_isdn_data { struct zap_analog_data { uint32_t flags; + uint32_t max_dialstr; + uint32_t digit_timeout; + zio_signal_cb_t sig_cb; }; struct zap_span { diff --git a/libs/openzap/src/include/zap_analog.h b/libs/openzap/src/include/zap_analog.h index ff0919877d..82badfcea9 100644 --- a/libs/openzap/src/include/zap_analog.h +++ b/libs/openzap/src/include/zap_analog.h @@ -43,5 +43,6 @@ typedef enum { typedef struct zap_analog_data zap_analog_data_t; zap_status_t zap_analog_start(zap_span_t *span); -zap_status_t zap_analog_configure_span(zap_span_t *span, char *tonemap, zio_signal_cb_t sig_cb); +zap_status_t zap_analog_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb); + #endif diff --git a/libs/openzap/src/include/zap_types.h b/libs/openzap/src/include/zap_types.h index 9fafa28d65..41a45af4a7 100644 --- a/libs/openzap/src/include/zap_types.h +++ b/libs/openzap/src/include/zap_types.h @@ -94,15 +94,18 @@ typedef enum { } zap_signal_type_t; typedef enum { - ZAP_SIGEVENT_CALL_START, - ZAP_SIGEVENT_CALL_STOP, - ZAP_SIGEVENT_CALL_TRANSFER, + ZAP_SIGEVENT_START, + ZAP_SIGEVENT_STOP, + ZAP_SIGEVENT_TRANSFER, ZAP_SIGEVENT_ANSWER, ZAP_SIGEVENT_PROGRESS, ZAP_SIGEVENT_PROGRESS_MEDIA, ZAP_SIGEVENT_NOTIFY, - ZAP_SIGEVENT_MISC + ZAP_SIGEVENT_MISC, + ZAP_SIGEVENT_INVALID } zap_signal_event_t; +#define SIGNAL_STRINGS "START", "STOP", "TRANSFER", "ANSWER", "PROGRESS", "PROGRESS_MEDIA", "NOTIFY", "MISC", "INVALID" +ZAP_STR2ENUM_P(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t) typedef enum { ZAP_EVENT_NONE, @@ -185,8 +188,15 @@ typedef enum { ZAP_CHANNEL_STATE_DOWN, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_DIALTONE, - ZAP_CHANNEL_STATE_COLLECT + ZAP_CHANNEL_STATE_COLLECT, + ZAP_CHANNEL_STATE_RING, + ZAP_CHANNEL_STATE_BUSY, + ZAP_CHANNEL_STATE_ATTN, + ZAP_CHANNEL_STATE_IDLE, + ZAP_CHANNEL_STATE_INVALID } zap_channel_state_t; +#define CHANNEL_STATE_STRINGS "DOWN", "UP", "DIALTONE", "COLLECT", "RING", "BUSY", "ATTN", "IDLE", "INVALID" +ZAP_STR2ENUM_P(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t) typedef enum { ZAP_CHANNEL_CONFIGURED = (1 << 0), @@ -199,7 +209,8 @@ typedef enum { ZAP_CHANNEL_EVENT = (1 << 7), ZAP_CHANNEL_INTHREAD = (1 << 8), ZAP_CHANNEL_WINK = (1 << 9), - ZAP_CHANNEL_FLASH = (1 << 10) + ZAP_CHANNEL_FLASH = (1 << 10), + ZAP_CHANNEL_STATE_CHANGE = (1 << 11) } zap_channel_flag_t; @@ -210,7 +221,7 @@ typedef struct zap_span zap_span_t; #define ZIO_SPAN_POLL_EVENT_ARGS (zap_span_t *span, uint32_t ms) #define ZIO_SPAN_NEXT_EVENT_ARGS (zap_span_t *span, zap_event_t **event) -#define ZIO_SIGNAL_CB_ARGS (zap_span_t *span, zap_sigmsg_t *sigmsg, void *raw_data, uint32_t raw_data_len) +#define ZIO_SIGNAL_CB_ARGS (zap_sigmsg_t *sigmsg) #define ZIO_EVENT_CB_ARGS (zap_channel_t *zchan, zap_event_t *event) #define ZIO_CODEC_ARGS (void *data, zap_size_t max, zap_size_t *datalen) #define ZIO_CONFIGURE_ARGS (struct zap_io_interface *zio) diff --git a/libs/openzap/src/testanalog.c b/libs/openzap/src/testanalog.c index 0bec2444b1..c61cf5138a 100644 --- a/libs/openzap/src/testanalog.c +++ b/libs/openzap/src/testanalog.c @@ -1,9 +1,60 @@ #include "openzap.h" #include "zap_analog.h" + +static void *test_call(zap_thread_t *me, void *obj) +{ + zap_channel_t *chan = (zap_channel_t *) obj; + uint8_t frame[1024]; + zap_size_t len; + + + sleep(5); + + printf("answer call\n"); + + zap_set_state_locked(chan, ZAP_CHANNEL_STATE_UP); + + while (chan->state == ZAP_CHANNEL_STATE_UP) { + zap_wait_flag_t flags = ZAP_READ; + + if (zap_channel_wait(chan, &flags, -1) == ZAP_FAIL) { + break; + } + len = sizeof(frame); + if (flags & ZAP_READ) { + if (zap_channel_read(chan, frame, &len) == ZAP_SUCCESS) { + //printf("WRITE %d\n", len); + zap_channel_write(chan, frame, &len); + } else { + break; + } + } + } + + if (chan->state == ZAP_CHANNEL_STATE_UP) { + zap_set_state_locked(chan, ZAP_CHANNEL_STATE_BUSY); + } + + printf("call over\n"); + +} + static ZIO_SIGNAL_CB_FUNCTION(on_signal) { - return ZAP_FAIL; + printf("got sig [%s]\n", zap_signal_event2str(sigmsg->event_id)); + + switch(sigmsg->event_id) { + case ZAP_SIGEVENT_START: + zap_set_state_locked(sigmsg->channel, ZAP_CHANNEL_STATE_RING); + printf("launching thread and indicating ring\n"); + zap_thread_create_detached(test_call, sigmsg->channel); + break; + default: + break; + } + + return ZAP_SUCCESS; } int main(int argc, char *argv[]) @@ -24,7 +75,7 @@ int main(int argc, char *argv[]) } - zap_analog_configure_span(span, "us", on_signal); + zap_analog_configure_span(span, "us", 2000, 11, on_signal); zap_analog_start(span); while(zap_test_flag(span->analog_data, ZAP_ANALOG_RUNNING)) { diff --git a/libs/openzap/src/zap_analog.c b/libs/openzap/src/zap_analog.c index 0029430615..5a68aabd96 100644 --- a/libs/openzap/src/zap_analog.c +++ b/libs/openzap/src/zap_analog.c @@ -34,20 +34,34 @@ #include "openzap.h" #include "zap_analog.h" -zap_status_t zap_analog_configure_span(zap_span_t *span, char *tonemap, zio_signal_cb_t sig_cb) +zap_status_t zap_analog_configure_span(zap_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, zio_signal_cb_t sig_cb) { + assert(sig_cb != NULL); + if (span->signal_type) { snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling."); return ZAP_FAIL; } + if (digit_timeout < 2000 || digit_timeout > 10000) { + digit_timeout = 2000; + } + + if (max_dialstr < 2 || max_dialstr > 20) { + max_dialstr = 11; + } + span->analog_data = malloc(sizeof(*span->analog_data)); - assert(span->analog_data != NULL); memset(span->analog_data, 0, sizeof(*span->analog_data)); + assert(span->analog_data != NULL); + + span->analog_data->digit_timeout = digit_timeout; + span->analog_data->max_dialstr = max_dialstr; + span->analog_data->sig_cb = sig_cb; span->signal_type = ZAP_SIGTYPE_ANALOG; zap_span_load_tones(span, tonemap); - + return ZAP_SUCCESS; } @@ -73,17 +87,13 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) uint8_t frame[1024]; zap_size_t len, rlen; zap_codec_t codec = ZAP_CODEC_SLIN, old_codec; - char *tones[4] = {0}; - time_t start; - int isbz = 0; - int wtime = 10; zap_tone_type_t tt = ZAP_TONE_DTMF; - int play_tones = 1; - - - tones[0] = chan->span->tone_map[ZAP_TONEMAP_DIAL]; - tones[1] = chan->span->tone_map[ZAP_TONEMAP_BUSY]; - tones[2] = chan->span->tone_map[ZAP_TONEMAP_ATTN]; + char dtmf[128]; + int dtmf_offset = 0; + zap_analog_data_t *data = chan->span->analog_data; + zap_channel_t *closed_chan; + uint32_t state_counter = 0, elapsed = 0, interval = 0, last_digit = 0, indicate = 0; + zap_sigmsg_t sig; zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n"); @@ -100,7 +110,8 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) } zap_set_flag_locked(chan, ZAP_CHANNEL_INTHREAD); - zap_set_state_locked(chan, ZAP_CHANNEL_STATE_DIALTONE); + + teletone_init_session(&ts, 0, teletone_handler, dt_buffer); #if 0 @@ -108,40 +119,144 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) ts.debug_stream = stdout; #endif ts.rate = 8000; - teletone_run(&ts, tones[isbz++]); zap_channel_command(chan, ZAP_COMMAND_GET_CODEC, &old_codec); - zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &codec); + zap_channel_command(chan, ZAP_COMMAND_GET_INTERVAL, &interval); + zap_buffer_set_loops(dt_buffer, -1); - time(&start); - - while (chan->state >= ZAP_CHANNEL_STATE_DIALTONE && zap_test_flag(chan, ZAP_CHANNEL_INTHREAD)) { + while (zap_test_flag(chan, ZAP_CHANNEL_INTHREAD)) { zap_wait_flag_t flags = ZAP_READ; - char dtmf[128]; zap_size_t dlen = 0; len = sizeof(frame); + + elapsed += interval; + state_counter += interval; + XX printf("WTF %s %s\n", zap_channel_state2str(chan->state), zap_channel_state2str(chan->last_state)); + if (!zap_test_flag(chan, ZAP_CHANNEL_STATE_CHANGE)) { + switch(chan->state) { + case ZAP_CHANNEL_STATE_DIALTONE: + { + if (state_counter > 10000) { + zap_set_state_locked(chan, ZAP_CHANNEL_STATE_BUSY); + } + } + break; + case ZAP_CHANNEL_STATE_BUSY: + { + if (state_counter > 20000) { + zap_set_state_locked(chan, ZAP_CHANNEL_STATE_ATTN); + } + } + break; + case ZAP_CHANNEL_STATE_UP: + case ZAP_CHANNEL_STATE_IDLE: + { + zap_sleep(interval * 1000); + } + break; + default: + break; - if (play_tones && tones[isbz] && time(NULL) - start > wtime) { - zap_buffer_zero(dt_buffer); - teletone_run(&ts, tones[isbz++]); - time(&start); - wtime *= 2; + } + } else { + zap_clear_flag_locked(chan, ZAP_CHANNEL_STATE_CHANGE); + switch(chan->state) { + case ZAP_CHANNEL_STATE_UP: + { + zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &old_codec); + sig.event_id = ZAP_SIGEVENT_ANSWER; + 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); + } + break; + case ZAP_CHANNEL_STATE_DOWN: + { + sig.event_id = ZAP_SIGEVENT_STOP; + data->sig_cb(&sig); + goto done; + } + break; + case ZAP_CHANNEL_STATE_DIALTONE: + { + zap_buffer_zero(dt_buffer); + teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_DIAL]); + indicate = 1; + } + break; + + case ZAP_CHANNEL_STATE_RING: + { + zap_buffer_zero(dt_buffer); + teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_RING]); + indicate = 1; + } + break; + + case ZAP_CHANNEL_STATE_BUSY: + { + zap_buffer_zero(dt_buffer); + teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_BUSY]); + indicate = 1; + } + break; + + case ZAP_CHANNEL_STATE_ATTN: + { + zap_buffer_zero(dt_buffer); + teletone_run(&ts, chan->span->tone_map[ZAP_TONEMAP_ATTN]); + indicate = 1; + } + break; + default: + indicate = 0; + break; + } + + state_counter = 0; + } + + + if ((dlen = zap_channel_dequeue_dtmf(chan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) { + if (chan->state == ZAP_CHANNEL_STATE_DIALTONE || chan->state == ZAP_CHANNEL_STATE_COLLECT) { + zap_log(ZAP_LOG_DEBUG, "DTMF %s\n", dtmf + dtmf_offset); + if (chan->state == ZAP_CHANNEL_STATE_DIALTONE) { + zap_set_state_locked(chan, ZAP_CHANNEL_STATE_COLLECT); + } + dtmf_offset = strlen(dtmf); + last_digit = elapsed; + } } - if ((dlen = zap_channel_dequeue_dtmf(chan, dtmf, sizeof(dtmf)))) { - printf("DTMF %s\n", dtmf); - play_tones = 0; + if (last_digit && ((elapsed - last_digit > data->digit_timeout) || strlen(dtmf) > data->max_dialstr)) { + zap_log(ZAP_LOG_DEBUG, "Number obtained [%s]\n", dtmf); + zap_set_state_locked(chan, ZAP_CHANNEL_STATE_IDLE); + last_digit = 0; } - + if (zap_channel_wait(chan, &flags, -1) == ZAP_FAIL) { goto done; } - + if (flags & ZAP_READ) { if (zap_channel_read(chan, frame, &len) == ZAP_SUCCESS) { rlen = zap_buffer_read_loop(dt_buffer, frame, len); - if (play_tones) { + if (indicate) { + if (chan->effective_codec != codec) { + zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &codec); + } zap_channel_write(chan, frame, &rlen); } } else { @@ -151,7 +266,13 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) } done: - zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &old_codec); + + + closed_chan = chan; + zap_channel_close(&chan); + + zap_channel_command(closed_chan, ZAP_COMMAND_SET_CODEC, &old_codec); + if (ts.buffer) { teletone_destroy_session(&ts); } @@ -159,9 +280,9 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj) zap_buffer_destroy(&dt_buffer); } - zap_clear_flag(chan, ZAP_CHANNEL_INTHREAD); - zap_channel_close(&chan); - zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread ended. %d\n", old_codec); + zap_clear_flag(closed_chan, ZAP_CHANNEL_INTHREAD); + + zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread ended.\n"); return NULL; } @@ -178,6 +299,7 @@ static zap_status_t process_event(zap_span_t *span, zap_event_t *event) case ZAP_OOB_OFFHOOK: { if (!zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) { + zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DIALTONE); zap_thread_create_detached(zap_analog_channel_run, event->channel); } } diff --git a/libs/openzap/src/zap_io.c b/libs/openzap/src/zap_io.c index 71014be2bc..5f2ec84db2 100644 --- a/libs/openzap/src/zap_io.c +++ b/libs/openzap/src/zap_io.c @@ -86,6 +86,11 @@ ZAP_STR2ENUM(zap_str2zap_oob_event, zap_oob_event2str, zap_oob_event_t, OOB_NAME ZAP_ENUM_NAMES(TRUNK_TYPE_NAMES, TRUNK_STRINGS) ZAP_STR2ENUM(zap_str2zap_trunk_type, zap_trunk_type2str, zap_trunk_type_t, TRUNK_TYPE_NAMES, ZAP_TRUNK_NONE) +ZAP_ENUM_NAMES(SIGNAL_NAMES, SIGNAL_STRINGS) +ZAP_STR2ENUM(zap_str2zap_signal_event, zap_signal_event2str, zap_signal_event_t, SIGNAL_NAMES, ZAP_SIGEVENT_INVALID) + +ZAP_ENUM_NAMES(CHANNEL_STATE_NAMES, CHANNEL_STATE_STRINGS) +ZAP_STR2ENUM(zap_str2zap_channel_state, zap_channel_state2str, zap_channel_state_t, CHANNEL_STATE_NAMES, ZAP_CHANNEL_STATE_INVALID) static char *cut_path(char *in) { @@ -259,7 +264,7 @@ zap_status_t zap_span_load_tones(zap_span_t *span, char *mapname) if (index > ZAP_TONEMAP_INVALID) { zap_log(ZAP_LOG_WARNING, "Unknown tone name %s\n", var); } else { - zap_log(ZAP_LOG_DEBUG, "added tone [%s] = [%s] %d\n", var, val, index); + zap_log(ZAP_LOG_DEBUG, "added tone [%s] = [%s]\n", var, val); zap_copy_string(span->tone_map[index], val, sizeof(span->tone_map[index])); x++; } @@ -637,6 +642,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo { if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) { zchan->effective_codec = ZAP_COMMAND_OBJ_INT; + if (zchan->effective_codec == zchan->native_codec) { zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE); } else {