add basics for analog (wip)

git-svn-id: http://svn.openzap.org/svn/openzap/trunk@130 a93c3328-9c30-0410-af19-c9cd2b2d52af
This commit is contained in:
Anthony Minessale 2007-05-24 03:42:40 +00:00
parent 17c249c210
commit d97b50a9c9
8 changed files with 709 additions and 15 deletions

View File

@ -73,6 +73,9 @@ testapp: testapp.c $(MYLIB)
testisdn: testisdn.c $(MYLIB) testisdn: testisdn.c $(MYLIB)
$(CC) $(INCS) -L. testisdn.c -o testisdn -lopenzap -lm -lpthread $(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 priserver.o: priserver.c
$(CC) $(INCS) $(TMP) -c priserver.c -o priserver.o $(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 $@ $(CC) $(CC_CFLAGS) $(CFLAGS) -c $< -o $@
clean: clean:
rm -f *.o isdn/*.o $(MYLIB) *~ \#* testapp priserver rm -f *.o isdn/*.o $(MYLIB) *~ \#* testapp priserver testisdn testanalog

View File

@ -74,6 +74,11 @@
#pragma warning(disable:4706) #pragma warning(disable:4706)
#endif #endif
#ifndef WIN32
#include <time.h>
#include <sys/time.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -91,6 +96,8 @@
#include "Q931.h" #include "Q931.h"
#include "Q921.h" #include "Q921.h"
#define XX if (0)
#ifdef NDEBUG #ifdef NDEBUG
#undef assert #undef assert
#define assert(_Expression) ((void)(_Expression)) #define assert(_Expression) ((void)(_Expression))
@ -131,6 +138,11 @@
*/ */
#define zap_set_flag(obj, flag) (obj)->flags |= (flag) #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 \brief Clear a flag on an arbitrary object while locked
\command obj the object to test \command obj the object to test
@ -138,6 +150,12 @@
*/ */
#define zap_clear_flag(obj, flag) (obj)->flags &= ~(flag) #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 \brief Copy flags from one arbitrary object to another
\command dest the object to copy the flags to \command dest the object to copy the flags to
@ -157,6 +175,8 @@
struct zap_event { struct zap_event {
zap_event_type_t e_type; zap_event_type_t e_type;
uint32_t enum_id;
zap_channel_t *channel;
void *data; void *data;
}; };
@ -172,6 +192,8 @@ struct zap_channel {
uint32_t effective_interval; uint32_t effective_interval;
uint32_t native_interval; uint32_t native_interval;
uint32_t packet_len; uint32_t packet_len;
zap_channel_state_t state;
zap_mutex_t *mutex;
teletone_dtmf_detect_state_t dtmf_detect; teletone_dtmf_detect_state_t dtmf_detect;
zap_event_t event_header; zap_event_t event_header;
char last_error[256]; char last_error[256];
@ -179,9 +201,11 @@ struct zap_channel {
void *mod_data; void *mod_data;
uint32_t skip_read_frames; uint32_t skip_read_frames;
zap_buffer_t *dtmf_buffer; zap_buffer_t *dtmf_buffer;
zap_buffer_t *digit_buffer;
uint32_t dtmf_on; uint32_t dtmf_on;
uint32_t dtmf_off; uint32_t dtmf_off;
teletone_generation_session_t tone_session; teletone_generation_session_t tone_session;
zap_time_t last_event_time;
struct zap_span *span; struct zap_span *span;
struct zap_io_interface *zio; struct zap_io_interface *zio;
}; };
@ -207,6 +231,10 @@ struct zap_isdn_data {
uint32_t flags; uint32_t flags;
}; };
struct zap_analog_data {
uint32_t flags;
};
struct zap_span { struct zap_span {
uint32_t span_id; uint32_t span_id;
uint32_t chan_count; uint32_t chan_count;
@ -217,6 +245,8 @@ struct zap_span {
zap_trunk_type_t trunk_type; zap_trunk_type_t trunk_type;
zap_signal_type_t signal_type; zap_signal_type_t signal_type;
struct zap_isdn_data *isdn_data; struct zap_isdn_data *isdn_data;
struct zap_analog_data *analog_data;
zap_event_t event_header;
char last_error[256]; char last_error[256];
zap_channel_t channels[ZAP_MAX_CHANNELS_SPAN]; zap_channel_t channels[ZAP_MAX_CHANNELS_SPAN];
}; };
@ -233,12 +263,21 @@ struct zap_io_interface {
zio_wait_t wait; zio_wait_t wait;
zio_read_t read; zio_read_t read;
zio_write_t write; zio_write_t write;
zio_span_poll_event_t poll_event;
zio_span_next_event_t next_event;
uint32_t span_index; uint32_t span_index;
struct zap_span spans[ZAP_MAX_SPANS_INTERFACE]; 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); zap_trunk_type_t str2zap_trunk_type(char *name);
char *zap_trunk_type2str(zap_trunk_type_t type); 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_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_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_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_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_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(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_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_close(zap_channel_t **zchan);
zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj); zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj);

View File

@ -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

View File

@ -50,6 +50,8 @@ struct zap_io_interface;
#define ZAP_COMMAND_OBJ_INT *((int *)obj) #define ZAP_COMMAND_OBJ_INT *((int *)obj)
#define ZAP_COMMAND_OBJ_CHAR_P (char *)obj #define ZAP_COMMAND_OBJ_CHAR_P (char *)obj
typedef uint64_t zap_time_t;
typedef enum { typedef enum {
ZAP_TRUNK_E1, ZAP_TRUNK_E1,
ZAP_TRUNK_T1, ZAP_TRUNK_T1,
@ -79,6 +81,7 @@ typedef enum {
typedef enum { typedef enum {
ZAP_EVENT_NONE, ZAP_EVENT_NONE,
ZAP_EVENT_DTMF, ZAP_EVENT_DTMF,
ZAP_EVENT_OOB,
ZAP_EVENT_COUNT ZAP_EVENT_COUNT
} zap_event_type_t; } zap_event_type_t;
@ -143,7 +146,6 @@ typedef enum {
ZAP_CHAN_TYPE_DQ931, ZAP_CHAN_TYPE_DQ931,
ZAP_CHAN_TYPE_FXS, ZAP_CHAN_TYPE_FXS,
ZAP_CHAN_TYPE_FXO, ZAP_CHAN_TYPE_FXO,
ZAP_CHAN_TYPE_COUNT ZAP_CHAN_TYPE_COUNT
} zap_chan_type_t; } zap_chan_type_t;
@ -153,6 +155,13 @@ typedef enum {
ZAP_CHANNEL_FEATURE_INTERVAL = (1 << 2) ZAP_CHANNEL_FEATURE_INTERVAL = (1 << 2)
} zap_channel_feature_t; } 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 { typedef enum {
ZAP_CHANNEL_CONFIGURED = (1 << 0), ZAP_CHANNEL_CONFIGURED = (1 << 0),
ZAP_CHANNEL_READY = (1 << 1), ZAP_CHANNEL_READY = (1 << 1),
@ -160,14 +169,31 @@ typedef enum {
ZAP_CHANNEL_DTMF_DETECT = (1 << 3), ZAP_CHANNEL_DTMF_DETECT = (1 << 3),
ZAP_CHANNEL_SUPRESS_DTMF = (1 << 4), ZAP_CHANNEL_SUPRESS_DTMF = (1 << 4),
ZAP_CHANNEL_TRANSCODE = (1 << 5), 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; } 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_channel zap_channel_t;
typedef struct zap_event zap_event_t; typedef struct zap_event zap_event_t;
typedef struct zap_sigmsg zap_sigmsg_t; typedef struct zap_sigmsg zap_sigmsg_t;
typedef struct zap_span zap_span_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_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_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_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_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) #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_signal_cb_t) ZIO_SIGNAL_CB_ARGS ;
typedef zap_status_t (*zio_event_cb_t) ZIO_EVENT_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_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_read_t) ZIO_READ_ARGS ;
typedef zap_status_t (*zio_write_t) ZIO_WRITE_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_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_EVENT_CB_FUNCTION(name) zap_status_t name ZIO_EVENT_CB_ARGS
#define ZIO_CODEC_FUNCTION(name) zap_status_t name ZIO_CODEC_ARGS #define ZIO_CODEC_FUNCTION(name) zap_status_t name ZIO_CODEC_ARGS

View File

@ -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();
}

View File

@ -32,3 +32,212 @@
*/ */
#include "openzap.h" #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);
}

