]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add basics for analog (wip)
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 24 May 2007 03:42:40 +0000 (03:42 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 24 May 2007 03:42:40 +0000 (03:42 +0000)
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@130 a93c3328-9c30-0410-af19-c9cd2b2d52af

libs/openzap/src/Makefile
libs/openzap/src/include/openzap.h
libs/openzap/src/include/zap_analog.h [new file with mode: 0644]
libs/openzap/src/include/zap_types.h
libs/openzap/src/testanalog.c [new file with mode: 0644]
libs/openzap/src/zap_analog.c
libs/openzap/src/zap_io.c
libs/openzap/src/zap_wanpipe.c

index 8041ea3a7d6e5fb0bea34f4aaf4182ec68290821..8e9ba7b0939450f19dcd84ea247129bd8becd451 100644 (file)
@@ -73,6 +73,9 @@ testapp: testapp.c $(MYLIB)
 testisdn: testisdn.c $(MYLIB)
        $(CC) $(INCS) -L. testisdn.c -o testisdn -lopenzap -lm -lpthread
 
+testanalog: testanalog.c $(MYLIB)
+       $(CC) $(INCS) -L. testanalog.c -o testanalog -lopenzap -lm -lpthread
+
 priserver.o: priserver.c
        $(CC) $(INCS) $(TMP) -c priserver.c -o priserver.o 
 
@@ -95,5 +98,5 @@ zap_zt.o: zap_zt.c
        $(CC) $(CC_CFLAGS) $(CFLAGS) -c $< -o $@
 
 clean:
-       rm -f *.o isdn/*.o $(MYLIB) *~ \#* testapp priserver
+       rm -f *.o isdn/*.o $(MYLIB) *~ \#* testapp priserver testisdn testanalog
 
index 5a0f74fafae3fbbebd9a767dbebcfeb99ca1faba..8235d30846aa11361fedefb97ee3fe3f5784cc97 100644 (file)
 #pragma warning(disable:4706)
 #endif
 
+#ifndef WIN32
+#include <time.h>
+#include <sys/time.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -91,6 +96,8 @@
 #include "Q931.h"
 #include "Q921.h"
 
+#define XX if (0)
+
 #ifdef  NDEBUG
 #undef assert
 #define assert(_Expression)     ((void)(_Expression))
 */
 #define zap_set_flag(obj, flag) (obj)->flags |= (flag)
 
+#define zap_set_flag_locked(obj, flag) assert(obj->mutex != NULL);\
+zap_mutex_lock(obj->mutex);\
+(obj)->flags |= (flag);\
+zap_mutex_unlock(obj->mutex);
+
 /*!
   \brief Clear a flag on an arbitrary object while locked
   \command obj the object to test
 */
 #define zap_clear_flag(obj, flag) (obj)->flags &= ~(flag)
 
+#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_is_dtmf(key)  ((key > 47 && key < 58) || (key > 64 && key < 69) || (key > 96 && key < 101) || key == 35 || key == 42 || key == 87 || key == 119)
+
 /*!
   \brief Copy flags from one arbitrary object to another
   \command dest the object to copy the flags to
 
 struct zap_event {
        zap_event_type_t e_type;
+       uint32_t enum_id;
+       zap_channel_t *channel;
        void *data;
 };
 
@@ -172,6 +192,8 @@ struct zap_channel {
        uint32_t effective_interval;
        uint32_t native_interval;
        uint32_t packet_len;
+       zap_channel_state_t state;
+       zap_mutex_t *mutex;
        teletone_dtmf_detect_state_t dtmf_detect;
        zap_event_t event_header;
        char last_error[256];
@@ -179,9 +201,11 @@ struct zap_channel {
        void *mod_data;
        uint32_t skip_read_frames;
        zap_buffer_t *dtmf_buffer;
+       zap_buffer_t *digit_buffer;
        uint32_t dtmf_on;
        uint32_t dtmf_off;
        teletone_generation_session_t tone_session;
+       zap_time_t last_event_time;
        struct zap_span *span;
        struct zap_io_interface *zio;
 };
@@ -207,6 +231,10 @@ struct zap_isdn_data {
        uint32_t flags;
 };
 
+struct zap_analog_data {
+       uint32_t flags;
+};
+
 struct zap_span {
        uint32_t span_id;
        uint32_t chan_count;
@@ -217,6 +245,8 @@ struct zap_span {
        zap_trunk_type_t trunk_type;
        zap_signal_type_t signal_type;
        struct zap_isdn_data *isdn_data;
+       struct zap_analog_data *analog_data;
+       zap_event_t event_header;
        char last_error[256];
        zap_channel_t channels[ZAP_MAX_CHANNELS_SPAN];
 };
@@ -233,12 +263,21 @@ struct zap_io_interface {
        zio_wait_t wait;
        zio_read_t read;
        zio_write_t write;
+       zio_span_poll_event_t poll_event;
+       zio_span_next_event_t next_event;
        uint32_t span_index;
        struct zap_span spans[ZAP_MAX_SPANS_INTERFACE];
 };
 
+zap_size_t zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len);
+zap_status_t zap_channel_queue_dtmf(zap_channel_t *zchan, const char *dtmf);
+zap_time_t zap_current_time_in_ms(void);
+zap_oob_event_t str2zap_oob_signal(char *name);
+char *zap_oob_signal2str(zap_oob_event_t type);
 zap_trunk_type_t str2zap_trunk_type(char *name);
 char *zap_trunk_type2str(zap_trunk_type_t type);
+zap_status_t zap_span_poll_event(zap_span_t *span, uint32_t ms);
+zap_status_t zap_span_next_event(zap_span_t *span, zap_event_t **event);
 zap_status_t zap_span_find(const char *name, uint32_t id, zap_span_t **span);
 zap_status_t zap_span_create(zap_io_interface_t *zio, zap_span_t **span);
 zap_status_t zap_span_close_all(zap_io_interface_t *zio);
@@ -246,6 +285,7 @@ zap_status_t zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_cha
 zap_status_t zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_callback);
 zap_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback);
 zap_status_t zap_channel_open(const char *name, uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan);
+zap_status_t zap_channel_open_chan(zap_channel_t *zchan);
 zap_status_t zap_channel_open_any(const char *name, uint32_t span_id, zap_direction_t direction, zap_channel_t **zchan);
 zap_status_t zap_channel_close(zap_channel_t **zchan);
 zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj);
diff --git a/libs/openzap/src/include/zap_analog.h b/libs/openzap/src/include/zap_analog.h
new file mode 100644 (file)
index 0000000..8c12797
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2007, Anthony Minessale II
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ZAP_ANALOG_H
+#define ZAP_ANALOG_H
+#include "openzap.h"
+
+typedef enum {
+       ZAP_ANALOG_RUNNING = (1 << 0)
+} zap_analog_flag_t;
+
+
+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, zio_signal_cb_t sig_cb);
+
+#endif
index ee958c6bfb4412378f0e574376ae6c4468b43201..03d6ba851051a13d19557d6dd35c85c16621e266 100644 (file)
@@ -50,6 +50,8 @@ struct zap_io_interface;
 #define ZAP_COMMAND_OBJ_INT *((int *)obj)
 #define ZAP_COMMAND_OBJ_CHAR_P (char *)obj
 
+typedef uint64_t zap_time_t;
+
 typedef enum {
        ZAP_TRUNK_E1,
        ZAP_TRUNK_T1,
@@ -79,6 +81,7 @@ typedef enum {
 typedef enum {
        ZAP_EVENT_NONE,
        ZAP_EVENT_DTMF,
+       ZAP_EVENT_OOB,
        ZAP_EVENT_COUNT
 } zap_event_type_t;
 
@@ -143,7 +146,6 @@ typedef enum {
        ZAP_CHAN_TYPE_DQ931,
        ZAP_CHAN_TYPE_FXS,
        ZAP_CHAN_TYPE_FXO,
-
        ZAP_CHAN_TYPE_COUNT
 } zap_chan_type_t;
 
@@ -153,6 +155,13 @@ typedef enum {
        ZAP_CHANNEL_FEATURE_INTERVAL = (1 << 2)
 } zap_channel_feature_t;
 
+typedef enum {
+       ZAP_CHANNEL_STATE_DOWN,
+       ZAP_CHANNEL_STATE_UP,
+       ZAP_CHANNEL_STATE_DIALTONE,
+       ZAP_CHANNEL_STATE_COLLECT
+} zap_channel_state_t;
+
 typedef enum {
        ZAP_CHANNEL_CONFIGURED = (1 << 0),
        ZAP_CHANNEL_READY = (1 << 1),
@@ -160,14 +169,31 @@ typedef enum {
        ZAP_CHANNEL_DTMF_DETECT = (1 << 3),
        ZAP_CHANNEL_SUPRESS_DTMF = (1 << 4),
        ZAP_CHANNEL_TRANSCODE = (1 << 5),
-       ZAP_CHANNEL_BUFFER = (1 << 6)
+       ZAP_CHANNEL_BUFFER = (1 << 6),
+       ZAP_CHANNEL_EVENT = (1 << 7),
+       ZAP_CHANNEL_INTHREAD = (1 << 8),
+       ZAP_CHANNEL_WINK = (1 << 9),
+       ZAP_CHANNEL_FLASH = (1 << 10)
 } zap_channel_flag_t;
 
+typedef enum {
+       ZAP_OOB_DTMF,
+       ZAP_OOB_ONHOOK,
+       ZAP_OOB_OFFHOOK,
+       ZAP_OOB_WINK,
+       ZAP_OOB_FLASH,
+       ZAP_OOB_RING_START,
+       ZAP_OOB_RING_STOP,
+       ZAP_OOB_INVALID
+} zap_oob_event_t;
+
 typedef struct zap_channel zap_channel_t;
 typedef struct zap_event zap_event_t;
 typedef struct zap_sigmsg zap_sigmsg_t;
 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_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)
@@ -179,6 +205,8 @@ typedef struct zap_span zap_span_t;
 #define ZIO_READ_ARGS (zap_channel_t *zchan, void *data, zap_size_t *datalen)
 #define ZIO_WRITE_ARGS (zap_channel_t *zchan, void *data, zap_size_t *datalen)
 
+typedef zap_status_t (*zio_span_poll_event_t) ZIO_SPAN_POLL_EVENT_ARGS ;
+typedef zap_status_t (*zio_span_next_event_t) ZIO_SPAN_NEXT_EVENT_ARGS ;
 typedef zap_status_t (*zio_signal_cb_t) ZIO_SIGNAL_CB_ARGS ;
 typedef zap_status_t (*zio_event_cb_t) ZIO_EVENT_CB_ARGS ;
 typedef zap_status_t (*zio_codec_t) ZIO_CODEC_ARGS ;
@@ -190,6 +218,8 @@ typedef zap_status_t (*zio_wait_t) ZIO_WAIT_ARGS ;
 typedef zap_status_t (*zio_read_t) ZIO_READ_ARGS ;
 typedef zap_status_t (*zio_write_t) ZIO_WRITE_ARGS ;
 
+#define ZIO_SPAN_POLL_EVENT_FUNCTION(name) zap_status_t name ZIO_SPAN_POLL_EVENT_ARGS
+#define ZIO_SPAN_NEXT_EVENT_FUNCTION(name) zap_status_t name ZIO_SPAN_NEXT_EVENT_ARGS
 #define ZIO_SIGNAL_CB_FUNCTION(name) zap_status_t name ZIO_SIGNAL_CB_ARGS
 #define ZIO_EVENT_CB_FUNCTION(name) zap_status_t name ZIO_EVENT_CB_ARGS
 #define ZIO_CODEC_FUNCTION(name) zap_status_t name ZIO_CODEC_ARGS
diff --git a/libs/openzap/src/testanalog.c b/libs/openzap/src/testanalog.c
new file mode 100644 (file)
index 0000000..7254bf4
--- /dev/null
@@ -0,0 +1,36 @@
+#include "openzap.h"
+#include "zap_analog.h"
+
+static ZIO_SIGNAL_CB_FUNCTION(on_signal)
+{
+       return ZAP_FAIL;
+}
+
+int main(int argc, char *argv[])
+{
+       zap_span_t *span;
+
+       zap_global_set_default_logger(ZAP_LOG_LEVEL_DEBUG);
+
+       if (zap_global_init() != ZAP_SUCCESS) {
+               fprintf(stderr, "Error loading OpenZAP\n");
+               exit(-1);
+       }
+
+       printf("OpenZAP loaded\n");
+
+       if (zap_span_find("wanpipe", 1, &span) != ZAP_SUCCESS) {
+               fprintf(stderr, "Error finding OpenZAP span\n");
+       }
+       
+       
+       zap_analog_configure_span(span, on_signal);
+       zap_analog_start(span);
+
+       while(zap_test_flag(span->analog_data, ZAP_ANALOG_RUNNING)) {
+               sleep(1);
+       }
+
+       zap_global_destroy();
+
+}
index dabea87c4e0d097346b04ef0b9d0deeb217796ad..c9e93bdb83acc65d6498ff93a1ff3ee2ed179276 100644 (file)
  */
 
 #include "openzap.h"
+#include "zap_analog.h"
+
+zap_status_t zap_analog_configure_span(zap_span_t *span, zio_signal_cb_t sig_cb)
+{
+       if (span->signal_type) {
+               snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
+               return ZAP_FAIL;
+       }
+
+       span->analog_data = malloc(sizeof(*span->analog_data));
+       assert(span->analog_data != NULL);
+       memset(span->analog_data, 0, sizeof(*span->analog_data));
+       span->signal_type = ZAP_SIGTYPE_ANALOG;
+       
+       return ZAP_SUCCESS;
+
+}
+
+static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
+{
+       zap_buffer_t *dt_buffer = ts->user_data;
+       int wrote;
+
+       if (!dt_buffer) {
+               return -1;
+       }
+       wrote = teletone_mux_tones(ts, map);
+       zap_buffer_write(dt_buffer, ts->buffer, wrote * 2);
+       printf("add %d\n", wrote * 2);
+       return 0;
+}
+
+static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
+{
+       zap_channel_t *chan = (zap_channel_t *) obj;
+       zap_buffer_t *dt_buffer = NULL;
+       teletone_generation_session_t ts;
+       uint8_t frame[1024];
+       zap_size_t len, rlen;
+       zap_codec_t codec = ZAP_CODEC_SLIN, old_codec;
+       char *tones[] = { "%(1000,0,350,440)",
+                                         "%(500,500,480,620)",
+                                         "v=2000;%(100,100,1400,2060,2450,2600)",
+                                         NULL };
+       
+       time_t start;
+       int isbz = 0;
+       int wtime = 10;
+       zap_tone_type_t tt = ZAP_TONE_DTMF;
+       int play_tones = 1;
+       
+       zap_log(ZAP_LOG_DEBUG, "ANALOG CHANNEL thread starting.\n");
+
+       if (zap_channel_open_chan(chan) != ZAP_SUCCESS) {
+               goto done;
+       }
+
+       if (zap_buffer_create(&dt_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
+               goto done;
+       }
+
+       if (zap_channel_command(chan, ZAP_COMMAND_ENABLE_TONE_DETECT, &tt) != ZAP_SUCCESS) {
+               goto done;
+       }
+       /*zap_channel_set_event_callback(chan, my_zap_event_handler);*/
+
+
+       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);
+       ts.rate = 8000;
+       ts.debug = 1;
+       ts.debug_stream = stdout;
+       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_buffer_set_loops(dt_buffer, -1);
+
+       time(&start);
+
+
+
+       while (chan->state >= ZAP_CHANNEL_STATE_DIALTONE && 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);
+
+               if (play_tones && tones[isbz] && time(NULL) - start > wtime) {
+                       zap_buffer_zero(dt_buffer);
+                       teletone_run(&ts, tones[isbz++]);
+                       time(&start);
+                       wtime *= 2;
+               }
+
+               if ((dlen = zap_channel_dequeue_dtmf(chan, dtmf, sizeof(dtmf)))) {
+                       printf("DTMF %s\n", dtmf);
+                       play_tones = 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) {
+                                       zap_channel_write(chan, frame, &rlen);
+                               }
+                       } else {
+                               goto done;
+                       }
+               }
+       }
+       
+ done:
+       zap_channel_command(chan, ZAP_COMMAND_SET_CODEC, &old_codec);
+       if (ts.buffer) {
+               teletone_destroy_session(&ts);
+       }
+       if (dt_buffer) {
+               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);
+       return NULL;
+}
+
+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_signal2str(event->enum_id), event->channel->span_id, event->channel->chan_id);
+
+       switch(event->enum_id) {
+       case ZAP_OOB_ONHOOK:
+               {
+                       zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
+               }
+               break;
+       case ZAP_OOB_OFFHOOK:
+               {
+                       if (!zap_test_flag(event->channel, ZAP_CHANNEL_INTHREAD)) {
+                               zap_thread_create_detached(zap_analog_channel_run, event->channel);
+                       }
+               }
+       }
+
+
+       return ZAP_SUCCESS;
+}
+
+static void *zap_analog_run(zap_thread_t *me, void *obj)
+{
+       zap_span_t *span = (zap_span_t *) obj;
+       zap_analog_data_t *data = span->analog_data;
+
+       zap_log(ZAP_LOG_DEBUG, "ANALOG thread starting.\n");
+
+       while(zap_test_flag(data, ZAP_ANALOG_RUNNING)) {
+               int waitms = 10;
+               zap_status_t status;
+
+               status = zap_span_poll_event(span, waitms);
+               
+               switch(status) {
+               case ZAP_TIMEOUT:
+               case ZAP_SUCCESS:
+                       {
+                               zap_event_t *event;
+                               while (zap_span_next_event(span, &event) == ZAP_SUCCESS) {
+                                       if (process_event(span, event) != ZAP_SUCCESS) {
+                                               goto end;
+                                       }
+                               }
+                       }
+                       break;
+               case ZAP_FAIL:
+                       {
+                               zap_log(ZAP_LOG_DEBUG, "Failure!\n");
+                               goto end;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+       }
+
+ end:
+
+       zap_clear_flag(data, ZAP_ANALOG_RUNNING);
+       
+       zap_log(ZAP_LOG_DEBUG, "ANALOG thread ending.\n");
+
+       return NULL;
+}
+
+
+
+zap_status_t zap_analog_start(zap_span_t *span)
+{
+       zap_set_flag(span->analog_data, ZAP_ANALOG_RUNNING);
+       return zap_thread_create_detached(zap_analog_run, span);
+}
+
index f4dbeeeade0095471014fb86b75399a146c29674..f0ca7dd395b8ac74e00b7dccd148472a932e0d86 100644 (file)
 #include "zap_zt.h"
 #endif
 
+static int time_is_init = 0;
+
+static void time_init(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+       timeBeginPeriod(1);
+#endif
+       time_is_init = 1;
+}
+
+static void time_end(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+       timeEndPeriod(1);
+#endif
+       time_is_init = 0;
+}
+
+zap_time_t zap_current_time_in_ms(void)
+{
+#ifdef WIN32_TIME_GET_TIME
+       return timeGetTime();
+#else
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+       return ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
+#endif
+}
+
 static struct {
        zap_hash_t *interface_hash;
        zap_mutex_t *mutex;
@@ -56,6 +85,41 @@ static char *TRUNK_TYPE_NAMES[] = {
        NULL
 };
 
+static char *OOB_NAMES[] = {
+       "ZAP_OOB_DTMF",
+       "ZAP_OOB_ONHOOK",
+       "ZAP_OOB_OFFHOOK",
+       "WINK",
+       "FLASH",
+       "ZAP_OOB_RING_START",
+       "ZAP_OOB_RING_STOP",
+       "INVALID",
+       NULL
+};
+
+zap_oob_event_t str2zap_oob_signal(char *name)
+{
+       int i;
+       zap_trunk_type_t t = ZAP_OOB_INVALID;
+
+       for (i = 0; i < ZAP_OOB_INVALID; i++) {
+               if (!strcasecmp(name, OOB_NAMES[i])) {
+                       t = (zap_oob_event_t) i;
+                       break;
+               }
+       }
+
+       return t;
+}
+
+char *zap_oob_signal2str(zap_oob_event_t type)
+{
+       if (type > ZAP_OOB_INVALID) {
+               type = ZAP_OOB_INVALID;
+       }
+       return OOB_NAMES[(int)type];
+}
+
 static char *LEVEL_NAMES[] = {
        "EMERG",
        "ALERT",
@@ -206,16 +270,26 @@ zap_status_t zap_span_create(zap_io_interface_t *zio, zap_span_t **span)
 zap_status_t zap_span_close_all(zap_io_interface_t *zio)
 {
        zap_span_t *span;
-       uint32_t i;
+       uint32_t i, j;
 
        for(i = 0; i < zio->span_index; i++) {
                span = &zio->spans[i];
+
+               for(j = 0; j < span->chan_count; j++) {
+                       zap_mutex_destroy(&span->channels[j].mutex);
+                       zap_buffer_destroy(&span->channels[j].digit_buffer);
+                       zap_buffer_destroy(&span->channels[j].dtmf_buffer);
+               }
+
                if (span->mutex) {
                        zap_mutex_destroy(&span->mutex);
                }
                if (span->isdn_data) {
                        free(span->isdn_data);
                }
+               if (span->analog_data) {
+                       free(span->isdn_data);
+               }
        }
        
        return i ? ZAP_SUCCESS : ZAP_FAIL;
@@ -232,6 +306,8 @@ zap_status_t zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_cha
                new_chan->span_id = span->span_id;
                new_chan->chan_id = span->chan_count;
                new_chan->span = span;
+               zap_mutex_create(&new_chan->mutex);
+               zap_buffer_create(&new_chan->digit_buffer, 128, 128, 0);
                zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY);
                *chan = new_chan;
                return ZAP_SUCCESS;
@@ -277,6 +353,29 @@ zap_status_t zap_span_set_event_callback(zap_span_t *span, zio_event_cb_t event_
        return ZAP_SUCCESS;
 }
 
+
+zap_status_t zap_span_poll_event(zap_span_t *span, uint32_t ms)
+{
+       assert(span->zio != NULL);
+
+       if (span->zio->poll_event) {
+               return span->zio->poll_event(span, ms);
+       }
+
+       return ZAP_NOTIMPL;
+}
+
+zap_status_t zap_span_next_event(zap_span_t *span, zap_event_t **event)
+{
+       assert(span->zio != NULL);
+
+       if (span->zio->next_event) {
+               return span->zio->next_event(span, event);
+       }
+
+       return ZAP_NOTIMPL;
+}
+
 zap_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback)
 {
        zap_mutex_lock(zchan->span->mutex);
@@ -397,9 +496,15 @@ static zap_status_t zap_channel_reset(zap_channel_t *zchan)
                teletone_destroy_session(&zchan->tone_session);
                memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
        }
+
        if (zchan->dtmf_buffer) {
-               zap_buffer_destroy(&zchan->dtmf_buffer);
+               zap_buffer_zero(zchan->dtmf_buffer);
        }
+
+       if (zchan->digit_buffer) {
+               zap_buffer_zero(zchan->digit_buffer);
+       }
+
        zchan->dtmf_on = zchan->dtmf_off = 0;
 
        if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE)) {
@@ -411,7 +516,21 @@ static zap_status_t zap_channel_reset(zap_channel_t *zchan)
        return ZAP_SUCCESS;
 }
 
+zap_status_t zap_channel_open_chan(zap_channel_t *zchan)
+{
+       zap_status_t status;
 
+       zap_mutex_lock(zchan->span->mutex);
+       if (zap_test_flag(zchan, ZAP_CHANNEL_READY) && ! zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
+               status = zchan->span->zio->open(zchan);
+               if (status == ZAP_SUCCESS) {
+                       zap_set_flag(zchan, ZAP_CHANNEL_OPEN);
+               }
+       }
+       zap_mutex_unlock(zchan->span->mutex);
+
+       return status;
+}
 
 zap_status_t zap_channel_open(const char *name, uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan)
 {
@@ -824,6 +943,56 @@ ZIO_CODEC_FUNCTION(zio_alaw2ulaw)
 
 /******************************/
 
+zap_size_t zap_channel_dequeue_dtmf(zap_channel_t *zchan, char *dtmf, zap_size_t len)
+{
+       zap_size_t bytes;
+
+       assert(zchan != NULL);
+
+       zap_mutex_lock(zchan->mutex);
+       if ((bytes = zap_buffer_read(zchan->digit_buffer, dtmf, len)) > 0) {
+               *(dtmf + bytes) = '\0';
+       }
+       zap_mutex_unlock(zchan->mutex);
+
+       return bytes;
+}
+
+
+zap_status_t zap_channel_queue_dtmf(zap_channel_t *zchan, const char *dtmf)
+{
+       zap_status_t status;
+       register zap_size_t len, inuse;
+       zap_size_t wr = 0;
+       const char *p;
+       
+       assert(zchan != NULL);
+
+       zap_mutex_lock(zchan->mutex);
+
+       inuse = zap_buffer_inuse(zchan->digit_buffer);
+       len = strlen(dtmf);
+       
+       if (len + inuse > zap_buffer_len(zchan->digit_buffer)) {
+               zap_buffer_toss(zchan->digit_buffer, strlen(dtmf));
+       }
+
+       p = dtmf;
+       while (wr < len && p) {
+               if (zap_is_dtmf(*p)) {
+                       wr++;
+               } else {
+                       break;
+               }
+               p++;
+       }
+
+       status = zap_buffer_write(zchan->digit_buffer, dtmf, wr) ? ZAP_SUCCESS : ZAP_FAIL;
+       zap_mutex_unlock(zchan->mutex);
+       
+       return status;
+}
+
 zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen)
 {
        zap_status_t status = ZAP_FAIL;
@@ -895,11 +1064,15 @@ zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *data
 
                        sln = sln_buf;
                }
-
+               XX printf("WTF %d\n", (int) slen);
                teletone_dtmf_detect(&zchan->dtmf_detect, sln, (int)slen);
                teletone_dtmf_get(&zchan->dtmf_detect, digit_str, sizeof(digit_str));
-               if(digit_str[0]) {
+
+               if(*digit_str) {
                        zio_event_cb_t event_callback = NULL;
+
+                       zap_channel_queue_dtmf(zchan, digit_str);
+
                        if (zchan->span->event_callback) {
                                event_callback = zchan->span->event_callback;
                        } else if (zchan->event_callback) {
@@ -907,6 +1080,7 @@ zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *data
                        }
 
                        if (event_callback) {
+                               zchan->event_header.channel = zchan;
                                zchan->event_header.e_type = ZAP_EVENT_DTMF;
                                zchan->event_header.data = digit_str;
                                event_callback(zchan, &zchan->event_header);
@@ -1012,6 +1186,7 @@ zap_status_t zap_global_init(void)
        uint32_t configured = 0;
        int modcount;
 
+       time_init();
        zap_isdn_init();
        
        memset(&interfaces, 0, sizeof(interfaces));
@@ -1047,6 +1222,7 @@ zap_status_t zap_global_init(void)
        }
 
        if (!zap_config_open_file(&cfg, "openzap.conf")) {
+               zap_log(ZAP_LOG_ERROR, "Cannot open openzap.conf!\n");  
                return ZAP_FAIL;
        }
        
@@ -1082,6 +1258,8 @@ zap_status_t zap_global_init(void)
 
 zap_status_t zap_global_destroy(void)
 {
+       time_end();
+
 #ifdef ZAP_ZT_SUPPORT
        if (interfaces.zt_interface) {
                zt_destroy();
index 04dc44d50760b2733d32921ed555876d8737b529..9eab6fcc4234ea7f3ab2c8e10784350f3aa7f762 100644 (file)
@@ -39,7 +39,9 @@
 #include <sangoma_tdm_api.h>
 
 static struct {
-       unsigned codec_ms;
+       uint32_t codec_ms;
+       uint32_t wink_ms;
+       uint32_t flash_ms;
 } wp_globals;
 
 static zap_io_interface_t wanpipe_interface;
@@ -70,6 +72,25 @@ static unsigned wp_open_range(zap_span_t *span, unsigned spanno, unsigned start,
                
                if (sockfd != WP_INVALID_SOCKET && zap_span_add_channel(span, sockfd, type, &chan) == ZAP_SUCCESS) {
                        zap_log(ZAP_LOG_INFO, "configuring device s%dc%d as OpenZAP device %d:%d fd:%d\n", spanno, x, chan->span_id, chan->chan_id, sockfd);
+                       if (type == ZAP_CHAN_TYPE_FXS || type == ZAP_CHAN_TYPE_FXO) {
+                               wanpipe_tdm_api_t tdm_api;
+
+                               tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_ENABLE_RXHOOK_EVENTS;
+                               wp_tdm_cmd_exec(chan, &tdm_api);
+
+                               if (type == ZAP_CHAN_TYPE_FXS) {
+                                       tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_ENABLE_RING_DETECT_EVENTS;
+                                       wp_tdm_cmd_exec(chan, &tdm_api);
+                               }
+
+                               tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_HW_CODING;
+                               wp_tdm_cmd_exec(chan, &tdm_api);
+                               if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
+                                       chan->native_codec = chan->effective_codec = ZAP_CODEC_ALAW;
+                               } else {
+                                       chan->native_codec = chan->effective_codec = ZAP_CODEC_ULAW;
+                               }
+                       }
                        configured++;
                } else {
                        zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
@@ -206,6 +227,10 @@ static ZIO_CONFIGURE_FUNCTION(wanpipe_configure)
                        } else if (!strcasecmp(var, "trunk_type")) {
                                span->trunk_type = str2zap_trunk_type(val);
                                zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s'\n", zap_trunk_type2str(span->trunk_type)); 
+                       } else if (!strcasecmp(var, "fxo-channel")) {
+                               configured += wp_configure_channel(&cfg, val, span, ZAP_CHAN_TYPE_FXO);
+                       } else if (!strcasecmp(var, "fxs-channel")) {
+                               configured += wp_configure_channel(&cfg, val, span, ZAP_CHAN_TYPE_FXS);
                        } else if (!strcasecmp(var, "b-channel")) {
                                configured += wp_configure_channel(&cfg, val, span, ZAP_CHAN_TYPE_B);
                        } else if (!strcasecmp(var, "d-channel")) {
@@ -250,13 +275,8 @@ static ZIO_OPEN_FUNCTION(wanpipe_open)
                zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
                zchan->effective_interval = zchan->native_interval = wp_globals.codec_ms;
                zchan->packet_len = zchan->native_interval * 8;
-               
-               tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_GET_HW_CODING;
-               if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
-                       zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ULAW;
-               } else {
-                       zchan->native_codec = zchan->effective_codec = ZAP_CODEC_ALAW;
-               }
+               zchan->native_codec = zchan->effective_codec;
+
        }
 
        return ZAP_SUCCESS;
@@ -392,12 +412,140 @@ static ZIO_WAIT_FUNCTION(wanpipe_wait)
        return ZAP_SUCCESS;
 }
 
+ZIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
+{
+       struct pollfd pfds[ZAP_MAX_CHANNELS_SPAN];
+       int i, j = 0, k = 0, r;
+       
+       for(i = 1; i <= span->chan_count; i++) {
+               memset(&pfds[j], 0, sizeof(pfds[j]));
+               pfds[j].fd = span->channels[i].sockfd;
+               pfds[j].events = POLLPRI;
+               //printf("set %d=%d\n", j, pfds[j].fd);
+               j++;
+       }
+
+    r = poll(pfds, j, ms);
+       
+       if (r == 0) {
+               return ZAP_TIMEOUT;
+       } else if (r < 0) {
+               snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+               return ZAP_FAIL;
+       }
+       
+       for(i = 1; i <= span->chan_count; i++) {
+               if (pfds[i-1].revents & POLLPRI) {
+                       zap_set_flag((&span->channels[i]), ZAP_CHANNEL_EVENT);
+                       span->channels[i].last_event_time = zap_current_time_in_ms();
+                       k++;
+               }
+       }
+       
+       return k ? ZAP_SUCCESS : ZAP_FAIL;
+}
+
+ZIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
+{
+       int i;
+       zap_oob_event_t event_id;
+       
+       for(i = 1; i <= span->chan_count; i++) {
+               if (span->channels[i].last_event_time && !zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {
+                       uint32_t diff = zap_current_time_in_ms() - span->channels[i].last_event_time;
+                       XX printf("%u %u %u\n", diff, (unsigned)zap_current_time_in_ms(), (unsigned)span->channels[i].last_event_time);
+                       if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_WINK)) {
+                               if (diff > wp_globals.wink_ms) {
+                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
+                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
+                                       event_id = ZAP_OOB_OFFHOOK;
+                                       goto event;
+                               }
+                       }
+
+                       if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_FLASH)) {
+                               if (diff > wp_globals.flash_ms) {
+                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
+                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
+                                       event_id = ZAP_OOB_ONHOOK;
+                                       goto event;
+                               }
+                       }
+               }
+               if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {
+                       wanpipe_tdm_api_t tdm_api;
+                       zap_clear_flag((&span->channels[i]), ZAP_CHANNEL_EVENT);
+
+                       tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_READ_EVENT;
+                       if (wp_tdm_cmd_exec(&span->channels[i], &tdm_api) != ZAP_SUCCESS) {
+                               snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
+                               return ZAP_FAIL;
+                       }
+                       
+                       switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
+                       case WP_TDM_EVENT_RXHOOK:
+                               {
+                                       event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rxhook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? ZAP_OOB_OFFHOOK : ZAP_OOB_ONHOOK;
+                                       
+                                       if (event_id == ZAP_OOB_OFFHOOK) {
+                                               if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_FLASH)) {
+                                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
+                                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
+                                                       event_id = ZAP_OOB_FLASH;
+                                                       goto event;
+                                               } else {
+                                                       zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
+                                               }
+                                       } else {
+                                               if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_WINK)) {
+                                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_WINK);
+                                                       zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
+                                                       event_id = ZAP_OOB_WINK;
+                                                       goto event;
+                                               } else {
+                                                       zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_FLASH);
+                                               }
+                                       }
+                                       continue;
+                               }
+                               break;
+                       case WP_TDM_EVENT_RING_DETECT:
+                               {
+                                       event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state & WP_TDMAPI_EVENT_RING_PRESENT ? ZAP_OOB_RING_START : ZAP_OOB_RING_STOP;
+                                       tdm_api.wp_tdm_cmd.cmd = SIOC_WP_TDM_DISABLE_RING_DETECT_EVENTS;
+                                       wp_tdm_cmd_exec(&span->channels[i], &tdm_api);
+                               }
+                               break;
+                       default:
+                               {
+                                       zap_log(ZAP_LOG_WARNING, "Unhandled event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
+                                       event_id = ZAP_OOB_INVALID;
+                               }
+                               break;
+                       }
+
+               event:
+                       span->channels[i].last_event_time = 0;
+                       span->event_header.e_type = ZAP_EVENT_OOB;
+                       span->event_header.enum_id = event_id;
+                       span->event_header.channel = &span->channels[i];
+                       *event = &span->event_header;
+                       return ZAP_SUCCESS;
+               }
+       }
+
+       return ZAP_FAIL;
+       
+}
+
 zap_status_t wanpipe_init(zap_io_interface_t **zio)
 {
        assert(zio != NULL);
        memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
 
        wp_globals.codec_ms = 20;
+       wp_globals.wink_ms = 150;
+       wp_globals.flash_ms = 750;
        wanpipe_interface.name = "wanpipe";
        wanpipe_interface.configure =  wanpipe_configure;
        wanpipe_interface.open = wanpipe_open;
@@ -406,6 +554,8 @@ zap_status_t wanpipe_init(zap_io_interface_t **zio)
        wanpipe_interface.wait = wanpipe_wait;
        wanpipe_interface.read = wanpipe_read;
        wanpipe_interface.write = wanpipe_write;
+       wanpipe_interface.poll_event = wanpipe_poll_event;
+       wanpipe_interface.next_event = wanpipe_next_event;
        *zio = &wanpipe_interface;
 
        return ZAP_SUCCESS;