- added better compatibility for OpenPBX code creation.
- added first code for RTP over CAPI for Eicon DIVA Server cards.
This commit is contained in:
parent
b18c166ecf
commit
c828da398a
|
@ -1,2 +1,3 @@
|
|||
.version
|
||||
config.h
|
||||
openpbx
|
||||
|
|
29
Makefile
29
Makefile
|
@ -1,11 +1,12 @@
|
|||
#
|
||||
# (CAPI*)
|
||||
#
|
||||
# An implementation of Common ISDN API 2.0 for Asterisk
|
||||
# An implementation of Common ISDN API 2.0 for
|
||||
# Asterisk/OpenPBX.org
|
||||
#
|
||||
# Makefile, based on the Asterisk Makefile, Coypright (C) 1999, Mark Spencer
|
||||
#
|
||||
# Copyright (C) 2005 Cytronics & Melware
|
||||
# Copyright (C) 2005-2006 Cytronics & Melware
|
||||
#
|
||||
# Armin Schindler <armin@melware.de>
|
||||
#
|
||||
|
@ -22,6 +23,8 @@ OSNAME=${shell uname}
|
|||
|
||||
.EXPORT_ALL_VARIABLES:
|
||||
|
||||
.PHONY: openpbx
|
||||
|
||||
INSTALL_PREFIX=
|
||||
|
||||
ASTERISK_HEADER_DIR=$(INSTALL_PREFIX)/usr/include
|
||||
|
@ -80,7 +83,7 @@ INSTALL=install
|
|||
|
||||
SHAREDOS=chan_capi.so
|
||||
|
||||
OBJECTS=chan_capi.o c20msg.o
|
||||
OBJECTS=chan_capi.o c20msg.o chan_capi_rtp.o
|
||||
|
||||
CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations
|
||||
|
||||
|
@ -108,3 +111,23 @@ install_config: capi.conf
|
|||
|
||||
samples: install_config
|
||||
|
||||
openpbx:
|
||||
@rm -rf openpbx
|
||||
@mkdir -p openpbx/channels
|
||||
@mkdir -p openpbx/include/openpbx
|
||||
@mkdir -p openpbx/doc
|
||||
@mkdir -p openpbx/configs
|
||||
@( \
|
||||
./preparser -c openpbx.ctrl chan_capi.c openpbx/channels/chan_capi.c; \
|
||||
./preparser -c openpbx.ctrl chan_capi_rtp.c openpbx/channels/chan_capi_rtp.c; \
|
||||
./preparser -c openpbx.ctrl c20msg.c openpbx/channels/c20msg.c; \
|
||||
./preparser -c openpbx.ctrl chan_capi.h openpbx/include/openpbx/chan_capi.h; \
|
||||
./preparser -c openpbx.ctrl chan_capi_rtp.h openpbx/include/openpbx/chan_capi_rtp.h; \
|
||||
./preparser -c openpbx.ctrl chan_capi20.h openpbx/include/openpbx/chan_capi20.h; \
|
||||
./preparser -c openpbx.ctrl xlaw.h openpbx/include/openpbx/xlaw.h; \
|
||||
./preparser -c openpbx.ctrl README openpbx/doc/README.chan_capi; \
|
||||
./preparser -c openpbx.ctrl capi.conf openpbx/configs/capi.conf.sample; \
|
||||
true; \
|
||||
)
|
||||
|
||||
|
||||
|
|
3
README
3
README
|
@ -1,7 +1,7 @@
|
|||
(CAPI*) chan_capi a Common ISDN API 2.0 implementation
|
||||
for Asterisk/OpenPBX
|
||||
|
||||
Copyright (C) 2005 Cytronics & Melware
|
||||
Copyright (C) 2005-2006 Cytronics & Melware
|
||||
Armin Schindler <armin@melware.de>
|
||||
|
||||
Reworked, but based on the work of
|
||||
|
@ -65,6 +65,7 @@ This chan_capi version includes:
|
|||
- Support 'type of number'.
|
||||
- ISDN hold.
|
||||
- CAPI Line Interconnect.
|
||||
- Eicon DIVA Server VoIP/RTP
|
||||
|
||||
Permissions
|
||||
===========
|
||||
|
|
10
capi.conf
10
capi.conf
|
@ -30,10 +30,10 @@ group=1 ;dialout group
|
|||
;prefix=0 ;set a prefix to calling number on incoming calls
|
||||
softdtmf=on ;enable/disable software dtmf detection, recommended for AVM cards
|
||||
relaxdtmf=on ;in addition to softdtmf, you can use relaxed dtmf detection
|
||||
accountcode= ;Asterisk accountcode to use in CDRs
|
||||
accountcode= ;PBX accountcode to use in CDRs
|
||||
context=capi-in ;context for incoming calls
|
||||
;holdtype=hold ;when Asterisk puts the call on hold, ISDN HOLD will be used. If
|
||||
;set to 'local' (default value), no hold is done and Asterisk may
|
||||
;holdtype=hold ;when the PBX puts the call on hold, ISDN HOLD will be used. If
|
||||
;set to 'local' (default value), no hold is done and the PBX may
|
||||
;play MOH.
|
||||
;immediate=yes ;DID: immediate start of pbx with extension 's' if no digits were
|
||||
; received on incoming call (no destination number yet)
|
||||
|
@ -46,8 +46,10 @@ context=capi-in ;context for incoming calls
|
|||
echocancelold=yes;use facility selector 6 instead of correct 8 (necessary for older eicon drivers)
|
||||
;echotail=64 ;echo cancel tail setting
|
||||
;bridge=yes ;native bridging (CAPI line interconnect) if available
|
||||
;callgroup=1 ;Asterisk call group
|
||||
;callgroup=1 ;PBX call group
|
||||
;language=de ;set language for this device (overwrites default language)
|
||||
;disallow=all ;RTP codec selection (valid with Eicon DIVA Server only)
|
||||
;allow=all ;RTP codec selection (valid with Eicon DIVA Server only)
|
||||
devices=2 ;number of concurrent calls on this controller
|
||||
;(2 makes sense for single BRI, 30 for PRI)
|
||||
|
||||
|
|
378
chan_capi.c
378
chan_capi.c
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for Asterisk
|
||||
* An implementation of Common ISDN API 2.0 for
|
||||
* Asterisk / OpenPBX.org
|
||||
*
|
||||
* Copyright (C) 2005 Cytronics & Melware
|
||||
* Copyright (C) 2005-2006 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
|
@ -15,7 +16,49 @@
|
|||
* This program is free software and may be modified and
|
||||
* distributed under the terms of the GNU Public License.
|
||||
*/
|
||||
#ifdef PBX_IS_OPBX
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "confdefs.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef PBX_IS_OPBX
|
||||
#include "openpbx.h"
|
||||
|
||||
OPENPBX_FILE_VERSION("$HeadURL$", "$Revision$")
|
||||
|
||||
#include "openpbx/lock.h"
|
||||
#include "openpbx/frame.h"
|
||||
#include "openpbx/channel.h"
|
||||
#include "openpbx/logger.h"
|
||||
#include "openpbx/module.h"
|
||||
#include "openpbx/pbx.h"
|
||||
#include "openpbx/config.h"
|
||||
#include "openpbx/options.h"
|
||||
#include "openpbx/features.h"
|
||||
#include "openpbx/utils.h"
|
||||
#include "openpbx/cli.h"
|
||||
#include "openpbx/rtp.h"
|
||||
#include "openpbx/causes.h"
|
||||
#include "openpbx/strings.h"
|
||||
#include "openpbx/devicestate.h"
|
||||
#include "openpbx/dsp.h"
|
||||
#include "openpbx/xlaw.h"
|
||||
#include "openpbx/chan_capi20.h"
|
||||
#include "openpbx/chan_capi.h"
|
||||
#include "openpbx/chan_capi_rtp.h"
|
||||
#else
|
||||
#include "config.h"
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
|
@ -32,36 +75,39 @@
|
|||
#include <asterisk/features.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/cli.h>
|
||||
#include <asterisk/rtp.h>
|
||||
#include <asterisk/causes.h>
|
||||
#ifndef CC_AST_NO_STRINGS
|
||||
#include <asterisk/strings.h>
|
||||
#endif
|
||||
#include <asterisk/dsp.h>
|
||||
#ifndef CC_AST_NO_DEVICESTATE
|
||||
#include <asterisk/devicestate.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/dsp.h>
|
||||
#include "xlaw.h"
|
||||
#include "chan_capi20.h"
|
||||
#include "chan_capi.h"
|
||||
#include "chan_capi_rtp.h"
|
||||
#endif
|
||||
|
||||
#ifdef PBX_IS_OPBX
|
||||
#define CC_VERSION "cm-opbx-0.7"
|
||||
#else
|
||||
/* #define CC_VERSION "cm-x.y.z" */
|
||||
#define CC_VERSION "$Revision$"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* personal stuff
|
||||
*/
|
||||
static unsigned capi_ApplID = 0;
|
||||
unsigned capi_ApplID = 0;
|
||||
|
||||
static _cword capi_MessageNumber;
|
||||
static char *desc = "Common ISDN API for Asterisk";
|
||||
#ifdef PBX_IS_OPBX
|
||||
static char *ccdesc = "Common ISDN API for OpenPBX";
|
||||
#else
|
||||
static char *ccdesc = "Common ISDN API for Asterisk";
|
||||
#endif
|
||||
#ifdef CC_AST_HAVE_TECH_PVT
|
||||
static const char tdesc[] = "Common ISDN API Driver (" CC_VERSION ") " ASTERISKVERSION;
|
||||
static const char channeltype[] = "CAPI";
|
||||
|
@ -114,7 +160,7 @@ AST_MUTEX_DEFINE_STATIC(usecnt_lock);
|
|||
AST_MUTEX_DEFINE_STATIC(iflock);
|
||||
AST_MUTEX_DEFINE_STATIC(contrlock);
|
||||
AST_MUTEX_DEFINE_STATIC(capi_put_lock);
|
||||
AST_MUTEX_DEFINE_STATIC(verbose_lock);
|
||||
AST_MUTEX_DEFINE_EXPORTED(verbose_lock);
|
||||
|
||||
static int capi_capability = AST_FORMAT_ALAW;
|
||||
|
||||
|
@ -134,7 +180,7 @@ static char capi_international_prefix[AST_MAX_EXTENSION];
|
|||
|
||||
static char default_language[MAX_LANGUAGE] = "";
|
||||
|
||||
static int capidebug = 0;
|
||||
int capidebug = 0;
|
||||
|
||||
/* local prototypes */
|
||||
static int capi_indicate(struct ast_channel *c, int condition);
|
||||
|
@ -148,6 +194,39 @@ extern char *capi_info_string(unsigned int info);
|
|||
cc_verbose(4, 1, "CAPI: %s no interface for PLCI=%#x\n", x, PLCI); \
|
||||
return; \
|
||||
}
|
||||
|
||||
/*
|
||||
* B protocol settings
|
||||
*/
|
||||
#define CC_BPROTO_TRANSPARENT 0
|
||||
#define CC_BPROTO_FAXG3 1
|
||||
#define CC_BPROTO_RTP 2
|
||||
static struct {
|
||||
_cword b1protocol;
|
||||
_cword b2protocol;
|
||||
_cword b3protocol;
|
||||
_cstruct b1configuration;
|
||||
_cstruct b2configuration;
|
||||
_cstruct b3configuration;
|
||||
} b_protocol_table[] =
|
||||
{
|
||||
{ 0x01, 0x01, 0x00, /* 0 */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
{ 0x04, 0x04, 0x04, /* 1 */
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
},
|
||||
{ 0x1f, 0x1f, 0x1f, /* 2 */
|
||||
(_cstruct) "\x00",
|
||||
(_cstruct) "\x02\x01\x00",
|
||||
(_cstruct) "\x00"
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* command to string function
|
||||
*/
|
||||
|
@ -209,7 +288,7 @@ static void show_capi_info(_cword info)
|
|||
/*
|
||||
* get a new capi message number automically
|
||||
*/
|
||||
static _cword get_capi_MessageNumber(void)
|
||||
_cword get_capi_MessageNumber(void)
|
||||
{
|
||||
_cword mn;
|
||||
|
||||
|
@ -231,7 +310,7 @@ static _cword get_capi_MessageNumber(void)
|
|||
/*
|
||||
* write a capi message to capi device
|
||||
*/
|
||||
static MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG)
|
||||
MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG)
|
||||
{
|
||||
MESSAGE_EXCHANGE_ERROR error;
|
||||
|
||||
|
@ -720,6 +799,11 @@ static void interface_cleanup(struct capi_pvt *i)
|
|||
memset(i->dnid, 0, sizeof(i->dnid));
|
||||
i->cid_ton = 0;
|
||||
|
||||
i->rtpcodec = 0;
|
||||
if (i->rtp) {
|
||||
ast_rtp_destroy(i->rtp);
|
||||
}
|
||||
|
||||
i->owner = NULL;
|
||||
return;
|
||||
}
|
||||
|
@ -1057,9 +1141,12 @@ static int capi_call(struct ast_channel *c, char *idest, int timeout)
|
|||
CONNECT_REQ_CALLINGPARTYNUMBER(&CMSG) = (_cstruct)calling;
|
||||
CONNECT_REQ_CALLINGPARTYSUBADDRESS(&CMSG) = (_cstruct)osa;
|
||||
|
||||
CONNECT_REQ_B1PROTOCOL(&CMSG) = 1;
|
||||
CONNECT_REQ_B2PROTOCOL(&CMSG) = 1;
|
||||
CONNECT_REQ_B3PROTOCOL(&CMSG) = 0;
|
||||
CONNECT_REQ_B1PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b1protocol;
|
||||
CONNECT_REQ_B2PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b2protocol;
|
||||
CONNECT_REQ_B3PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b3protocol;
|
||||
CONNECT_REQ_B1CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b1configuration;
|
||||
CONNECT_REQ_B2CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b2configuration;
|
||||
CONNECT_REQ_B3CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b3configuration;
|
||||
|
||||
bchaninfo[0] = 2;
|
||||
bchaninfo[1] = 0x0;
|
||||
|
@ -1083,7 +1170,7 @@ static int capi_call(struct ast_channel *c, char *idest, int timeout)
|
|||
/*
|
||||
* answer a capi call
|
||||
*/
|
||||
static int capi_send_answer(struct ast_channel *c, int *bprot, _cstruct b3conf)
|
||||
static int capi_send_answer(struct ast_channel *c, _cstruct b3conf)
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
_cmsg CMSG;
|
||||
|
@ -1112,10 +1199,14 @@ static int capi_send_answer(struct ast_channel *c, int *bprot, _cstruct b3conf)
|
|||
strncpy(&buf[3], dnid, sizeof(buf) - 4);
|
||||
CONNECT_RESP_CONNECTEDNUMBER(&CMSG) = (_cstruct)buf;
|
||||
}
|
||||
CONNECT_RESP_B1PROTOCOL(&CMSG) = bprot[0];
|
||||
CONNECT_RESP_B2PROTOCOL(&CMSG) = bprot[1];
|
||||
CONNECT_RESP_B3PROTOCOL(&CMSG) = bprot[2];
|
||||
CONNECT_RESP_B3CONFIGURATION(&CMSG) = (_cstruct)b3conf;
|
||||
CONNECT_RESP_B1PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b1protocol;
|
||||
CONNECT_RESP_B2PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b2protocol;
|
||||
CONNECT_RESP_B3PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b3protocol;
|
||||
CONNECT_RESP_B1CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b1configuration;
|
||||
CONNECT_RESP_B2CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b2configuration;
|
||||
if (!b3conf)
|
||||
b3conf = b_protocol_table[i->bproto].b3configuration;
|
||||
CONNECT_RESP_B3CONFIGURATION(&CMSG) = b3conf;
|
||||
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Answering for %s\n",
|
||||
i->name, dnid);
|
||||
|
@ -1138,10 +1229,15 @@ static int capi_answer(struct ast_channel *c)
|
|||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
int ret;
|
||||
int bprot[3] = { 1, 1, 0 };
|
||||
|
||||
if (i->rtp) {
|
||||
i->bproto = CC_BPROTO_RTP;
|
||||
} else {
|
||||
i->bproto = CC_BPROTO_TRANSPARENT;
|
||||
}
|
||||
|
||||
cc_mutex_lock(&i->lock);
|
||||
ret = capi_send_answer(c, bprot, NULL);
|
||||
ret = capi_send_answer(c, NULL);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1149,7 +1245,7 @@ static int capi_answer(struct ast_channel *c)
|
|||
/*
|
||||
* PBX tells us to read for a channel
|
||||
*/
|
||||
struct ast_frame *capi_read(struct ast_channel *c)
|
||||
static struct ast_frame *capi_read(struct ast_channel *c)
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
int readsize = 0;
|
||||
|
@ -1209,7 +1305,7 @@ struct ast_frame *capi_read(struct ast_channel *c)
|
|||
/*
|
||||
* PBX tells us to write for a channel
|
||||
*/
|
||||
int capi_write(struct ast_channel *c, struct ast_frame *f)
|
||||
static int capi_write(struct ast_channel *c, struct ast_frame *f)
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
MESSAGE_EXCHANGE_ERROR error;
|
||||
|
@ -1218,6 +1314,7 @@ int capi_write(struct ast_channel *c, struct ast_frame *f)
|
|||
unsigned char *buf;
|
||||
struct ast_frame *fsmooth;
|
||||
int txavg=0;
|
||||
int ret = 0;
|
||||
|
||||
if (!i) {
|
||||
cc_log(LOG_ERROR, "channel has no interface\n");
|
||||
|
@ -1256,16 +1353,22 @@ int capi_write(struct ast_channel *c, struct ast_frame *f)
|
|||
cc_mutex_unlock(&i->lock);
|
||||
return 0;
|
||||
}
|
||||
if (f->subclass != capi_capability) {
|
||||
cc_log(LOG_ERROR, "dont know how to write subclass %d\n", f->subclass);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
return -1;
|
||||
}
|
||||
if ((!f->data) || (!f->datalen) || (!i->smoother)) {
|
||||
cc_log(LOG_ERROR, "No data for FRAME_VOICE %s\n", c->name);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
return 0;
|
||||
}
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_RTP) && (f->subclass & i->codec)) {
|
||||
ret = capi_write_rtp(c, f);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
return ret;
|
||||
}
|
||||
if (f->subclass != capi_capability) {
|
||||
cc_log(LOG_ERROR, "dont know how to write subclass %s(%d)\n",
|
||||
ast_getformatname(f->subclass), f->subclass);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_smoother_feed(i->smoother, f) != 0) {
|
||||
cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->name);
|
||||
|
@ -1281,7 +1384,8 @@ int capi_write(struct ast_channel *c, struct ast_frame *f)
|
|||
DATA_B3_REQ_FLAGS(&CMSG) = 0;
|
||||
|
||||
DATA_B3_REQ_DATAHANDLE(&CMSG) = i->send_buffer_handle;
|
||||
buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) * CAPI_MAX_B3_BLOCK_SIZE]);
|
||||
buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) *
|
||||
(CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)]);
|
||||
DATA_B3_REQ_DATA(&CMSG) = buf;
|
||||
i->send_buffer_handle++;
|
||||
|
||||
|
@ -1411,7 +1515,8 @@ static int line_interconnect(struct capi_pvt *i0, struct capi_pvt *i1, int start
|
|||
*/
|
||||
static CC_BRIDGE_RETURN capi_bridge(struct ast_channel *c0,
|
||||
struct ast_channel *c1,
|
||||
int flags, struct ast_frame **fo, struct ast_channel **rc
|
||||
int flags, struct ast_frame **fo,
|
||||
struct ast_channel **rc
|
||||
#ifdef CC_AST_BRIDGE_WITH_TIMEOUTMS
|
||||
, int timeoutms
|
||||
#endif
|
||||
|
@ -1583,8 +1688,22 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
|
|||
CC_CHANNEL_PVT(tmp) = i;
|
||||
|
||||
tmp->callgroup = i->callgroup;
|
||||
|
||||
tmp->nativeformats = capi_capability;
|
||||
i->bproto = CC_BPROTO_TRANSPARENT;
|
||||
if ((i->rtpcodec = (capi_controllers[i->controller]->rtpcodec & i->capability))) {
|
||||
if (capi_alloc_rtp(i)) {
|
||||
/* error on rtp alloc */
|
||||
i->rtpcodec = 0;
|
||||
} else {
|
||||
/* start with rtp */
|
||||
tmp->nativeformats = i->rtpcodec;
|
||||
i->bproto = CC_BPROTO_RTP;
|
||||
i->isdnstate |= CAPI_ISDN_STATE_RTP;
|
||||
}
|
||||
}
|
||||
fmt = ast_best_codec(tmp->nativeformats);
|
||||
i->codec = fmt;
|
||||
tmp->readformat = fmt;
|
||||
tmp->writeformat = fmt;
|
||||
|
||||
|
@ -1605,6 +1724,11 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
|
|||
tmp->pvt->rawreadformat = fmt;
|
||||
tmp->pvt->rawwriteformat = fmt;
|
||||
#endif
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: setting format %s - %s%s\n",
|
||||
i->name, ast_getformatname(fmt),
|
||||
ast_getformatname_multiple(alloca(80), 80,
|
||||
tmp->nativeformats),
|
||||
(i->rtp) ? " (RTP)" : "");
|
||||
cc_copy_string(tmp->context, i->context, sizeof(tmp->context));
|
||||
#ifdef CC_AST_CHANNEL_HAS_CID
|
||||
if (!ast_strlen_zero(i->cid))
|
||||
|
@ -1637,16 +1761,17 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
|
|||
* PBX wants us to dial ...
|
||||
*/
|
||||
#ifdef CC_AST_HAVE_TECH_PVT
|
||||
struct ast_channel *capi_request(const char *type, int format, void *data, int *cause)
|
||||
static struct ast_channel *capi_request(const char *type, int format, void *data, int *cause)
|
||||
#else
|
||||
struct ast_channel *capi_request(char *type, int format, void *data)
|
||||
static struct ast_channel *capi_request(char *type, int format, void *data)
|
||||
#endif
|
||||
{
|
||||
struct capi_pvt *i;
|
||||
struct ast_channel *tmp = NULL;
|
||||
char *dest, *interface, *param, *ocid;
|
||||
char buffer[CAPI_MAX_STRING];
|
||||
unsigned int capigroup = 0, controller = 0;
|
||||
ast_group_t capigroup = 0;
|
||||
unsigned int controller = 0;
|
||||
unsigned int foundcontroller;
|
||||
int notfound = 1;
|
||||
|
||||
|
@ -1666,7 +1791,7 @@ struct ast_channel *capi_request(char *type, int format, void *data)
|
|||
if (interface[0] == 'g') {
|
||||
capigroup = ast_get_group(interface + 1);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "capi request group = %d\n",
|
||||
capigroup);
|
||||
(unsigned int)capigroup);
|
||||
} else if (!strncmp(interface, "contr", 5)) {
|
||||
controller = atoi(interface + 5);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "capi request controller = %d\n",
|
||||
|
@ -1791,11 +1916,11 @@ static void capi_change_bchan_fax(struct ast_channel *c, B3_PROTO_FAXG3 *b3conf)
|
|||
|
||||
SELECT_B_PROTOCOL_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
SELECT_B_PROTOCOL_REQ_PLCI(&CMSG) = i->PLCI;
|
||||
SELECT_B_PROTOCOL_REQ_B1PROTOCOL(&CMSG) = 4;
|
||||
SELECT_B_PROTOCOL_REQ_B2PROTOCOL(&CMSG) = 4;
|
||||
SELECT_B_PROTOCOL_REQ_B3PROTOCOL(&CMSG) = 4;
|
||||
SELECT_B_PROTOCOL_REQ_B1CONFIGURATION(&CMSG) = NULL;
|
||||
SELECT_B_PROTOCOL_REQ_B2CONFIGURATION(&CMSG) = NULL;
|
||||
SELECT_B_PROTOCOL_REQ_B1PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b1protocol;
|
||||
SELECT_B_PROTOCOL_REQ_B2PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b2protocol;
|
||||
SELECT_B_PROTOCOL_REQ_B3PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b3protocol;
|
||||
SELECT_B_PROTOCOL_REQ_B1CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b1configuration;
|
||||
SELECT_B_PROTOCOL_REQ_B2CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b2configuration;
|
||||
SELECT_B_PROTOCOL_REQ_B3CONFIGURATION(&CMSG) = (_cstruct)b3conf;
|
||||
_capi_put_cmsg(&CMSG);
|
||||
|
||||
|
@ -1810,7 +1935,6 @@ static int capi_receive_fax(struct ast_channel *c, char *data)
|
|||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
int res = 0;
|
||||
char *filename, *stationid, *headline;
|
||||
int bprot[3] = { 4, 4, 4 };
|
||||
B3_PROTO_FAXG3 b3conf;
|
||||
|
||||
if (!data) { /* no data implies no filename or anything is present */
|
||||
|
@ -1838,11 +1962,13 @@ static int capi_receive_fax(struct ast_channel *c, char *data)
|
|||
i->FaxState = 1;
|
||||
setup_b3_fax_config(&b3conf, FAX_SFF_FORMAT, stationid, headline);
|
||||
|
||||
i->bproto = CC_BPROTO_FAXG3;
|
||||
|
||||
switch (i->state) {
|
||||
case CAPI_STATE_ALERTING:
|
||||
case CAPI_STATE_DID:
|
||||
case CAPI_STATE_INCALL:
|
||||
capi_send_answer(c, bprot, (_cstruct)&b3conf);
|
||||
capi_send_answer(c, (_cstruct)&b3conf);
|
||||
cc_mutex_unlock(&i->lock);
|
||||
break;
|
||||
case CAPI_STATE_CONNECTED:
|
||||
|
@ -2079,6 +2205,7 @@ static void start_b3(struct capi_pvt *i)
|
|||
i->isdnstate |= CAPI_ISDN_STATE_B3_PEND;
|
||||
CONNECT_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
CONNECT_B3_REQ_PLCI(&CMSG) = i->PLCI;
|
||||
CONNECT_B3_REQ_NCPI(&CMSG) = capi_rtp_ncpi(i);
|
||||
_capi_put_cmsg(&CMSG);
|
||||
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: sent CONNECT_B3_REQ PLCI=%#x\n",
|
||||
i->name, i->PLCI);
|
||||
|
@ -2086,7 +2213,7 @@ static void start_b3(struct capi_pvt *i)
|
|||
}
|
||||
|
||||
/*
|
||||
* send CONNECT_B3_REQ for early B3
|
||||
* start early B3
|
||||
*/
|
||||
static void start_early_b3(struct capi_pvt *i)
|
||||
{
|
||||
|
@ -2448,12 +2575,6 @@ static void capi_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned
|
|||
case 0x0028: /* DSP */
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element DSP\n",
|
||||
i->name);
|
||||
#if 0
|
||||
struct ast_frame ft = { AST_FRAME_TEXT, capi_number(INFO_IND_INFOELEMENT(CMSG),0), };
|
||||
ast_sendtext(i->owner,capi_number(INFO_IND_INFOELEMENT(CMSG), 0));
|
||||
ast_queue_frame(i->owner, &ft);
|
||||
cc_log(LOG_NOTICE,"%s\n",capi_number(INFO_IND_INFOELEMENT(CMSG),0));
|
||||
#endif
|
||||
break;
|
||||
case 0x0029: /* Date/Time */
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element Date/Time %02d/%02d/%02d %02d:%02d\n",
|
||||
|
@ -2661,15 +2782,6 @@ static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsi
|
|||
|
||||
if (FACILITY_IND_FACILITYSELECTOR(CMSG) == FACILITYSELECTOR_SUPPLEMENTARY) {
|
||||
/* supplementary sservices */
|
||||
#if 0
|
||||
cc_log(LOG_NOTICE,"FACILITY_IND PLCI = %#x\n",PLCI);
|
||||
cc_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0]);
|
||||
cc_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]);
|
||||
cc_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[2]);
|
||||
cc_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3]);
|
||||
cc_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[4]);
|
||||
cc_log(LOG_NOTICE,"%#x\n",FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[5]);
|
||||
#endif
|
||||
/* ECT */
|
||||
if ( (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x6) &&
|
||||
(FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3] == 0x2) ) {
|
||||
|
@ -2736,10 +2848,12 @@ static void capi_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
int j;
|
||||
int rxavg = 0;
|
||||
int txavg = 0;
|
||||
int rtpoffset = 0;
|
||||
|
||||
if (i != NULL) {
|
||||
if (i->isdnstate & CAPI_ISDN_STATE_RTP) rtpoffset = 12;
|
||||
b3len = DATA_B3_IND_DATALENGTH(CMSG);
|
||||
b3buf = &(i->rec_buffer[AST_FRIENDLY_OFFSET]);
|
||||
b3buf = &(i->rec_buffer[AST_FRIENDLY_OFFSET - rtpoffset]);
|
||||
memcpy(b3buf, (char *)DATA_B3_IND_DATA(CMSG), b3len);
|
||||
}
|
||||
|
||||
|
@ -2760,7 +2874,14 @@ static void capi_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
i->name, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (i->isdnstate & CAPI_ISDN_STATE_RTP) {
|
||||
struct ast_frame *f = capi_read_rtp(i, b3buf, b3len);
|
||||
if (f)
|
||||
pipe_frame(i, f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (i->B3q < 800) {
|
||||
i->B3q += b3len;
|
||||
}
|
||||
|
@ -2992,6 +3113,7 @@ static void capi_handle_connect_b3_indication(_cmsg *CMSG, unsigned int PLCI, un
|
|||
CONNECT_B3_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), 0);
|
||||
CONNECT_B3_RESP_NCCI(&CMSG2) = NCCI;
|
||||
CONNECT_B3_RESP_REJECT(&CMSG2) = 0;
|
||||
CONNECT_B3_RESP_NCPI(&CMSG2) = capi_rtp_ncpi(i);
|
||||
_capi_put_cmsg(&CMSG2);
|
||||
|
||||
return_on_no_interface("CONNECT_B3_IND");
|
||||
|
@ -3760,7 +3882,7 @@ static int capi_ect(struct ast_channel *c, char *param)
|
|||
|
||||
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
FACILITY_REQ_CONTROLLER(&CMSG) = i->controller;
|
||||
FACILITY_REQ_PLCI(&CMSG) = plci;
|
||||
FACILITY_REQ_PLCI(&CMSG) = plci; /* implicit ECT */
|
||||
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_SUPPLEMENTARY;
|
||||
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac;
|
||||
|
||||
|
@ -3942,12 +4064,12 @@ static int capi_signal_progress(struct ast_channel *c, char *param)
|
|||
|
||||
SELECT_B_PROTOCOL_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
SELECT_B_PROTOCOL_REQ_PLCI(&CMSG) = i->PLCI;
|
||||
SELECT_B_PROTOCOL_REQ_B1PROTOCOL(&CMSG) = 1;
|
||||
SELECT_B_PROTOCOL_REQ_B2PROTOCOL(&CMSG) = 1;
|
||||
SELECT_B_PROTOCOL_REQ_B3PROTOCOL(&CMSG) = 0;
|
||||
SELECT_B_PROTOCOL_REQ_B1CONFIGURATION(&CMSG) = NULL;
|
||||
SELECT_B_PROTOCOL_REQ_B2CONFIGURATION(&CMSG) = NULL;
|
||||
SELECT_B_PROTOCOL_REQ_B3CONFIGURATION(&CMSG) = NULL;
|
||||
SELECT_B_PROTOCOL_REQ_B1PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b1protocol;
|
||||
SELECT_B_PROTOCOL_REQ_B2PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b2protocol;
|
||||
SELECT_B_PROTOCOL_REQ_B3PROTOCOL(&CMSG) = b_protocol_table[i->bproto].b3protocol;
|
||||
SELECT_B_PROTOCOL_REQ_B1CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b1configuration;
|
||||
SELECT_B_PROTOCOL_REQ_B2CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b2configuration;
|
||||
SELECT_B_PROTOCOL_REQ_B3CONFIGURATION(&CMSG) = b_protocol_table[i->bproto].b3configuration;
|
||||
|
||||
_capi_put_cmsg(&CMSG);
|
||||
|
||||
|
@ -4257,7 +4379,7 @@ int mkif(struct cc_capi_conf *conf)
|
|||
}
|
||||
memset(tmp, 0, sizeof(struct capi_pvt));
|
||||
|
||||
ast_mutex_init(&tmp->lock);
|
||||
cc_mutex_init(&tmp->lock);
|
||||
|
||||
if (i == 0) {
|
||||
snprintf(tmp->name, sizeof(tmp->name) - 1, "%s-pseudo-D", conf->name);
|
||||
|
@ -4323,6 +4445,7 @@ int mkif(struct cc_capi_conf *conf)
|
|||
capi_gains(&tmp->g, conf->rxgain, conf->txgain);
|
||||
|
||||
tmp->doDTMF = conf->softdtmf;
|
||||
tmp->capability = conf->capability;
|
||||
|
||||
tmp->next = iflist; /* prepend */
|
||||
iflist = tmp;
|
||||
|
@ -4347,7 +4470,7 @@ static void supported_sservices(struct cc_capi_controller *cp)
|
|||
MESSAGE_EXCHANGE_ERROR error;
|
||||
_cmsg CMSG, CMSG2;
|
||||
struct timeval tv;
|
||||
char fac[20];
|
||||
unsigned char fac[20];
|
||||
unsigned int services;
|
||||
|
||||
memset(fac, 0, sizeof(fac));
|
||||
|
@ -4390,50 +4513,52 @@ static void supported_sservices(struct cc_capi_controller *cp)
|
|||
services);
|
||||
|
||||
/* success, so set the features we have */
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 " ");
|
||||
if (services & 0x0001) {
|
||||
cp->holdretrieve = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "HOLD/RETRIEVE\n");
|
||||
cc_verbose(3, 0, "HOLD/RETRIEVE ");
|
||||
}
|
||||
if (services & 0x0002) {
|
||||
cp->terminalportability = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "TERMINAL PORTABILITY\n");
|
||||
cc_verbose(3, 0, "TERMINAL-PORTABILITY ");
|
||||
}
|
||||
if (services & 0x0004) {
|
||||
cp->ECT = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "ECT\n");
|
||||
cc_verbose(3, 0, "ECT ");
|
||||
}
|
||||
if (services & 0x0008) {
|
||||
cp->threePTY = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "3PTY\n");
|
||||
cc_verbose(3, 0, "3PTY ");
|
||||
}
|
||||
if (services & 0x0010) {
|
||||
cp->CF = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "CF\n");
|
||||
cc_verbose(3, 0, "CF ");
|
||||
}
|
||||
if (services & 0x0020) {
|
||||
cp->CD = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "CD\n");
|
||||
cc_verbose(3, 0, "CD ");
|
||||
}
|
||||
if (services & 0x0040) {
|
||||
cp->MCID = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "MCID\n");
|
||||
cc_verbose(3, 0, "MCID ");
|
||||
}
|
||||
if (services & 0x0080) {
|
||||
cp->CCBS = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "CCBS\n");
|
||||
cc_verbose(3, 0, "CCBS ");
|
||||
}
|
||||
if (services & 0x0100) {
|
||||
cp->MWI = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "MWI\n");
|
||||
cc_verbose(3, 0, "MWI ");
|
||||
}
|
||||
if (services & 0x0200) {
|
||||
cp->CCNR = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "CCNR\n");
|
||||
cc_verbose(3, 0, "CCNR ");
|
||||
}
|
||||
if (services & 0x0400) {
|
||||
cp->CONF = 1;
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "CONF\n");
|
||||
cc_verbose(3, 0, "CONF");
|
||||
}
|
||||
cc_verbose(3, 0, "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4547,6 +4672,7 @@ static int cc_init_capi(void)
|
|||
#endif
|
||||
struct cc_capi_controller *cp;
|
||||
int controller;
|
||||
unsigned int privateoptions;
|
||||
|
||||
if (capi20_isinstalled() != 0) {
|
||||
cc_log(LOG_WARNING, "CAPI not installed, CAPI disabled!\n");
|
||||
|
@ -4645,6 +4771,18 @@ static int cc_init_capi(void)
|
|||
supported_sservices(cp);
|
||||
}
|
||||
|
||||
/* New profile options for e.g. RTP with Eicon DIVA */
|
||||
privateoptions = read_capi_dword(&profile.manufacturer[0]);
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_3 "CAPI/contr%d private options=0x%08x\n",
|
||||
controller, privateoptions);
|
||||
if (privateoptions & 0x02) {
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "VoIP/RTP is supported\n");
|
||||
voice_over_ip_profile(cp);
|
||||
}
|
||||
if (privateoptions & 0x04) {
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "T.38 is supported\n");
|
||||
}
|
||||
|
||||
capi_controllers[controller] = cp;
|
||||
}
|
||||
return 0;
|
||||
|
@ -4684,38 +4822,36 @@ static int conf_interface(struct cc_capi_conf *conf, struct ast_variable *v)
|
|||
if (!strcasecmp(v->name, token)) { \
|
||||
cc_copy_string(var, v->value, sizeof(var)); \
|
||||
continue; \
|
||||
}
|
||||
} else
|
||||
#define CONF_INTEGER(var, token) \
|
||||
if (!strcasecmp(v->name, token)) { \
|
||||
var = atoi(v->value); \
|
||||
continue; \
|
||||
}
|
||||
} else
|
||||
#define CONF_TRUE(var, token, val) \
|
||||
if (!strcasecmp(v->name, token)) { \
|
||||
if (ast_true(v->value)) \
|
||||
var = val; \
|
||||
continue; \
|
||||
}
|
||||
|
||||
} else
|
||||
|
||||
for (; v; v = v->next) {
|
||||
CONF_INTEGER(conf->devices, "devices");
|
||||
CONF_STRING(conf->context, "context");
|
||||
CONF_STRING(conf->incomingmsn, "incomingmsn");
|
||||
CONF_STRING(conf->defaultcid, "defaultcid");
|
||||
CONF_STRING(conf->controllerstr, "controller");
|
||||
CONF_STRING(conf->prefix, "prefix");
|
||||
CONF_STRING(conf->accountcode, "accountcode");
|
||||
CONF_STRING(conf->language, "language");
|
||||
CONF_INTEGER(conf->devices, "devices")
|
||||
CONF_STRING(conf->context, "context")
|
||||
CONF_STRING(conf->incomingmsn, "incomingmsn")
|
||||
CONF_STRING(conf->defaultcid, "defaultcid")
|
||||
CONF_STRING(conf->controllerstr, "controller")
|
||||
CONF_STRING(conf->prefix, "prefix")
|
||||
CONF_STRING(conf->accountcode, "accountcode")
|
||||
CONF_STRING(conf->language, "language")
|
||||
|
||||
if (!strcasecmp(v->name, "softdtmf")) {
|
||||
if ((!conf->softdtmf) && (ast_true(v->value))) {
|
||||
conf->softdtmf = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
CONF_TRUE(conf->softdtmf, "relaxdtmf", 2);
|
||||
|
||||
} else
|
||||
CONF_TRUE(conf->softdtmf, "relaxdtmf", 2)
|
||||
if (!strcasecmp(v->name, "holdtype")) {
|
||||
if (!strcasecmp(v->value, "hold")) {
|
||||
conf->holdtype = CC_HOLDTYPE_HOLD;
|
||||
|
@ -4725,39 +4861,37 @@ static int conf_interface(struct cc_capi_conf *conf, struct ast_variable *v)
|
|||
conf->holdtype = CC_HOLDTYPE_LOCAL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
CONF_TRUE(conf->immediate, "immediate", 1);
|
||||
CONF_TRUE(conf->es, "echosquelch", 1);
|
||||
CONF_TRUE(conf->bridge, "bridge", 1);
|
||||
CONF_TRUE(conf->ntmode, "ntmode", 1);
|
||||
|
||||
} else
|
||||
CONF_TRUE(conf->immediate, "immediate", 1)
|
||||
CONF_TRUE(conf->es, "echosquelch", 1)
|
||||
CONF_TRUE(conf->bridge, "bridge", 1)
|
||||
CONF_TRUE(conf->ntmode, "ntmode", 1)
|
||||
if (!strcasecmp(v->name, "callgroup")) {
|
||||
conf->callgroup = ast_get_group(v->value);
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcasecmp(v->name, "group")) {
|
||||
conf->group = ast_get_group(v->value);
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcasecmp(v->name, "rxgain")) {
|
||||
if (sscanf(v->value, "%f", &conf->rxgain) != 1) {
|
||||
cc_log(LOG_ERROR,"invalid rxgain\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcasecmp(v->name, "txgain")) {
|
||||
if (sscanf(v->value, "%f", &conf->txgain) != 1) {
|
||||
cc_log(LOG_ERROR, "invalid txgain\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcasecmp(v->name, "echocancelold")) {
|
||||
if (ast_true(v->value)) {
|
||||
conf->ecSelector = 6;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcasecmp(v->name, "echocancel")) {
|
||||
if (ast_true(v->value)) {
|
||||
conf->echocancel = 1;
|
||||
|
@ -4783,14 +4917,14 @@ static int conf_interface(struct cc_capi_conf *conf, struct ast_variable *v)
|
|||
cc_log(LOG_ERROR,"Unknown echocancel parameter \"%s\" -- ignoring\n",v->value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcasecmp(v->name, "echotail")) {
|
||||
conf->ectail = atoi(v->value);
|
||||
if (conf->ectail > 255) {
|
||||
conf->ectail = 255;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
if (!strcasecmp(v->name, "isdnmode")) {
|
||||
if (!strcasecmp(v->value, "did"))
|
||||
conf->isdnmode = CAPI_ISDNMODE_DID;
|
||||
|
@ -4799,6 +4933,12 @@ static int conf_interface(struct cc_capi_conf *conf, struct ast_variable *v)
|
|||
else
|
||||
cc_log(LOG_ERROR,"Unknown isdnmode parameter \"%s\" -- ignoring\n",
|
||||
v->value);
|
||||
} else
|
||||
if (!strcasecmp(v->name, "allow")) {
|
||||
ast_parse_allow_disallow(&conf->prefs, &conf->capability, v->value, 1);
|
||||
} else
|
||||
if (!strcasecmp(v->name, "disallow")) {
|
||||
ast_parse_allow_disallow(&conf->prefs, &conf->capability, v->value, 0);
|
||||
}
|
||||
}
|
||||
#undef CONF_STRING
|
||||
|
@ -5082,12 +5222,12 @@ int usecount()
|
|||
|
||||
char *description()
|
||||
{
|
||||
return desc;
|
||||
return ccdesc;
|
||||
}
|
||||
|
||||
|
||||
#ifndef PBX_IS_OPBX
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
138
chan_capi.h
138
chan_capi.h
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for Asterisk
|
||||
* An implementation of Common ISDN API 2.0 for
|
||||
* Asterisk / OpenPBX.org
|
||||
*
|
||||
* Copyright (C) 2005 Cytronics & Melware
|
||||
* Copyright (C) 2005-2006 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
|
@ -16,8 +17,8 @@
|
|||
* distributed under the terms of the GNU Public License.
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_CAPI_H
|
||||
#define _ASTERISK_CAPI_H
|
||||
#ifndef _PBX_CAPI_H
|
||||
#define _PBX_CAPI_H
|
||||
|
||||
#define CAPI_MAX_CONTROLLERS 16
|
||||
#define CAPI_MAX_B3_BLOCKS 7
|
||||
|
@ -25,7 +26,7 @@
|
|||
/* was : 130 bytes Alaw = 16.25 ms audio not suitable for VoIP */
|
||||
/* now : 160 bytes Alaw = 20 ms audio */
|
||||
/* you can tune this to your need. higher value == more latency */
|
||||
#define CAPI_MAX_B3_BLOCK_SIZE 160
|
||||
#define CAPI_MAX_B3_BLOCK_SIZE 172 /* 160 + RTP-Header */
|
||||
|
||||
#define CAPI_BCHANS 120
|
||||
#define ALL_SERVICES 0x1FFF03FF
|
||||
|
@ -33,20 +34,6 @@
|
|||
#define CAPI_ISDNMODE_MSN 0
|
||||
#define CAPI_ISDNMODE_DID 1
|
||||
|
||||
/*
|
||||
* helper for ast_verbose with different verbose settings
|
||||
*/
|
||||
#define cc_verbose(o_v, c_d, text...) \
|
||||
do { \
|
||||
if ((o_v == 0) || (option_verbose > o_v)) { \
|
||||
if ((!c_d) || ((c_d) && (capidebug))) { \
|
||||
ast_mutex_lock(&verbose_lock); \
|
||||
ast_verbose(text); \
|
||||
ast_mutex_unlock(&verbose_lock); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* some helper functions */
|
||||
static inline void write_capi_word(void *m, unsigned short val)
|
||||
{
|
||||
|
@ -77,12 +64,57 @@ static inline unsigned int read_capi_dword(void *m)
|
|||
}
|
||||
|
||||
/*
|
||||
* PBX defines
|
||||
* define some private functions
|
||||
*/
|
||||
#define cc_mutex_lock(x) ast_mutex_lock(x)
|
||||
#define cc_mutex_unlock(x) ast_mutex_unlock(x)
|
||||
#define cc_log(x...) ast_log(x)
|
||||
#define cc_copy_string(dst, src, size) ast_copy_string(dst, src, size)
|
||||
#ifdef PBX_IS_OPBX
|
||||
#define cc_mutex_t opbx_mutex_t
|
||||
#define cc_mutex_init opbx_mutex_init
|
||||
#define cc_mutex_lock(x) opbx_mutex_lock(x)
|
||||
#define cc_mutex_unlock(x) opbx_mutex_unlock(x)
|
||||
#define cc_copy_string(dst, src, size) opbx_copy_string(dst, src, size)
|
||||
#define cc_log(x...) opbx_log(x)
|
||||
#define cc_pbx_verbose(x...) opbx_verbose(x)
|
||||
#else
|
||||
#define cc_mutex_t ast_mutex_t
|
||||
#define cc_mutex_init ast_mutex_init
|
||||
#define cc_mutex_lock(x) ast_mutex_lock(x)
|
||||
#define cc_mutex_unlock(x) ast_mutex_unlock(x)
|
||||
#ifdef CC_AST_NO_STRINGS
|
||||
#define cc_copy_string(dst, src, size) strncpy(dst, src, size -1)
|
||||
#else
|
||||
#define cc_copy_string(dst, src, size) ast_copy_string(dst, src, size)
|
||||
#endif
|
||||
#define cc_log(x...) ast_log(x)
|
||||
#define cc_pbx_verbose(x...) ast_verbose(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* helper for <pbx>_verbose with different verbose settings
|
||||
*/
|
||||
#define cc_verbose(o_v, c_d, text...) \
|
||||
do { \
|
||||
if ((o_v == 0) || (option_verbose > o_v)) { \
|
||||
if ((!c_d) || ((c_d) && (capidebug))) { \
|
||||
cc_mutex_lock(&verbose_lock); \
|
||||
cc_pbx_verbose(text); \
|
||||
cc_mutex_unlock(&verbose_lock); \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#ifdef PBX_IS_OPBX
|
||||
#define CC_CHANNEL_PVT(c) (c)->tech_pvt
|
||||
#else
|
||||
#ifndef AST_MUTEX_DEFINE_STATIC
|
||||
#define AST_MUTEX_DEFINE_STATIC(mutex) \
|
||||
static cc_mutex_t mutex = AST_MUTEX_INITIALIZER
|
||||
#endif
|
||||
|
||||
#ifndef AST_MUTEX_DEFINE_EXPORTED
|
||||
#define AST_MUTEX_DEFINE_EXPORTED(mutex) \
|
||||
cc_mutex_t mutex = AST_MUTEX_INITIALIZER
|
||||
#endif
|
||||
|
||||
/*
|
||||
* definitions for compatibility with older versions of ast*
|
||||
|
@ -93,12 +125,6 @@ static inline unsigned int read_capi_dword(void *m)
|
|||
#define CC_CHANNEL_PVT(c) (c)->pvt->pvt
|
||||
#endif
|
||||
|
||||
#ifdef CC_AST_HAS_BRIDGED_CHANNEL
|
||||
#define CC_AST_BRIDGED_CHANNEL(x) ast_bridged_channel(x)
|
||||
#else
|
||||
#define CC_AST_BRIDGED_CHANNEL(x) (x)->bridge
|
||||
#endif
|
||||
|
||||
#ifdef CC_AST_HAS_BRIDGE_RESULT
|
||||
#define CC_BRIDGE_RETURN enum ast_bridge_result
|
||||
#else
|
||||
|
@ -109,10 +135,19 @@ static inline unsigned int read_capi_dword(void *m)
|
|||
#define AST_BRIDGE_RETRY -3
|
||||
#endif
|
||||
|
||||
#ifndef AST_MUTEX_DEFINE_STATIC
|
||||
#define AST_MUTEX_DEFINE_STATIC(mutex) \
|
||||
static ast_mutex_t mutex = AST_MUTEX_INITIALIZER
|
||||
#ifndef CC_AST_GROUP_T
|
||||
#define ast_group_t unsigned int
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* prototypes
|
||||
*/
|
||||
extern unsigned capi_ApplID;
|
||||
extern cc_mutex_t verbose_lock;
|
||||
extern int capidebug;
|
||||
extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG);
|
||||
extern _cword get_capi_MessageNumber(void);
|
||||
|
||||
/* FAX Resolutions */
|
||||
#define FAX_STANDARD_RESOLUTION 0
|
||||
|
@ -148,10 +183,12 @@ typedef struct fax3proto3 B3_PROTO_FAXG3;
|
|||
#define ECHO_EFFECTIVE_TX_COUNT 3 /* 2 x 20ms = 40ms == 40-100ms ... ignore first 40ms */
|
||||
#define ECHO_TXRX_RATIO 2.3 /* if( rx < (txavg/ECHO_TXRX_RATIO) ) rx=0; */
|
||||
|
||||
#define FACILITYSELECTOR_DTMF 1
|
||||
#define FACILITYSELECTOR_SUPPLEMENTARY 3
|
||||
#define FACILITYSELECTOR_LINE_INTERCONNECT 5
|
||||
#define FACILITYSELECTOR_ECHO_CANCEL 8
|
||||
#define FACILITYSELECTOR_DTMF 0x0001
|
||||
#define FACILITYSELECTOR_SUPPLEMENTARY 0x0003
|
||||
#define FACILITYSELECTOR_LINE_INTERCONNECT 0x0005
|
||||
#define FACILITYSELECTOR_ECHO_CANCEL 0x0008
|
||||
#define FACILITYSELECTOR_FAX_OVER_IP 0x00fd
|
||||
#define FACILITYSELECTOR_VOICE_OVER_IP 0x00fe
|
||||
|
||||
#define CC_HOLDTYPE_LOCAL 0
|
||||
#define CC_HOLDTYPE_HOLD 1
|
||||
|
@ -199,6 +236,7 @@ struct cc_capi_gains {
|
|||
#define CAPI_ISDN_STATE_DID 0x00000080
|
||||
#define CAPI_ISDN_STATE_B3_PEND 0x00000100
|
||||
#define CAPI_ISDN_STATE_B3_UP 0x00000200
|
||||
#define CAPI_ISDN_STATE_RTP 0x00000400
|
||||
#define CAPI_ISDN_STATE_PBX 0x80000000
|
||||
|
||||
#define CAPI_CHANNELTYPE_B 0
|
||||
|
@ -206,7 +244,7 @@ struct cc_capi_gains {
|
|||
|
||||
/* ! Private data for a capi device */
|
||||
struct capi_pvt {
|
||||
ast_mutex_t lock;
|
||||
cc_mutex_t lock;
|
||||
int fd;
|
||||
int fd2;
|
||||
|
||||
|
@ -228,7 +266,8 @@ struct capi_pvt {
|
|||
unsigned long controllers;
|
||||
|
||||
/* send buffer */
|
||||
unsigned char send_buffer[CAPI_MAX_B3_BLOCKS * CAPI_MAX_B3_BLOCK_SIZE];
|
||||
unsigned char send_buffer[CAPI_MAX_B3_BLOCKS *
|
||||
(CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)];
|
||||
unsigned short send_buffer_handle;
|
||||
|
||||
/* receive buffer */
|
||||
|
@ -240,6 +279,9 @@ struct capi_pvt {
|
|||
/* the state of the line */
|
||||
unsigned int isdnstate;
|
||||
int cause;
|
||||
|
||||
/* which b-protocol is active */
|
||||
int bproto;
|
||||
|
||||
char context[AST_MAX_EXTENSION];
|
||||
/*! Multiple Subscriber Number we listen to (, seperated list) */
|
||||
|
@ -258,8 +300,8 @@ struct capi_pvt {
|
|||
|
||||
char accountcode[20];
|
||||
|
||||
unsigned int callgroup;
|
||||
unsigned int group;
|
||||
ast_group_t callgroup;
|
||||
ast_group_t group;
|
||||
|
||||
/* language */
|
||||
char language[MAX_LANGUAGE];
|
||||
|
@ -329,6 +371,12 @@ struct capi_pvt {
|
|||
unsigned int reason;
|
||||
unsigned int reasonb3;
|
||||
|
||||
/* RTP */
|
||||
struct ast_rtp *rtp;
|
||||
int capability;
|
||||
int rtpcodec;
|
||||
int codec;
|
||||
|
||||
/*! Next channel in list */
|
||||
struct capi_pvt *next;
|
||||
};
|
||||
|
@ -368,10 +416,12 @@ struct cc_capi_conf {
|
|||
int holdtype;
|
||||
int es;
|
||||
int bridge;
|
||||
unsigned int callgroup;
|
||||
unsigned int group;
|
||||
ast_group_t callgroup;
|
||||
ast_group_t group;
|
||||
float rxgain;
|
||||
float txgain;
|
||||
struct ast_codec_pref prefs;
|
||||
int capability;
|
||||
};
|
||||
|
||||
struct cc_capi_controller {
|
||||
|
@ -398,6 +448,8 @@ struct cc_capi_controller {
|
|||
int MWI;
|
||||
int CCNR;
|
||||
int CONF;
|
||||
/* RTP */
|
||||
int rtpcodec;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for
|
||||
* Asterisk / OpenPBX.org
|
||||
*
|
||||
* Copyright (C) 2006 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* This program is free software and may be modified and
|
||||
* distributed under the terms of the GNU Public License.
|
||||
*/
|
||||
#ifdef PBX_IS_OPBX
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "confdefs.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef PBX_IS_OPBX
|
||||
#include "openpbx/lock.h"
|
||||
#include "openpbx/frame.h"
|
||||
#include "openpbx/channel.h"
|
||||
#include "openpbx/logger.h"
|
||||
#include "openpbx/module.h"
|
||||
#include "openpbx/pbx.h"
|
||||
#include "openpbx/config.h"
|
||||
#include "openpbx/options.h"
|
||||
#include "openpbx/features.h"
|
||||
#include "openpbx/utils.h"
|
||||
#include "openpbx/rtp.h"
|
||||
#include "openpbx/strings.h"
|
||||
#include "openpbx/chan_capi20.h"
|
||||
#include "openpbx/chan_capi.h"
|
||||
#include "openpbx/chan_capi_rtp.h"
|
||||
#else
|
||||
#include "config.h"
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/channel.h>
|
||||
#ifndef CC_AST_HAVE_TECH_PVT
|
||||
#include <asterisk/channel_pvt.h>
|
||||
#endif
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/features.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/rtp.h>
|
||||
#ifndef CC_AST_NO_STRINGS
|
||||
#include <asterisk/strings.h>
|
||||
#endif
|
||||
#include "chan_capi20.h"
|
||||
#include "chan_capi.h"
|
||||
#include "chan_capi_rtp.h"
|
||||
#endif
|
||||
|
||||
/* RTP settings / NCPI RTP struct */
|
||||
|
||||
static unsigned char NCPI_voice_over_ip_alaw[] =
|
||||
/* Len Options */
|
||||
"\x27\x00\x00\x00\x00"
|
||||
/* Len Filt */
|
||||
"\x00"
|
||||
/* Len Tem PT Seq Timestamp SSRC */
|
||||
"\x0c\x80\x00\x00\x00\x00\x00\x00\x00\x12\x34\x56\x78"
|
||||
/* Len Ulaw Alaw */
|
||||
"\x04\x00\x00\x08\x08"
|
||||
/* Len Alaw */
|
||||
"\x02\x08\x08"
|
||||
/* Len UlawLen Opts IntervalAlawLen Opts Interval */
|
||||
"\x0c\x00\x04\x03\x00\x80\x00\x08\x04\x03\x00\x80\x00";
|
||||
|
||||
static unsigned char NCPI_voice_over_ip_ulaw[] =
|
||||
/* Len Options */
|
||||
"\x27\x00\x00\x00\x00"
|
||||
/* Len Filt */
|
||||
"\x00"
|
||||
/* Len Tem PT Seq Timestamp SSRC */
|
||||
"\x0c\x80\x00\x00\x00\x00\x00\x00\x00\x12\x34\x56\x78"
|
||||
/* Len Ulaw Alaw */
|
||||
"\x04\x00\x00\x08\x08"
|
||||
/* Len Ulaw */
|
||||
"\x02\x00\x00"
|
||||
/* Len UlawLen Opts IntervalAlawLen Opts Interval */
|
||||
"\x0c\x00\x04\x03\x00\x80\x00\x08\x04\x03\x00\x80\x00";
|
||||
|
||||
static unsigned char NCPI_voice_over_ip_gsm[] =
|
||||
/* Len Options */
|
||||
"\x27\x00\x00\x00\x00"
|
||||
/* Len Filt */
|
||||
"\x00"
|
||||
/* Len Tem PT Seq Timestamp SSRC */
|
||||
"\x0c\x80\x00\x00\x00\x00\x00\x00\x00\x12\x34\x56\x78"
|
||||
/* Len GSM Alaw */
|
||||
"\x04\x03\x03\x08\x08"
|
||||
/* Len GSM */
|
||||
"\x02\x03\x03"
|
||||
/* Len GSM Len Opts IntervalAlawLen Opts Interval */
|
||||
"\x0c\x03\x04\x0f\x00\xa0\x00\x08\x04\x00\x00\x80\x00";
|
||||
|
||||
static unsigned char NCPI_voice_over_ip_g723[] =
|
||||
/* Len Options */
|
||||
"\x27\x00\x00\x00\x00"
|
||||
/* Len Filt */
|
||||
"\x00"
|
||||
/* Len Tem PT Seq Timestamp SSRC */
|
||||
"\x0c\x80\x00\x00\x00\x00\x00\x00\x00\x12\x34\x56\x78"
|
||||
/* Len G723 Alaw */
|
||||
"\x04\x04\x04\x08\x08"
|
||||
/* Len G723 */
|
||||
"\x02\x04\x04"
|
||||
/* Len G723Len Opts IntervalAlawLen Opts Interval */
|
||||
"\x0c\x04\x04\x01\x00\xf0\x00\x08\x04\x00\x00\x80\x00";
|
||||
|
||||
static unsigned char NCPI_voice_over_ip_g726[] =
|
||||
/* Len Options */
|
||||
"\x27\x00\x00\x00\x00"
|
||||
/* Len Filt */
|
||||
"\x00"
|
||||
/* Len Tem PT Seq Timestamp SSRC */
|
||||
"\x0c\x80\x00\x00\x00\x00\x00\x00\x00\x12\x34\x56\x78"
|
||||
/* Len G726 Alaw */
|
||||
"\x04\x02\x02\x08\x08"
|
||||
/* Len G726 */
|
||||
"\x02\x02\x02"
|
||||
/* Len G726Len Opts IntervalAlawLen Opts Interval */
|
||||
"\x0c\x02\x04\x0f\x00\xf0\x00\x08\x04\x00\x00\x80\x00";
|
||||
|
||||
static unsigned char NCPI_voice_over_ip_g729[] =
|
||||
/* Len Options */
|
||||
"\x27\x00\x00\x00\x00"
|
||||
/* Len Filt */
|
||||
"\x00"
|
||||
/* Len Tem PT Seq Timestamp SSRC */
|
||||
"\x0c\x80\x00\x00\x00\x00\x00\x00\x00\x12\x34\x56\x78"
|
||||
/* Len G729 Alaw */
|
||||
"\x04\x12\x12\x08\x08"
|
||||
/* Len G729 */
|
||||
"\x02\x12\x12"
|
||||
/* Len G729Len Opts IntervalAlawLen Opts Interval */
|
||||
"\x0c\x12\x04\x0f\x00\xa0\x00\x08\x04\x00\x00\x80\x00";
|
||||
|
||||
|
||||
/*
|
||||
* return NCPI for chosen RTP codec
|
||||
*/
|
||||
_cstruct capi_rtp_ncpi(struct capi_pvt *i)
|
||||
{
|
||||
_cstruct ncpi = NULL;
|
||||
|
||||
if ((i) && (i->owner) &&
|
||||
(i->isdnstate & CAPI_ISDN_STATE_RTP)) {
|
||||
switch(i->codec) {
|
||||
case AST_FORMAT_ALAW:
|
||||
ncpi = NCPI_voice_over_ip_alaw;
|
||||
break;
|
||||
case AST_FORMAT_ULAW:
|
||||
ncpi = NCPI_voice_over_ip_ulaw;
|
||||
break;
|
||||
case AST_FORMAT_GSM:
|
||||
ncpi = NCPI_voice_over_ip_gsm;
|
||||
break;
|
||||
case AST_FORMAT_G723_1:
|
||||
ncpi = NCPI_voice_over_ip_g723;
|
||||
break;
|
||||
case AST_FORMAT_G726:
|
||||
ncpi = NCPI_voice_over_ip_g726;
|
||||
break;
|
||||
case AST_FORMAT_G729A:
|
||||
ncpi = NCPI_voice_over_ip_g729;
|
||||
break;
|
||||
default:
|
||||
cc_log(LOG_ERROR, "%s: format %s(%d) invalid.\n",
|
||||
i->name, ast_getformatname(i->codec), i->codec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ncpi;
|
||||
}
|
||||
|
||||
/*
|
||||
* create rtp for capi interface
|
||||
*/
|
||||
int capi_alloc_rtp(struct capi_pvt *i)
|
||||
{
|
||||
struct ast_hostent ahp;
|
||||
struct hostent *hp;
|
||||
struct in_addr addr;
|
||||
struct sockaddr_in us;
|
||||
char temp[MAXHOSTNAMELEN];
|
||||
|
||||
hp = ast_gethostbyname("localhost", &ahp);
|
||||
memcpy(&addr, hp->h_addr, sizeof(addr));
|
||||
|
||||
if (!(i->rtp = ast_rtp_new_with_bindaddr(NULL, NULL, 0, 0, addr))) {
|
||||
cc_log(LOG_ERROR, "%s: unable to alloc rtp.\n", i->name);
|
||||
return 1;
|
||||
}
|
||||
ast_rtp_get_us(i->rtp, &us);
|
||||
ast_rtp_set_peer(i->rtp, &us);
|
||||
cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: alloc rtp socket on %s:%d\n",
|
||||
i->name,
|
||||
ast_inet_ntoa(temp, sizeof(temp), us.sin_addr),
|
||||
ntohs(us.sin_port));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* write rtp for a channel
|
||||
*/
|
||||
int capi_write_rtp(struct ast_channel *c, struct ast_frame *f)
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
_cmsg CMSG;
|
||||
int rtpheaderlen = 12;
|
||||
struct sockaddr_in us;
|
||||
int len;
|
||||
|
||||
i->send_buffer_handle++;
|
||||
|
||||
ast_rtp_get_us(i->rtp, &us);
|
||||
us.sin_port = 0; /* don't really send */
|
||||
ast_rtp_set_peer(i->rtp, &us);
|
||||
if (ast_rtp_write(i->rtp, f) != 0) {
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: rtp_write error, dropping packet.\n",
|
||||
i->name);
|
||||
return -1;
|
||||
}
|
||||
len = f->datalen + rtpheaderlen;
|
||||
|
||||
cc_verbose(6, 1, VERBOSE_PREFIX_4 "%s: RTP write for NCCI=%#x len=%d(%d) %s\n",
|
||||
i->name, i->NCCI, len, f->datalen, ast_getformatname(f->subclass));
|
||||
|
||||
DATA_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
DATA_B3_REQ_NCCI(&CMSG) = i->NCCI;
|
||||
DATA_B3_REQ_FLAGS(&CMSG) = 0;
|
||||
DATA_B3_REQ_DATAHANDLE(&CMSG) = i->send_buffer_handle;
|
||||
DATA_B3_REQ_DATALENGTH(&CMSG) = len;
|
||||
DATA_B3_REQ_DATA(&CMSG) = (unsigned char *)(f->data - rtpheaderlen);
|
||||
|
||||
_capi_put_cmsg(&CMSG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read data b3 in RTP mode
|
||||
*/
|
||||
struct ast_frame *capi_read_rtp(struct capi_pvt *i, unsigned char *buf, int len)
|
||||
{
|
||||
struct ast_frame *f;
|
||||
struct sockaddr_in us;
|
||||
|
||||
if (!(i->owner))
|
||||
return NULL;
|
||||
|
||||
ast_rtp_get_us(i->rtp, &us);
|
||||
ast_rtp_set_peer(i->rtp, &us);
|
||||
|
||||
if (len != sendto(ast_rtp_fd(i->rtp), buf, len, 0, (struct sockaddr *)&us, sizeof(us))) {
|
||||
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: RTP sendto error\n",
|
||||
i->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((f = ast_rtp_read(i->rtp))) {
|
||||
if (f->frametype != AST_FRAME_VOICE) {
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: DATA_B3_IND RTP (len=%d) non voice type=%d\n",
|
||||
i->name, len, f->frametype);
|
||||
return NULL;
|
||||
}
|
||||
cc_verbose(6, 1, VERBOSE_PREFIX_4 "%s: DATA_B3_IND RTP NCCI=%#x len=%d %s (read/write=%d/%d)\n",
|
||||
i->name, i->NCCI, len, ast_getformatname(f->subclass),
|
||||
i->owner->readformat, i->owner->writeformat);
|
||||
if (i->owner->readformat != f->subclass) {
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: DATA_B3_IND RTP readformat=%d, but subclass=%d\n",
|
||||
i->name, i->owner->readformat, f->subclass);
|
||||
/* i->owner->nativeformats = i->rtpcodec; */
|
||||
/* cc_set_read_format(i->owner, i->codec); */
|
||||
/* cc_set_write_format(i->owner, i->codec); */
|
||||
/* TODO: we need to change the format here */
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/*
|
||||
* eval RTP profile
|
||||
*/
|
||||
void voice_over_ip_profile(struct cc_capi_controller *cp)
|
||||
{
|
||||
MESSAGE_EXCHANGE_ERROR error;
|
||||
_cmsg CMSG;
|
||||
struct timeval tv;
|
||||
unsigned char fac[3] = "\x03\x02\x00";
|
||||
int waitcount = 200;
|
||||
unsigned short info = 0;
|
||||
unsigned int payload1, payload2;
|
||||
|
||||
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
FACILITY_REQ_CONTROLLER(&CMSG) = cp->controller;
|
||||
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_VOICE_OVER_IP;
|
||||
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)&fac;
|
||||
_capi_put_cmsg(&CMSG);
|
||||
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
while (waitcount) {
|
||||
error = capi20_waitformessage(capi_ApplID, &tv);
|
||||
error = capi_get_cmsg(&CMSG, capi_ApplID);
|
||||
if (error == 0) {
|
||||
if (IS_FACILITY_CONF(&CMSG)) {
|
||||
info = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
usleep(20000);
|
||||
waitcount--;
|
||||
}
|
||||
if (!info) {
|
||||
cc_log(LOG_WARNING, "did not receive FACILITY_CONF\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse profile */
|
||||
if (FACILITY_CONF_FACILITYSELECTOR(&CMSG) != FACILITYSELECTOR_VOICE_OVER_IP) {
|
||||
cc_log(LOG_WARNING, "unexpected FACILITY_SELECTOR = %#x\n",
|
||||
FACILITY_CONF_FACILITYSELECTOR(&CMSG));
|
||||
return;
|
||||
}
|
||||
if ((info = FACILITY_CONF_INFO(&CMSG)) != 0x0000) {
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "FACILITY_CONF INFO = %#x, RTP not used.\n",
|
||||
info);
|
||||
return;
|
||||
|
||||
}
|
||||
if (FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG)[0] < 13) {
|
||||
cc_log(LOG_WARNING, "conf parameter too short %d, RTP not used.\n",
|
||||
FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG)[0]);
|
||||
return;
|
||||
}
|
||||
info = read_capi_word(&(FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG)[1]));
|
||||
if (info != 0x0002) {
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "FACILITY_CONF wrong parameter (0x%04x), RTP not used.\n",
|
||||
info);
|
||||
return;
|
||||
}
|
||||
info = read_capi_word(&(FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG)[4]));
|
||||
payload1 = read_capi_dword(&(FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG)[6]));
|
||||
payload2 = read_capi_dword(&(FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER(&CMSG)[10]));
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "RTP payload options 0x%04x 0x%08x 0x%08x\n",
|
||||
info, payload1, payload2);
|
||||
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "RTP codec: ");
|
||||
if (payload1 & 0x00000100) {
|
||||
cp->rtpcodec |= AST_FORMAT_ALAW;
|
||||
cc_verbose(3, 0, "G.711 alaw, ");
|
||||
}
|
||||
if (payload1 & 0x00000001) {
|
||||
cp->rtpcodec |= AST_FORMAT_ULAW;
|
||||
cc_verbose(3, 0, "G.711 ulaw, ");
|
||||
}
|
||||
if (payload1 & 0x00000008) {
|
||||
cp->rtpcodec |= AST_FORMAT_GSM;
|
||||
cc_verbose(3, 0, "GSM, ");
|
||||
}
|
||||
if (payload1 & 0x00000010) {
|
||||
cp->rtpcodec |= AST_FORMAT_G723_1;
|
||||
cc_verbose(3, 0, "G.723.1, ");
|
||||
}
|
||||
if (payload1 & 0x00000004) {
|
||||
cp->rtpcodec |= AST_FORMAT_G726;
|
||||
cc_verbose(3, 0, "G.726, ");
|
||||
}
|
||||
if (payload1 & 0x00040000) {
|
||||
cp->rtpcodec |= AST_FORMAT_G729A;
|
||||
cc_verbose(3, 0, "G.729");
|
||||
}
|
||||
cc_verbose(3, 0, "\n");
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* (CAPI*)
|
||||
*
|
||||
* An implementation of Common ISDN API 2.0 for
|
||||
* Asterisk / OpenPBX.org
|
||||
*
|
||||
* Copyright (C) 2006 Cytronics & Melware
|
||||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* This program is free software and may be modified and
|
||||
* distributed under the terms of the GNU Public License.
|
||||
*/
|
||||
|
||||
#ifndef _PBX_CAPI_RTP_H
|
||||
#define _PBX_CAPI_RTP_H
|
||||
|
||||
/*
|
||||
* prototypes
|
||||
*/
|
||||
extern int capi_alloc_rtp(struct capi_pvt *i);
|
||||
extern void voice_over_ip_profile(struct cc_capi_controller *cp);
|
||||
extern int capi_write_rtp(struct ast_channel *c, struct ast_frame *f);
|
||||
extern struct ast_frame *capi_read_rtp(struct capi_pvt *i, unsigned char *buf, int len);
|
||||
extern _cstruct capi_rtp_ncpi(struct capi_pvt *i);
|
||||
|
||||
#endif
|
|
@ -42,14 +42,6 @@ else
|
|||
echo " * no 'struct ast_channel_tech', using old pvt"
|
||||
fi
|
||||
|
||||
if grep -q "ast_bridged_channel" $INCLUDEDIR/channel.h; then
|
||||
echo "#define CC_AST_HAS_BRIDGED_CHANNEL" >>$CONFIGFILE
|
||||
echo " * found 'ast_bridged_channel'"
|
||||
else
|
||||
echo "#undef CC_AST_HAS_BRIDGED_CHANNEL" >>$CONFIGFILE
|
||||
echo " * no 'ast_bridged_channel'"
|
||||
fi
|
||||
|
||||
if grep -q "ast_bridge_result" $INCLUDEDIR/channel.h; then
|
||||
echo "#define CC_AST_HAS_BRIDGE_RESULT" >>$CONFIGFILE
|
||||
echo " * found 'ast_bridge_result'"
|
||||
|
@ -130,6 +122,22 @@ else
|
|||
echo " * no 'devicestate.h'"
|
||||
fi
|
||||
|
||||
if [ -f "$INCLUDEDIR/strings.h" ]; then
|
||||
echo "#undef CC_AST_NO_STRINGS" >>$CONFIGFILE
|
||||
echo " * found 'strings.h'"
|
||||
else
|
||||
echo "#define CC_AST_NO_STRINGS" >>$CONFIGFILE
|
||||
echo " * no 'strings.h'"
|
||||
fi
|
||||
|
||||
if grep -q "ast_group_t" $INCLUDEDIR/channel.h; then
|
||||
echo "#define CC_AST_GROUP_T" >>$CONFIGFILE
|
||||
echo " * found 'ast_group_t'"
|
||||
else
|
||||
echo "#undef CC_AST_GROUP_T" >>$CONFIGFILE
|
||||
echo " * no 'ast_group_t'"
|
||||
fi
|
||||
|
||||
echo "" >>$CONFIGFILE
|
||||
echo "#endif /* CHAN_CAPI_CONFIG_H */" >>$CONFIGFILE
|
||||
echo "" >>$CONFIGFILE
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
#define PBX_IS_OPBX
|
||||
|
||||
#define ASTERISKVERSION OPBX_VERSION_INFO
|
||||
|
||||
#define CC_AST_HAVE_TECH_PVT
|
||||
#define CC_AST_HAS_BRIDGE_RESULT
|
||||
#define CC_AST_BRIDGE_WITH_TIMEOUTMS
|
||||
#undef CC_AST_DSP_PROCESS_NEEDLOCK
|
||||
#define CC_AST_CHANNEL_HAS_CID
|
||||
#define CC_AST_FRAME_HAS_TIMEVAL
|
||||
#define CC_AST_CHANNEL_HAS_TRANSFERCAP
|
||||
#define CC_AST_CONTROL_HOLD
|
||||
#define CC_AST_CUSTOM_FUNCTION
|
||||
#undef CC_AST_NO_DEVICESTATE
|
||||
#undef CC_AST_NO_STRINGS
|
||||
#define CC_AST_GROUP_T
|
||||
|
||||
#define ast_channel opbx_channel
|
||||
#define ast_frame opbx_frame
|
||||
#define ast_channel_alloc opbx_channel_alloc
|
||||
#define ast_channel_free opbx_channel_free
|
||||
#define ast_channel_tech opbx_channel_tech
|
||||
#define ast_change_name opbx_change_name
|
||||
#define ast_setstate opbx_setstate
|
||||
#define ast_exists_extension opbx_exists_extension
|
||||
#define ast_canmatch_extension opbx_canmatch_extension
|
||||
#define ast_getformatname_multiple opbx_getformatname_multiple
|
||||
#define ast_getformatname opbx_getformatname
|
||||
#define ast_hostent opbx_hostent
|
||||
#define ast_gethostbyname opbx_gethostbyname
|
||||
#define ast_rtp_new_with_bindaddr opbx_rtp_new_with_bindaddr
|
||||
#define ast_rtp_get_us opbx_rtp_get_us
|
||||
#define ast_rtp_set_peer opbx_rtp_set_peer
|
||||
#define ast_inet_ntoa opbx_inet_ntoa
|
||||
#define ast_rtp_write opbx_rtp_write
|
||||
#define ast_rtp_read opbx_rtp_read
|
||||
#define ast_rtp_fd opbx_rtp_fd
|
||||
#define ast_rtp_destroy opbx_rtp_destroy
|
||||
#define ast_rtp opbx_rtp
|
||||
#define ast_pbx_verbose opbx_verbose
|
||||
#define ast_set_read_format opbx_set_read_format
|
||||
#define ast_set_write_format opbx_set_write_format
|
||||
#define ast_channel_unregister opbx_channel_unregister
|
||||
#define ast_channel_register opbx_channel_register
|
||||
#define ast_cli_unregister opbx_cli_unregister
|
||||
#define ast_cli_register opbx_cli_register
|
||||
#define ast_cli_entry opbx_cli_entry
|
||||
#define ast_cli opbx_cli
|
||||
#define ast_strdupa opbx_strdupa
|
||||
#define ast_check_hangup opbx_check_hangup
|
||||
#define ast_hangup opbx_hangup
|
||||
#define ast_softhangup opbx_softhangup
|
||||
#define ast_pbx_start opbx_pbx_start
|
||||
#define ast_queue_frame opbx_queue_frame
|
||||
#define ast_async_goto opbx_async_goto
|
||||
#define ast_waitfor_n opbx_waitfor_n
|
||||
#define ast_pthread_create opbx_pthread_create
|
||||
#define ast_unregister_application opbx_unregister_application
|
||||
#define ast_custom_function_unregister opbx_custom_function_unregister
|
||||
#define ast_custom_function_register opbx_custom_function_register
|
||||
#define ast_custom_function opbx_custom_function
|
||||
#define ast_register_application opbx_register_application
|
||||
#define ast_config_destroy opbx_config_destroy
|
||||
#define ast_config_load opbx_config_load
|
||||
#define ast_config opbx_config
|
||||
#define ast_smoother_feed opbx_smoother_feed
|
||||
#define ast_smoother_read opbx_smoother_read
|
||||
#define ast_smoother_reset opbx_smoother_reset
|
||||
#define ast_smoother_new opbx_smoother_new
|
||||
#define ast_smoother opbx_smoother
|
||||
#define ast_category_browse opbx_category_browse
|
||||
#define ast_variable_browse opbx_variable_browse
|
||||
#define ast_variable opbx_variable
|
||||
#define ast_parse_allow_disallow opbx_parse_allow_disallow
|
||||
#define ast_true opbx_true
|
||||
#define ast_false opbx_false
|
||||
#define ast_frfree opbx_frfree
|
||||
#define ast_strlen_zero opbx_strlen_zero
|
||||
#define ast_dsp_process opbx_dsp_process
|
||||
#define ast_dsp_free opbx_dsp_free
|
||||
#define ast_dsp_new opbx_dsp_new
|
||||
#define ast_dsp_set_features opbx_dsp_set_features
|
||||
#define ast_dsp_digitmode opbx_dsp_digitmode
|
||||
#define ast_dsp opbx_dsp
|
||||
#define ast_sendtext opbx_sendtext
|
||||
#define ast_get_group opbx_get_group
|
||||
#define ast_group_t opbx_group_t
|
||||
#define ast_write opbx_write
|
||||
#define ast_read opbx_read
|
||||
#define ast_best_codec opbx_best_codec
|
||||
#define ast_update_use_count opbx_update_use_count
|
||||
#define ast_codec_pref opbx_codec_pref
|
||||
|
||||
#define AST_FORMAT_ALAW OPBX_FORMAT_ALAW
|
||||
#define AST_FORMAT_ULAW OPBX_FORMAT_ULAW
|
||||
#define AST_FORMAT_GSM OPBX_FORMAT_GSM
|
||||
#define AST_FORMAT_G723_1 OPBX_FORMAT_G723_1
|
||||
#define AST_FORMAT_G726 OPBX_FORMAT_G726
|
||||
#define AST_FORMAT_G729A OPBX_FORMAT_G729A
|
||||
#define AST_FRAME_VOICE OPBX_FRAME_VOICE
|
||||
#define AST_FRAME_CONTROL OPBX_FRAME_CONTROL
|
||||
#define AST_FRAME_DTMF OPBX_FRAME_DTMF
|
||||
#define AST_FRAME_NULL OPBX_FRAME_NULL
|
||||
#define AST_FRAME_TEXT OPBX_FRAME_TEXT
|
||||
#define AST_CONTROL_RINGING OPBX_CONTROL_RINGING
|
||||
#define AST_CONTROL_PROCEEDING OPBX_CONTROL_PROCEEDING
|
||||
#define AST_CONTROL_BUSY OPBX_CONTROL_BUSY
|
||||
#define AST_CONTROL_CONGESTION OPBX_CONTROL_CONGESTION
|
||||
#define AST_CONTROL_PROGRESS OPBX_CONTROL_PROGRESS
|
||||
#define AST_CONTROL_HOLD OPBX_CONTROL_HOLD
|
||||
#define AST_CONTROL_UNHOLD OPBX_CONTROL_UNHOLD
|
||||
#define AST_CONTROL_ANSWER OPBX_CONTROL_ANSWER
|
||||
#define AST_STATE_RING OPBX_STATE_RING
|
||||
#define AST_STATE_UP OPBX_STATE_UP
|
||||
#define AST_STATE_DOWN OPBX_STATE_DOWN
|
||||
#define AST_STATE_DIALING OPBX_STATE_DIALING
|
||||
#define AST_STATE_RESERVED OPBX_STATE_RESERVED
|
||||
#define AST_FRIENDLY_OFFSET OPBX_FRIENDLY_OFFSET
|
||||
#define AST_SOFTHANGUP_DEV OPBX_SOFTHANGUP_DEV
|
||||
#define AST_DEVICE_UNKNOWN OPBX_DEVICE_UNKNOWN
|
||||
#define AST_CHANNEL_NAME OPBX_CHANNEL_NAME
|
||||
#define AST_BRIDGE_DTMF_CHANNEL_0 OPBX_BRIDGE_DTMF_CHANNEL_0
|
||||
#define AST_BRIDGE_DTMF_CHANNEL_1 OPBX_BRIDGE_DTMF_CHANNEL_1
|
||||
#define AST_MAX_EXTENSION OPBX_MAX_EXTENSION
|
||||
#define AST_CAUSE_INVALID_NUMBER_FORMAT OPBX_CAUSE_INVALID_NUMBER_FORMAT
|
||||
#define AST_CAUSE_REQUESTED_CHAN_UNAVAIL OPBX_CAUSE_REQUESTED_CHAN_UNAVAIL
|
||||
#define AST_CAUSE_NORMAL_CIRCUIT_CONGESTION OPBX_CAUSE_NORMAL_CIRCUIT_CONGESTION
|
||||
#define AST_CAUSE_NO_USER_RESPONSE OPBX_CAUSE_NO_USER_RESPONSE
|
||||
#define AST_CAUSE_NO_ANSWER OPBX_CAUSE_NO_ANSWER
|
||||
#define AST_CAUSE_USER_BUSY OPBX_CAUSE_USER_BUSY
|
||||
|
||||
#define AST_MUTEX_DEFINE_STATIC OPBX_MUTEX_DEFINE_STATIC
|
||||
|
||||
#define AST_MUTEX_DEFINE_EXPORTED OPBX_MUTEX_DEFINE_EXPORTED
|
||||
|
||||
#define CC_BRIDGE_RETURN enum opbx_bridge_result
|
||||
#define AST_BRIDGE_COMPLETE OPBX_BRIDGE_COMPLETE
|
||||
#define AST_BRIDGE_FAILED OPBX_BRIDGE_FAILED
|
||||
#define AST_BRIDGE_FAILED_NOWARN OPBX_BRIDGE_FAILED_NOWARN
|
||||
#define AST_BRIDGE_RETRY OPBX_BRIDGE_RETRY
|
||||
|
Loading…
Reference in New Issue