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 4b46d222e6
commit 6e8a5139ec
8 changed files with 709 additions and 15 deletions

View 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

View File

@ -74,6 +74,11 @@
#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))
@ -131,6 +138,11 @@
*/
#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
@ -138,6 +150,12 @@
*/
#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
@ -157,6 +175,8 @@
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);

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

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 "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"
#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();

View 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;