View File

@ -41,6 +41,35 @@
#include "zap_zt.h" #include "zap_zt.h"
#endif #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 { static struct {
zap_hash_t *interface_hash; zap_hash_t *interface_hash;
zap_mutex_t *mutex; zap_mutex_t *mutex;
@ -56,6 +85,41 @@ static char *TRUNK_TYPE_NAMES[] = {
NULL 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[] = { static char *LEVEL_NAMES[] = {
"EMERG", "EMERG",
"ALERT", "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_status_t zap_span_close_all(zap_io_interface_t *zio)
{ {
zap_span_t *span; zap_span_t *span;
uint32_t i; uint32_t i, j;
for(i = 0; i < zio->span_index; i++) { for(i = 0; i < zio->span_index; i++) {
span = &zio->spans[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) { if (span->mutex) {
zap_mutex_destroy(&span->mutex); zap_mutex_destroy(&span->mutex);
} }
if (span->isdn_data) { if (span->isdn_data) {
free(span->isdn_data); free(span->isdn_data);
} }
if (span->analog_data) {
free(span->isdn_data);
}
} }
return i ? ZAP_SUCCESS : ZAP_FAIL; 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->span_id = span->span_id;
new_chan->chan_id = span->chan_count; new_chan->chan_id = span->chan_count;
new_chan->span = span; 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); zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY);
*chan = new_chan; *chan = new_chan;
return ZAP_SUCCESS; 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; 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_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zio_event_cb_t event_callback)
{ {
zap_mutex_lock(zchan->span->mutex); 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); teletone_destroy_session(&zchan->tone_session);
memset(&zchan->tone_session, 0, sizeof(zchan->tone_session)); memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
} }
if (zchan->dtmf_buffer) { 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; zchan->dtmf_on = zchan->dtmf_off = 0;
if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE)) { 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; 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_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 zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen)
{ {
zap_status_t status = ZAP_FAIL; 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; sln = sln_buf;
} }
XX printf("WTF %d\n", (int) slen);
teletone_dtmf_detect(&zchan->dtmf_detect, sln, (int)slen); teletone_dtmf_detect(&zchan->dtmf_detect, sln, (int)slen);
teletone_dtmf_get(&zchan->dtmf_detect, digit_str, sizeof(digit_str)); 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; zio_event_cb_t event_callback = NULL;
zap_channel_queue_dtmf(zchan, digit_str);
if (zchan->span->event_callback) { if (zchan->span->event_callback) {
event_callback = zchan->span->event_callback; event_callback = zchan->span->event_callback;
} else if (zchan->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) { if (event_callback) {
zchan->event_header.channel = zchan;
zchan->event_header.e_type = ZAP_EVENT_DTMF; zchan->event_header.e_type = ZAP_EVENT_DTMF;
zchan->event_header.data = digit_str; zchan->event_header.data = digit_str;
event_callback(zchan, &zchan->event_header); event_callback(zchan, &zchan->event_header);
@ -1012,6 +1186,7 @@ zap_status_t zap_global_init(void)
uint32_t configured = 0; uint32_t configured = 0;
int modcount; int modcount;
time_init();
zap_isdn_init(); zap_isdn_init();
memset(&interfaces, 0, sizeof(interfaces)); memset(&interfaces, 0, sizeof(interfaces));
@ -1047,6 +1222,7 @@ zap_status_t zap_global_init(void)
} }
if (!zap_config_open_file(&cfg, "openzap.conf")) { if (!zap_config_open_file(&cfg, "openzap.conf")) {
zap_log(ZAP_LOG_ERROR, "Cannot open openzap.conf!\n");
return ZAP_FAIL; return ZAP_FAIL;
} }
@ -1082,6 +1258,8 @@ zap_status_t zap_global_init(void)
zap_status_t zap_global_destroy(void) zap_status_t zap_global_destroy(void)
{ {
time_end();
#ifdef ZAP_ZT_SUPPORT #ifdef ZAP_ZT_SUPPORT
if (interfaces.zt_interface) { if (interfaces.zt_interface) {
zt_destroy(); zt_destroy();

View File

@ -39,7 +39,9 @@
#include <sangoma_tdm_api.h> #include <sangoma_tdm_api.h>
static struct { static struct {
unsigned codec_ms; uint32_t codec_ms;
uint32_t wink_ms;
uint32_t flash_ms;
} wp_globals; } wp_globals;
static zap_io_interface_t wanpipe_interface; 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) { 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); 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++; configured++;
} else { } else {
zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x); 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")) { } else if (!strcasecmp(var, "trunk_type")) {
span->trunk_type = str2zap_trunk_type(val); span->trunk_type = str2zap_trunk_type(val);
zap_log(ZAP_LOG_DEBUG, "setting trunk type to '%s'\n", zap_trunk_type2str(span->trunk_type)); 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")) { } else if (!strcasecmp(var, "b-channel")) {
configured += wp_configure_channel(&cfg, val, span, ZAP_CHAN_TYPE_B); configured += wp_configure_channel(&cfg, val, span, ZAP_CHAN_TYPE_B);
} else if (!strcasecmp(var, "d-channel")) { } 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); zap_channel_set_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL);
zchan->effective_interval = zchan->native_interval = wp_globals.codec_ms; zchan->effective_interval = zchan->native_interval = wp_globals.codec_ms;
zchan->packet_len = zchan->native_interval * 8; zchan->packet_len = zchan->native_interval * 8;
zchan->native_codec = zchan->effective_codec;
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;
}
} }
return ZAP_SUCCESS; return ZAP_SUCCESS;
@ -392,12 +412,140 @@ static ZIO_WAIT_FUNCTION(wanpipe_wait)
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) zap_status_t wanpipe_init(zap_io_interface_t **zio)
{ {
assert(zio != NULL); assert(zio != NULL);
memset(&wanpipe_interface, 0, sizeof(wanpipe_interface)); memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
wp_globals.codec_ms = 20; wp_globals.codec_ms = 20;
wp_globals.wink_ms = 150;
wp_globals.flash_ms = 750;
wanpipe_interface.name = "wanpipe"; wanpipe_interface.name = "wanpipe";
wanpipe_interface.configure = wanpipe_configure; wanpipe_interface.configure = wanpipe_configure;
wanpipe_interface.open = wanpipe_open; 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.wait = wanpipe_wait;
wanpipe_interface.read = wanpipe_read; wanpipe_interface.read = wanpipe_read;
wanpipe_interface.write = wanpipe_write; wanpipe_interface.write = wanpipe_write;
wanpipe_interface.poll_event = wanpipe_poll_event;
wanpipe_interface.next_event = wanpipe_next_event;
*zio = &wanpipe_interface; *zio = &wanpipe_interface;
return ZAP_SUCCESS; return ZAP_SUCCESS;