2007-05-16 20:36:40 +00:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "openzap.h"
|
2007-05-17 14:56:12 +00:00
|
|
|
#include <stdarg.h>
|
2007-05-16 20:36:40 +00:00
|
|
|
#ifdef ZAP_WANPIPE_SUPPORT
|
|
|
|
#include "zap_wanpipe.h"
|
|
|
|
#endif
|
|
|
|
#ifdef ZAP_ZT_SUPPORT
|
|
|
|
#include "zap_zt.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
zap_hash_t *interface_hash;
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_t *mutex;
|
2007-05-16 20:36:40 +00:00
|
|
|
} globals;
|
|
|
|
|
2007-05-17 14:56:12 +00:00
|
|
|
static char *LEVEL_NAMES[] = {
|
|
|
|
"EMERG",
|
|
|
|
"ALERT",
|
|
|
|
"CRIT",
|
|
|
|
"ERROR",
|
|
|
|
"WARNING",
|
|
|
|
"NOTICE",
|
|
|
|
"INFO",
|
|
|
|
"DEBUG",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static char *cut_path(char *in)
|
|
|
|
{
|
|
|
|
char *p, *ret = in;
|
|
|
|
char delims[] = "/\\";
|
|
|
|
char *i;
|
|
|
|
|
|
|
|
for (i = delims; *i; i++) {
|
|
|
|
p = in;
|
|
|
|
while ((p = strchr(p, *i)) != 0) {
|
|
|
|
ret = ++p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void null_logger(char *file, const char *func, int line, int level, char *fmt, ...)
|
|
|
|
{
|
2007-05-17 17:28:35 +00:00
|
|
|
if (file && func && line && level && fmt) {
|
|
|
|
return;
|
2007-05-17 14:56:12 +00:00
|
|
|
}
|
2007-05-17 17:28:35 +00:00
|
|
|
return;
|
2007-05-17 14:56:12 +00:00
|
|
|
}
|
|
|
|
|
2007-05-17 16:58:11 +00:00
|
|
|
static int zap_log_level = 7;
|
2007-05-17 16:57:26 +00:00
|
|
|
|
2007-05-17 14:56:12 +00:00
|
|
|
static void default_logger(char *file, const char *func, int line, int level, char *fmt, ...)
|
|
|
|
{
|
|
|
|
char *fp;
|
|
|
|
char data[1024];
|
|
|
|
va_list ap;
|
2007-05-17 16:57:26 +00:00
|
|
|
|
|
|
|
if (level < 0 || level > 7) {
|
|
|
|
level = 7;
|
|
|
|
}
|
|
|
|
if (level > zap_log_level) {
|
|
|
|
return;
|
|
|
|
}
|
2007-05-17 14:56:12 +00:00
|
|
|
|
|
|
|
fp = cut_path(file);
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
|
|
|
vsnprintf(data, sizeof(data), fmt, ap);
|
|
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data);
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
zap_logger_t zap_log = null_logger;
|
2007-05-17 14:56:12 +00:00
|
|
|
|
|
|
|
void zap_global_set_logger(zap_logger_t logger)
|
|
|
|
{
|
|
|
|
if (logger) {
|
2007-05-17 16:57:26 +00:00
|
|
|
zap_log = logger;
|
2007-05-17 14:56:12 +00:00
|
|
|
} else {
|
2007-05-17 16:57:26 +00:00
|
|
|
zap_log = null_logger;
|
2007-05-17 14:56:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
void zap_global_set_default_logger(int level)
|
2007-05-17 14:56:12 +00:00
|
|
|
{
|
2007-05-17 16:57:26 +00:00
|
|
|
if (level < 0 || level > 7) {
|
|
|
|
level = 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
zap_log = default_logger;
|
|
|
|
zap_log_level = level;
|
2007-05-17 14:56:12 +00:00
|
|
|
}
|
2007-05-16 20:36:40 +00:00
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
static int equalkeys(void *k1, void *k2)
|
2007-05-16 20:36:40 +00:00
|
|
|
{
|
|
|
|
return strcmp((char *) k1, (char *) k2) ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
static uint32_t hashfromstring(void *ky)
|
2007-05-16 20:36:40 +00:00
|
|
|
{
|
|
|
|
unsigned char *str = (unsigned char *) ky;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t hash = 0;
|
2007-05-16 20:36:40 +00:00
|
|
|
int c;
|
2007-05-17 16:57:26 +00:00
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
while ((c = *str++)) {
|
|
|
|
hash = c + (hash << 6) + (hash << 16) - hash;
|
|
|
|
}
|
2007-05-17 16:57:26 +00:00
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
zap_status_t zap_span_create(zap_software_interface_t *zint, zap_span_t **span)
|
|
|
|
{
|
|
|
|
zap_span_t *new_span = NULL;
|
|
|
|
|
|
|
|
assert(zint != NULL);
|
|
|
|
|
|
|
|
if (zint->span_index < ZAP_MAX_SPANS_INTERFACE) {
|
|
|
|
new_span = &zint->spans[++zint->span_index];
|
|
|
|
memset(new_span, 0, sizeof(*new_span));
|
|
|
|
zap_set_flag(new_span, ZAP_SPAN_CONFIGURED);
|
|
|
|
new_span->span_id = zint->span_index;
|
|
|
|
new_span->zint = zint;
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_create(&new_span->mutex);
|
2007-05-16 20:36:40 +00:00
|
|
|
*span = new_span;
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_status_t zap_span_close_all(zap_software_interface_t *zint)
|
|
|
|
{
|
|
|
|
zap_span_t *span;
|
|
|
|
uint32_t i;
|
|
|
|
|
|
|
|
for(i = 0; i < zint->span_index; i++) {
|
|
|
|
span = &zint->spans[i];
|
|
|
|
if (span->mutex) {
|
|
|
|
zap_mutex_destroy(&span->mutex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return i ? ZAP_SUCCESS : ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
zap_status_t zap_span_add_channel(zap_span_t *span, zap_socket_t sockfd, zap_chan_type_t type, zap_channel_t **chan)
|
|
|
|
{
|
|
|
|
if (span->chan_count < ZAP_MAX_CHANNELS_SPAN) {
|
|
|
|
zap_channel_t *new_chan;
|
|
|
|
new_chan = &span->channels[++span->chan_count];
|
|
|
|
new_chan->type = type;
|
|
|
|
new_chan->sockfd = sockfd;
|
|
|
|
new_chan->zint = span->zint;
|
2007-05-17 20:28:38 +00:00
|
|
|
new_chan->span_id = span->span_id;
|
|
|
|
new_chan->chan_id = span->chan_count;
|
2007-05-19 00:50:50 +00:00
|
|
|
new_chan->span = span;
|
2007-05-16 20:36:40 +00:00
|
|
|
zap_set_flag(new_chan, ZAP_CHANNEL_CONFIGURED | ZAP_CHANNEL_READY);
|
|
|
|
*chan = new_chan;
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
zap_status_t zap_span_find(const char *name, uint32_t id, zap_span_t **span)
|
2007-05-19 00:50:50 +00:00
|
|
|
{
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_software_interface_t *zint;
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_span_t *fspan;
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(globals.mutex);
|
|
|
|
zint = (zap_software_interface_t *) hashtable_search(globals.interface_hash, (char *)name);
|
|
|
|
zap_mutex_unlock(globals.mutex);
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
if (!zint) {
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id > ZAP_MAX_SPANS_INTERFACE) {
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
fspan = &zint->spans[id];
|
|
|
|
|
|
|
|
if (!zap_test_flag(fspan, ZAP_SPAN_CONFIGURED)) {
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*span = fspan;
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
zap_status_t zap_span_set_event_callback(zap_span_t *span, zint_event_cb_t event_callback)
|
|
|
|
{
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(span->mutex);
|
2007-05-19 00:50:50 +00:00
|
|
|
span->event_callback = event_callback;
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_unlock(span->mutex);
|
2007-05-19 00:50:50 +00:00
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
zap_status_t zap_channel_set_event_callback(zap_channel_t *zchan, zint_event_cb_t event_callback)
|
|
|
|
{
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(zchan->span->mutex);
|
2007-05-19 00:50:50 +00:00
|
|
|
zchan->event_callback = event_callback;
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_unlock(zchan->span->mutex);
|
2007-05-19 00:50:50 +00:00
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
2007-05-16 20:36:40 +00:00
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
zap_status_t zap_channel_open_any(const char *name, uint32_t span_id, zap_direction_t direction, zap_channel_t **zchan)
|
2007-05-18 17:50:37 +00:00
|
|
|
{
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_software_interface_t *zint;
|
2007-05-18 17:50:37 +00:00
|
|
|
zap_status_t status = ZAP_FAIL;
|
2007-05-18 18:17:33 +00:00
|
|
|
zap_channel_t *check;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i,j;
|
2007-05-18 18:17:33 +00:00
|
|
|
zap_span_t *span;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t span_max;
|
2007-05-18 18:17:33 +00:00
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(globals.mutex);
|
|
|
|
zint = (zap_software_interface_t *) hashtable_search(globals.interface_hash, (char *)name);
|
|
|
|
zap_mutex_unlock(globals.mutex);
|
|
|
|
|
2007-05-18 18:17:33 +00:00
|
|
|
if (!zint) {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Invalid interface name!\n");
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (span_id) {
|
|
|
|
span_max = span_id;
|
|
|
|
} else {
|
|
|
|
span_max = zint->span_index;
|
|
|
|
}
|
|
|
|
|
2007-05-18 18:20:27 +00:00
|
|
|
if (direction == ZAP_TOP_DOWN) {
|
2007-05-18 18:17:33 +00:00
|
|
|
j = 1;
|
|
|
|
} else {
|
|
|
|
j = span_max;
|
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(globals.mutex);
|
2007-05-18 18:28:32 +00:00
|
|
|
|
2007-05-18 18:17:33 +00:00
|
|
|
for(;;) {
|
|
|
|
span = &zint->spans[j];
|
2007-05-18 18:28:32 +00:00
|
|
|
|
2007-05-18 18:17:33 +00:00
|
|
|
if (!zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
|
|
|
|
goto next_loop;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (direction == ZAP_TOP_DOWN) {
|
2007-05-18 18:28:32 +00:00
|
|
|
if (j > span_max) {
|
2007-05-18 18:17:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (j == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-05-18 18:28:32 +00:00
|
|
|
|
2007-05-18 17:50:37 +00:00
|
|
|
if (direction == ZAP_TOP_DOWN) {
|
2007-05-18 18:17:33 +00:00
|
|
|
i = 1;
|
|
|
|
} else {
|
|
|
|
i = span->chan_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
|
|
|
|
if (direction == ZAP_TOP_DOWN) {
|
2007-05-18 18:28:32 +00:00
|
|
|
if (i > span->chan_count) {
|
2007-05-18 18:17:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (i == 0) {
|
|
|
|
break;
|
2007-05-18 17:50:37 +00:00
|
|
|
}
|
|
|
|
}
|
2007-05-18 18:28:32 +00:00
|
|
|
|
2007-05-18 18:17:33 +00:00
|
|
|
check = &span->channels[i];
|
|
|
|
|
|
|
|
if (zap_test_flag(check, ZAP_CHANNEL_READY) && !zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
|
|
|
|
|
|
|
|
status = check->zint->open(check);
|
|
|
|
|
|
|
|
if (status == ZAP_SUCCESS) {
|
|
|
|
zap_set_flag(check, ZAP_CHANNEL_OPEN);
|
|
|
|
*zchan = check;
|
|
|
|
return status;
|
2007-05-18 17:50:37 +00:00
|
|
|
}
|
|
|
|
}
|
2007-05-18 18:17:33 +00:00
|
|
|
|
|
|
|
if (direction == ZAP_TOP_DOWN) {
|
|
|
|
i++;
|
|
|
|
} else {
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
next_loop:
|
|
|
|
|
|
|
|
if (direction == ZAP_TOP_DOWN) {
|
|
|
|
j++;
|
|
|
|
} else {
|
|
|
|
j--;
|
2007-05-18 17:50:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_unlock(globals.mutex);
|
|
|
|
|
2007-05-18 17:50:37 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
static zap_status_t zap_channel_reset(zap_channel_t *zchan)
|
|
|
|
{
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_OPEN);
|
|
|
|
zchan->event_callback = NULL;
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
|
|
|
|
if (zchan->tone_session.buffer) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
zchan->dtmf_on = zchan->dtmf_off = 0;
|
|
|
|
|
|
|
|
if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE)) {
|
|
|
|
zchan->effective_codec = zchan->native_codec;
|
|
|
|
zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
zap_status_t zap_channel_open(const char *name, uint32_t span_id, uint32_t chan_id, zap_channel_t **zchan)
|
2007-05-16 20:36:40 +00:00
|
|
|
{
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_software_interface_t *zint;
|
2007-05-17 21:58:11 +00:00
|
|
|
zap_status_t status = ZAP_FAIL;
|
2007-05-16 20:36:40 +00:00
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(globals.mutex);
|
|
|
|
zint = (zap_software_interface_t *) hashtable_search(globals.interface_hash, (char *)name);
|
|
|
|
zap_mutex_unlock(globals.mutex);
|
|
|
|
|
|
|
|
|
2007-05-16 22:56:27 +00:00
|
|
|
if (span_id < ZAP_MAX_SPANS_INTERFACE && chan_id < ZAP_MAX_CHANNELS_SPAN && zint) {
|
2007-05-16 20:36:40 +00:00
|
|
|
zap_channel_t *check;
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(zint->spans[span_id].mutex);
|
2007-05-16 20:36:40 +00:00
|
|
|
check = &zint->spans[span_id].channels[chan_id];
|
2007-05-21 17:48:13 +00:00
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
if (zap_test_flag(check, ZAP_CHANNEL_READY) && ! zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
|
2007-05-17 21:58:11 +00:00
|
|
|
status = check->zint->open(check);
|
|
|
|
if (status == ZAP_SUCCESS) {
|
|
|
|
zap_set_flag(check, ZAP_CHANNEL_OPEN);
|
|
|
|
*zchan = check;
|
|
|
|
}
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_unlock(zint->spans[span_id].mutex);
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
2007-05-17 21:58:11 +00:00
|
|
|
return status;
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
zap_status_t zap_channel_close(zap_channel_t **zchan)
|
|
|
|
{
|
|
|
|
zap_channel_t *check;
|
2007-05-17 21:58:11 +00:00
|
|
|
zap_status_t status = ZAP_FAIL;
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
assert(zchan != NULL);
|
|
|
|
check = *zchan;
|
|
|
|
assert(check != NULL);
|
2007-05-18 17:50:37 +00:00
|
|
|
*zchan = NULL;
|
2007-05-21 17:48:13 +00:00
|
|
|
|
|
|
|
zap_mutex_lock(check->span->mutex);
|
2007-05-16 20:36:40 +00:00
|
|
|
if (zap_test_flag(check, ZAP_CHANNEL_OPEN)) {
|
2007-05-17 21:58:11 +00:00
|
|
|
status = check->zint->close(check);
|
|
|
|
if (status == ZAP_SUCCESS) {
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_channel_reset(check);
|
2007-05-17 21:58:11 +00:00
|
|
|
*zchan = NULL;
|
|
|
|
}
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
2007-05-21 17:48:13 +00:00
|
|
|
|
|
|
|
zap_mutex_unlock(check->span->mutex);
|
2007-05-16 20:36:40 +00:00
|
|
|
|
2007-05-17 21:58:11 +00:00
|
|
|
return status;
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
static zap_status_t zchan_activate_dtmf_buffer(zap_channel_t *zchan)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (zchan->dtmf_buffer) {
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zap_buffer_create(&zchan->dtmf_buffer, 1024, 3192, 0) != ZAP_SUCCESS) {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Failed to allocate DTMF Buffer!\n");
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "buffer error");
|
|
|
|
return ZAP_FAIL;
|
|
|
|
} else {
|
|
|
|
zap_log(ZAP_LOG_DEBUG, "Created DTMF Buffer!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!zchan->dtmf_on) {
|
|
|
|
zchan->dtmf_on = 150;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!zchan->dtmf_off) {
|
|
|
|
zchan->dtmf_off = 50;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
|
|
|
|
teletone_init_session(&zchan->tone_session, 1024, NULL, NULL);
|
|
|
|
|
|
|
|
zchan->tone_session.rate = 8000;
|
|
|
|
zchan->tone_session.duration = zchan->dtmf_on * (zchan->tone_session.rate / 1000);
|
|
|
|
zchan->tone_session.wait = zchan->dtmf_off * (zchan->tone_session.rate / 1000);
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, void *obj)
|
2007-05-16 20:36:40 +00:00
|
|
|
{
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_status_t status = ZAP_FAIL;
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
assert(zchan != NULL);
|
2007-05-16 21:59:11 +00:00
|
|
|
assert(zchan->zint != NULL);
|
2007-05-16 20:36:40 +00:00
|
|
|
|
|
|
|
if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
|
2007-05-16 20:36:40 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_lock(zchan->span->mutex);
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
switch(command) {
|
2007-05-20 01:50:01 +00:00
|
|
|
case ZAP_COMMAND_SET_INTERVAL:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) {
|
|
|
|
zchan->effective_interval = ZAP_COMMAND_OBJ_INT;
|
|
|
|
if (zchan->effective_interval == zchan->native_interval) {
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_BUFFER);
|
|
|
|
} else {
|
|
|
|
zap_set_flag(zchan, ZAP_CHANNEL_BUFFER);
|
|
|
|
}
|
|
|
|
zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-20 01:50:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_GET_INTERVAL:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_INTERVAL)) {
|
|
|
|
ZAP_COMMAND_OBJ_INT = zchan->effective_interval;
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-20 01:50:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_SET_CODEC:
|
2007-05-19 04:07:48 +00:00
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
|
|
|
|
zchan->effective_codec = ZAP_COMMAND_OBJ_INT;
|
|
|
|
if (zchan->effective_codec == zchan->native_codec) {
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_TRANSCODE);
|
|
|
|
} else {
|
|
|
|
zap_set_flag(zchan, ZAP_CHANNEL_TRANSCODE);
|
|
|
|
}
|
2007-05-20 01:50:01 +00:00
|
|
|
zchan->packet_len = zchan->native_interval * (zchan->effective_codec == ZAP_CODEC_SLIN ? 16 : 8);
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ZAP_COMMAND_GET_CODEC:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_CODECS)) {
|
|
|
|
ZAP_COMMAND_OBJ_INT = zchan->effective_codec;
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2007-05-19 00:50:50 +00:00
|
|
|
case ZAP_COMMAND_ENABLE_TONE_DETECT:
|
|
|
|
{
|
|
|
|
/* if they don't have thier own, use ours */
|
2007-05-19 04:07:48 +00:00
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
|
|
|
|
if (tt == ZAP_TONE_DTMF) {
|
|
|
|
teletone_dtmf_detect_init (&zchan->dtmf_detect, 8000);
|
|
|
|
zap_set_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
|
|
|
|
zap_set_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 00:50:50 +00:00
|
|
|
} else {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command");
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_FAIL);
|
2007-05-19 00:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_DISABLE_TONE_DETECT:
|
|
|
|
{
|
2007-05-19 04:07:48 +00:00
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
|
|
|
|
if (tt == ZAP_TONE_DTMF) {
|
|
|
|
teletone_dtmf_detect_init (&zchan->dtmf_detect, 8000);
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_DTMF_DETECT);
|
|
|
|
zap_clear_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF);
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 00:50:50 +00:00
|
|
|
} else {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid command");
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_FAIL);
|
2007-05-19 00:50:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-05-19 04:07:48 +00:00
|
|
|
case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
|
|
|
|
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
|
|
|
|
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
|
|
|
|
int val = ZAP_COMMAND_OBJ_INT;
|
|
|
|
if (val > 10 && val < 1000) {
|
|
|
|
zchan->dtmf_on = val;
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 04:07:48 +00:00
|
|
|
} else {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_FAIL);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
|
|
|
|
int val = ZAP_COMMAND_OBJ_INT;
|
|
|
|
if (val > 10 && val < 1000) {
|
|
|
|
zchan->dtmf_off = val;
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 04:07:48 +00:00
|
|
|
} else {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_FAIL);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAP_COMMAND_SEND_DTMF:
|
|
|
|
{
|
|
|
|
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
|
|
|
|
char *cur;
|
|
|
|
char *digits = ZAP_COMMAND_OBJ_CHAR_P;
|
|
|
|
if (!zchan->dtmf_buffer) {
|
|
|
|
if ((status = zchan_activate_dtmf_buffer(zchan)) != ZAP_SUCCESS) {
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, status);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
zap_log(ZAP_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
|
2007-05-21 17:48:13 +00:00
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
for (cur = digits; *cur; cur++) {
|
|
|
|
int wrote = 0;
|
|
|
|
if ((wrote = teletone_mux_tones(&zchan->tone_session, &zchan->tone_session.TONES[(int)*cur]))) {
|
|
|
|
zap_buffer_write(zchan->dtmf_buffer, zchan->tone_session.buffer, wrote * 2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
zchan->skip_read_frames = 200;
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_SUCCESS);
|
2007-05-19 04:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
2007-05-19 00:50:50 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-05-18 03:31:09 +00:00
|
|
|
if (!zchan->zint->command) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
|
2007-05-21 17:48:13 +00:00
|
|
|
GOTO_STATUS(done, ZAP_FAIL);
|
2007-05-16 21:59:11 +00:00
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
status = zchan->zint->command(zchan, command, obj);
|
|
|
|
|
|
|
|
done:
|
|
|
|
zap_mutex_unlock(zchan->span->mutex);
|
|
|
|
return status;
|
2007-05-16 20:36:40 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_status_t zap_channel_wait(zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to)
|
2007-05-16 20:36:40 +00:00
|
|
|
{
|
|
|
|
assert(zchan != NULL);
|
2007-05-16 21:59:11 +00:00
|
|
|
assert(zchan->zint != NULL);
|
2007-05-16 20:36:40 +00:00
|
|
|
|
|
|
|
if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
|
2007-05-16 20:36:40 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-16 21:59:11 +00:00
|
|
|
if (!zchan->zint->wait) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
|
2007-05-16 21:59:11 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return zchan->zint->wait(zchan, flags, to);
|
2007-05-16 20:36:40 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
/*******************************/
|
|
|
|
ZINT_CODEC_FUNCTION(zint_slin2ulaw)
|
|
|
|
{
|
|
|
|
int16_t sln_buf[512] = {0}, *sln = sln_buf;
|
|
|
|
uint8_t *lp = data;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i;
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_size_t len = *datalen;
|
|
|
|
|
|
|
|
if (max > len) {
|
|
|
|
max = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(sln, data, max);
|
|
|
|
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*lp++ = linear_to_ulaw(*sln++);
|
|
|
|
}
|
|
|
|
|
|
|
|
*datalen = max / 2;
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ZINT_CODEC_FUNCTION(zint_ulaw2slin)
|
|
|
|
{
|
|
|
|
int16_t *sln = data;
|
|
|
|
uint8_t law[1024] = {0}, *lp = law;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i;
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_size_t len = *datalen;
|
|
|
|
|
|
|
|
if (max > len) {
|
|
|
|
max = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(law, data, max);
|
|
|
|
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*sln++ = ulaw_to_linear(*lp++);
|
|
|
|
}
|
2007-05-19 04:07:48 +00:00
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
*datalen = max * 2;
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZINT_CODEC_FUNCTION(zint_slin2alaw)
|
|
|
|
{
|
|
|
|
int16_t sln_buf[512] = {0}, *sln = sln_buf;
|
|
|
|
uint8_t *lp = data;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i;
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_size_t len = *datalen;
|
|
|
|
|
|
|
|
if (max > len) {
|
|
|
|
max = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(sln, data, max);
|
|
|
|
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*lp++ = linear_to_alaw(*sln++);
|
|
|
|
}
|
|
|
|
|
|
|
|
*datalen = max / 2;
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ZINT_CODEC_FUNCTION(zint_alaw2slin)
|
|
|
|
{
|
|
|
|
int16_t *sln = data;
|
|
|
|
uint8_t law[1024] = {0}, *lp = law;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i;
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_size_t len = *datalen;
|
|
|
|
|
|
|
|
if (max > len) {
|
|
|
|
max = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(law, data, max);
|
|
|
|
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*sln++ = alaw_to_linear(*lp++);
|
|
|
|
}
|
|
|
|
|
|
|
|
*datalen = max * 2;
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZINT_CODEC_FUNCTION(zint_ulaw2alaw)
|
|
|
|
{
|
|
|
|
zap_size_t len = *datalen;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i;
|
2007-05-19 00:50:50 +00:00
|
|
|
uint8_t *lp = data;
|
|
|
|
|
|
|
|
if (max > len) {
|
|
|
|
max = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*lp = ulaw_to_alaw(*lp);
|
|
|
|
lp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZINT_CODEC_FUNCTION(zint_alaw2ulaw)
|
|
|
|
{
|
|
|
|
zap_size_t len = *datalen;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i;
|
2007-05-19 00:50:50 +00:00
|
|
|
uint8_t *lp = data;
|
|
|
|
|
|
|
|
if (max > len) {
|
|
|
|
max = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*lp = alaw_to_ulaw(*lp);
|
|
|
|
lp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************/
|
2007-05-16 20:36:40 +00:00
|
|
|
|
|
|
|
zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *datalen)
|
|
|
|
{
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_status_t status = ZAP_FAIL;
|
2007-05-19 05:05:29 +00:00
|
|
|
zint_codec_t codec_func = NULL;
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_size_t max = *datalen;
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
assert(zchan != NULL);
|
2007-05-16 21:59:11 +00:00
|
|
|
assert(zchan->zint != NULL);
|
|
|
|
assert(zchan->zint != NULL);
|
2007-05-18 03:31:09 +00:00
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
|
2007-05-16 20:36:40 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-16 21:59:11 +00:00
|
|
|
if (!zchan->zint->read) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
|
2007-05-16 21:59:11 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
status = zchan->zint->read(zchan, data, datalen);
|
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
if (status == ZAP_SUCCESS && zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) {
|
2007-05-19 00:50:50 +00:00
|
|
|
if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
|
|
|
|
codec_func = zint_ulaw2slin;
|
|
|
|
} else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) {
|
|
|
|
codec_func = zint_ulaw2alaw;
|
|
|
|
} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
|
|
|
|
codec_func = zint_alaw2slin;
|
|
|
|
} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) {
|
|
|
|
codec_func = zint_alaw2ulaw;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (codec_func) {
|
|
|
|
status = codec_func(data, max, datalen);
|
|
|
|
} else {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
|
|
|
|
status = ZAP_FAIL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zap_test_flag(zchan, ZAP_CHANNEL_DTMF_DETECT)) {
|
|
|
|
int16_t sln_buf[1024], *sln = sln_buf;
|
|
|
|
zap_size_t slen;
|
|
|
|
char digit_str[80] = "";
|
|
|
|
|
|
|
|
if (zchan->effective_codec == ZAP_CODEC_SLIN) {
|
|
|
|
sln = data;
|
|
|
|
slen = *datalen / 2;
|
|
|
|
} else {
|
|
|
|
zap_size_t len = *datalen;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t i;
|
2007-05-19 00:50:50 +00:00
|
|
|
uint8_t *lp = data;
|
|
|
|
slen = max;
|
|
|
|
|
|
|
|
if (slen > len) {
|
|
|
|
slen = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zchan->effective_codec == ZAP_CODEC_ULAW) {
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*sln++ = ulaw_to_linear(*lp++);
|
|
|
|
}
|
|
|
|
} else if (zchan->effective_codec == ZAP_CODEC_ALAW) {
|
|
|
|
for(i = 0; i < max; i++) {
|
|
|
|
*sln++ = alaw_to_linear(*lp++);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sln = sln_buf;
|
|
|
|
}
|
|
|
|
|
2007-05-19 05:05:29 +00:00
|
|
|
teletone_dtmf_detect(&zchan->dtmf_detect, sln, (int)slen);
|
2007-05-19 00:50:50 +00:00
|
|
|
teletone_dtmf_get(&zchan->dtmf_detect, digit_str, sizeof(digit_str));
|
|
|
|
if(digit_str[0]) {
|
|
|
|
zint_event_cb_t event_callback = NULL;
|
|
|
|
if (zchan->span->event_callback) {
|
|
|
|
event_callback = zchan->span->event_callback;
|
|
|
|
} else if (zchan->event_callback) {
|
|
|
|
event_callback = zchan->event_callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event_callback) {
|
|
|
|
zchan->event_header.e_type = ZAP_EVENT_DTMF;
|
|
|
|
zchan->event_header.data = digit_str;
|
|
|
|
event_callback(zchan, &zchan->event_header);
|
|
|
|
zchan->event_header.e_type = ZAP_EVENT_NONE;
|
|
|
|
zchan->event_header.data = NULL;
|
|
|
|
}
|
|
|
|
if (zap_test_flag(zchan, ZAP_CHANNEL_SUPRESS_DTMF)) {
|
|
|
|
zchan->skip_read_frames = 20;
|
|
|
|
}
|
|
|
|
if (zchan->skip_read_frames > 0) {
|
|
|
|
memset(data, 0, *datalen);
|
|
|
|
zchan->skip_read_frames--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
zap_status_t zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t *datalen)
|
|
|
|
{
|
2007-05-19 00:50:50 +00:00
|
|
|
zap_status_t status = ZAP_FAIL;
|
2007-05-19 05:05:29 +00:00
|
|
|
zint_codec_t codec_func = NULL;
|
2007-05-19 04:07:48 +00:00
|
|
|
zap_size_t dtmf_blen, max = *datalen;
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
assert(zchan != NULL);
|
2007-05-16 21:59:11 +00:00
|
|
|
assert(zchan->zint != NULL);
|
2007-05-16 20:36:40 +00:00
|
|
|
|
|
|
|
if (!zap_test_flag(zchan, ZAP_CHANNEL_OPEN)) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "channel not open");
|
2007-05-16 20:36:40 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-16 21:59:11 +00:00
|
|
|
if (!zchan->zint->write) {
|
2007-05-19 00:50:50 +00:00
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "method not implemented");
|
2007-05-16 21:59:11 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
2007-05-16 20:36:40 +00:00
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
if (zap_test_flag(zchan, ZAP_CHANNEL_TRANSCODE) && zchan->effective_codec != zchan->native_codec) {
|
2007-05-19 00:50:50 +00:00
|
|
|
if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
|
|
|
|
codec_func = zint_slin2ulaw;
|
|
|
|
} else if (zchan->native_codec == ZAP_CODEC_ULAW && zchan->effective_codec == ZAP_CODEC_ALAW) {
|
|
|
|
codec_func = zint_alaw2ulaw;
|
|
|
|
} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_SLIN) {
|
|
|
|
codec_func = zint_slin2alaw;
|
|
|
|
} else if (zchan->native_codec == ZAP_CODEC_ALAW && zchan->effective_codec == ZAP_CODEC_ULAW) {
|
|
|
|
codec_func = zint_ulaw2alaw;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (codec_func) {
|
|
|
|
status = codec_func(data, max, datalen);
|
|
|
|
} else {
|
|
|
|
snprintf(zchan->last_error, sizeof(zchan->last_error), "codec error!");
|
|
|
|
status = ZAP_FAIL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
if (zchan->dtmf_buffer && (dtmf_blen = zap_buffer_inuse(zchan->dtmf_buffer))) {
|
|
|
|
zap_size_t dlen = *datalen;
|
|
|
|
uint8_t auxbuf[1024];
|
2007-05-19 05:05:29 +00:00
|
|
|
zap_size_t len, br;
|
2007-05-19 04:07:48 +00:00
|
|
|
|
|
|
|
if (zchan->native_codec != ZAP_CODEC_SLIN) {
|
|
|
|
dlen *= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = dtmf_blen > dlen ? dlen : dtmf_blen;
|
|
|
|
|
|
|
|
br = zap_buffer_read(zchan->dtmf_buffer, auxbuf, len);
|
|
|
|
|
|
|
|
if (br < dlen) {
|
|
|
|
memset(auxbuf + br, 0, dlen - br);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(data, auxbuf, dlen);
|
|
|
|
|
|
|
|
if (zchan->native_codec != ZAP_CODEC_SLIN) {
|
|
|
|
if (zchan->native_codec == ZAP_CODEC_ULAW) {
|
|
|
|
*datalen = dlen;
|
|
|
|
zint_slin2ulaw(data, max, datalen);
|
|
|
|
} else if (zchan->native_codec == ZAP_CODEC_ALAW) {
|
|
|
|
*datalen = dlen;
|
|
|
|
zint_slin2alaw(data, max, datalen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-19 00:50:50 +00:00
|
|
|
status = zchan->zint->write(zchan, data, datalen);
|
|
|
|
|
|
|
|
return status;
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
static struct {
|
|
|
|
zap_software_interface_t *wanpipe_interface;
|
|
|
|
zap_software_interface_t *zt_interface;
|
|
|
|
} interfaces;
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
zap_status_t zap_global_init(void)
|
|
|
|
{
|
|
|
|
zap_config_t cfg;
|
|
|
|
char *var, *val;
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t configured = 0;
|
2007-05-17 16:57:26 +00:00
|
|
|
int modcount;
|
2007-05-17 03:31:21 +00:00
|
|
|
|
2007-05-21 17:48:13 +00:00
|
|
|
memset(&interfaces, 0, sizeof(interfaces));
|
2007-05-16 20:36:40 +00:00
|
|
|
globals.interface_hash = create_hashtable(16, hashfromstring, equalkeys);
|
2007-05-17 16:57:26 +00:00
|
|
|
modcount = 0;
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_create(&globals.mutex);
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
#ifdef ZAP_WANPIPE_SUPPORT
|
2007-05-21 17:48:13 +00:00
|
|
|
if (wanpipe_init(&interfaces.wanpipe_interface) == ZAP_SUCCESS) {
|
|
|
|
zap_mutex_lock(globals.mutex);
|
|
|
|
hashtable_insert(globals.interface_hash, (void *)interfaces.wanpipe_interface->name, interfaces.wanpipe_interface);
|
|
|
|
zap_mutex_unlock(globals.mutex);
|
2007-05-17 16:57:26 +00:00
|
|
|
modcount++;
|
|
|
|
} else {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Error initilizing wanpipe.\n");
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
2007-05-21 17:48:13 +00:00
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
#ifdef ZAP_ZT_SUPPORT
|
2007-05-21 17:48:13 +00:00
|
|
|
if (zt_init(&interfaces.zt_interface) == ZAP_SUCCESS) {
|
|
|
|
zap_mutex_lock(globals.mutex);
|
|
|
|
hashtable_insert(globals.interface_hash, (void *)interfaces.zt_interface->name, interfaces.zt_interface);
|
|
|
|
zap_mutex_unlock(globals.mutex);
|
2007-05-17 16:57:26 +00:00
|
|
|
modcount++;
|
|
|
|
} else {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Error initilizing zt.\n");
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
if (!modcount) {
|
|
|
|
zap_log(ZAP_LOG_ERROR, "Error initilizing anything.\n");
|
2007-05-16 20:36:40 +00:00
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
if (!zap_config_open_file(&cfg, "openzap.conf")) {
|
|
|
|
return ZAP_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-05-16 20:36:40 +00:00
|
|
|
while (zap_config_next_pair(&cfg, &var, &val)) {
|
|
|
|
if (!strcasecmp(cfg.category, "openzap")) {
|
|
|
|
if (!strcmp(var, "load")) {
|
|
|
|
zap_software_interface_t *zint;
|
2007-05-21 17:48:13 +00:00
|
|
|
|
|
|
|
zap_mutex_lock(globals.mutex);
|
2007-05-16 22:56:27 +00:00
|
|
|
zint = (zap_software_interface_t *) hashtable_search(globals.interface_hash, val);
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_unlock(globals.mutex);
|
|
|
|
|
2007-05-16 22:56:27 +00:00
|
|
|
if (zint) {
|
2007-05-16 20:36:40 +00:00
|
|
|
if (zint->configure(zint) == ZAP_SUCCESS) {
|
|
|
|
configured++;
|
|
|
|
}
|
2007-05-17 16:57:26 +00:00
|
|
|
} else {
|
|
|
|
zap_log(ZAP_LOG_WARNING, "Attempted to load Non-Existant module '%s'\n", val);
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-17 03:31:21 +00:00
|
|
|
zap_config_close_file(&cfg);
|
|
|
|
|
2007-05-17 16:57:26 +00:00
|
|
|
if (configured) {
|
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
zap_log(ZAP_LOG_ERROR, "No modules configured!\n");
|
|
|
|
return ZAP_FAIL;
|
2007-05-16 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
zap_status_t zap_global_destroy(void)
|
|
|
|
{
|
|
|
|
#ifdef ZAP_ZT_SUPPORT
|
2007-05-21 17:48:13 +00:00
|
|
|
if (interfaces.zt_interface) {
|
|
|
|
zt_destroy();
|
|
|
|
zap_span_close_all(interfaces.zt_interface);
|
|
|
|
}
|
2007-05-16 20:36:40 +00:00
|
|
|
#endif
|
|
|
|
#ifdef ZAP_WANPIPE_SUPPORT
|
2007-05-21 17:48:13 +00:00
|
|
|
if (interfaces.wanpipe_interface) {
|
|
|
|
wanpipe_destroy();
|
|
|
|
zap_span_close_all(interfaces.wanpipe_interface);
|
|
|
|
}
|
2007-05-16 20:36:40 +00:00
|
|
|
#endif
|
2007-05-17 20:28:38 +00:00
|
|
|
|
|
|
|
hashtable_destroy(globals.interface_hash, 0);
|
2007-05-21 17:48:13 +00:00
|
|
|
zap_mutex_destroy(&globals.mutex);
|
2007-05-16 20:36:40 +00:00
|
|
|
return ZAP_SUCCESS;
|
|
|
|
}
|
2007-05-17 20:28:38 +00:00
|
|
|
|
|
|
|
|
2007-05-19 04:07:48 +00:00
|
|
|
uint32_t zap_separate_string(char *buf, char delim, char **array, int arraylen)
|
2007-05-17 20:28:38 +00:00
|
|
|
{
|
|
|
|
int argc;
|
|
|
|
char *ptr;
|
|
|
|
int quot = 0;
|
|
|
|
char qc = '"';
|
|
|
|
char *e;
|
|
|
|
int x;
|
|
|
|
|
|
|
|
if (!buf || !array || !arraylen) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(array, 0, arraylen * sizeof(*array));
|
|
|
|
|
|
|
|
ptr = buf;
|
|
|
|
|
|
|
|
for (argc = 0; *ptr && (argc < arraylen - 1); argc++) {
|
|
|
|
array[argc] = ptr;
|
|
|
|
for (; *ptr; ptr++) {
|
|
|
|
if (*ptr == qc) {
|
|
|
|
if (quot) {
|
|
|
|
quot--;
|
|
|
|
} else {
|
|
|
|
quot++;
|
|
|
|
}
|
|
|
|
} else if ((*ptr == delim) && !quot) {
|
|
|
|
*ptr++ = '\0';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*ptr) {
|
|
|
|
array[argc++] = ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* strip quotes */
|
|
|
|
for (x = 0; x < argc; x++) {
|
|
|
|
if (*(array[x]) == qc) {
|
|
|
|
(array[x])++;
|
|
|
|
if ((e = strchr(array[x], qc))) {
|
|
|
|
*e = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return argc;
|
|
|
|
}
|