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
$(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
#pragma warning(disable:4706)
#endif
+#ifndef WIN32
+#include <time.h>
+#include <sys/time.h>
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
};
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];
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;
};
uint32_t flags;
};
+struct zap_analog_data {
+ uint32_t flags;
+};
+
struct zap_span {
uint32_t span_id;
uint32_t chan_count;
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];
};
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);
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);
--- /dev/null
+/*
+ * 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
#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,
typedef enum {
ZAP_EVENT_NONE,
ZAP_EVENT_DTMF,
+ ZAP_EVENT_OOB,
ZAP_EVENT_COUNT
} zap_event_type_t;
ZAP_CHAN_TYPE_DQ931,
ZAP_CHAN_TYPE_FXS,
ZAP_CHAN_TYPE_FXO,
-
ZAP_CHAN_TYPE_COUNT
} zap_chan_type_t;
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),
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)
#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 ;
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
--- /dev/null
+#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();
+
+}
*/
#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);
+}
+
#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;
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",
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;
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;
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);
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)) {
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)
{
/******************************/
+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;
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) {
}
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);
uint32_t configured = 0;
int modcount;
+ time_init();
zap_isdn_init();
memset(&interfaces, 0, sizeof(interfaces));
}
if (!zap_config_open_file(&cfg, "openzap.conf")) {
+ zap_log(ZAP_LOG_ERROR, "Cannot open openzap.conf!\n");
return ZAP_FAIL;
}
zap_status_t zap_global_destroy(void)
{
+ time_end();
+
#ifdef ZAP_ZT_SUPPORT
if (interfaces.zt_interface) {
zt_destroy();
#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;
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);
} 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")) {
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;
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;
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;