- more restructuring
- chat handle null-plci voice frames
This commit is contained in:
parent
1b125d4d7e
commit
1b50367e34
2
Makefile
2
Makefile
|
@ -92,7 +92,7 @@ INSTALL=install
|
||||||
|
|
||||||
SHAREDOS=chan_capi.so
|
SHAREDOS=chan_capi.so
|
||||||
|
|
||||||
OBJECTS=chan_capi.o chan_capi_utils.o chan_capi_rtp.o \
|
OBJECTS=chan_capi.o chan_capi_utils.o chan_capi_rtp.o xlaw.o \
|
||||||
chan_capi_qsig_core.o chan_capi_qsig_ecma.o chan_capi_qsig_asn197ade.o \
|
chan_capi_qsig_core.o chan_capi_qsig_ecma.o chan_capi_qsig_asn197ade.o \
|
||||||
chan_capi_qsig_asn197no.o chan_capi_supplementary.o chan_capi_chat.o
|
chan_capi_qsig_asn197no.o chan_capi_supplementary.o chan_capi_chat.o
|
||||||
|
|
||||||
|
|
261
chan_capi.c
261
chan_capi.c
|
@ -138,11 +138,9 @@ AST_MUTEX_DEFINE_STATIC(usecnt_lock);
|
||||||
#endif
|
#endif
|
||||||
AST_MUTEX_DEFINE_STATIC(iflock);
|
AST_MUTEX_DEFINE_STATIC(iflock);
|
||||||
|
|
||||||
static int capi_capability = AST_FORMAT_ALAW;
|
|
||||||
|
|
||||||
static pthread_t monitor_thread = (pthread_t)(0-1);
|
static pthread_t monitor_thread = (pthread_t)(0-1);
|
||||||
|
|
||||||
struct capi_pvt *iflist = NULL;
|
struct capi_pvt *capi_iflist = NULL;
|
||||||
|
|
||||||
static struct cc_capi_controller *capi_controllers[CAPI_MAX_CONTROLLERS + 1];
|
static struct cc_capi_controller *capi_controllers[CAPI_MAX_CONTROLLERS + 1];
|
||||||
static int capi_num_controllers = 0;
|
static int capi_num_controllers = 0;
|
||||||
|
@ -162,6 +160,8 @@ static char capi_international_prefix[AST_MAX_EXTENSION];
|
||||||
|
|
||||||
static char default_language[MAX_LANGUAGE] = "";
|
static char default_language[MAX_LANGUAGE] = "";
|
||||||
|
|
||||||
|
int capi_capability = AST_FORMAT_ALAW;
|
||||||
|
|
||||||
#ifdef CC_AST_HAS_VERSION_1_4
|
#ifdef CC_AST_HAS_VERSION_1_4
|
||||||
/* Global jitterbuffer configuration - by default, jb is disabled */
|
/* Global jitterbuffer configuration - by default, jb is disabled */
|
||||||
static struct ast_jb_conf default_jbconf =
|
static struct ast_jb_conf default_jbconf =
|
||||||
|
@ -365,7 +365,7 @@ static int tcap2cip(unsigned short tcap)
|
||||||
return CAPI_CIPI_SPEECH;
|
return CAPI_CIPI_SPEECH;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char tcap_is_digital(unsigned short tcap)
|
unsigned char capi_tcap_is_digital(unsigned short tcap)
|
||||||
{
|
{
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
|
@ -493,7 +493,7 @@ static void capi_echo_canceller(struct capi_pvt *i, int function)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcap_is_digital(c->transfercapability)) {
|
if (capi_tcap_is_digital(c->transfercapability)) {
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: No echo canceller in digital mode (PLCI=%#x)\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: No echo canceller in digital mode (PLCI=%#x)\n",
|
||||||
i->vname, i->PLCI);
|
i->vname, i->PLCI);
|
||||||
return;
|
return;
|
||||||
|
@ -535,7 +535,7 @@ static int capi_detect_dtmf(struct capi_pvt *i, int flag)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcap_is_digital(c->transfercapability)) {
|
if (capi_tcap_is_digital(c->transfercapability)) {
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: No dtmf-detect in digital mode (PLCI=%#x)\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: No dtmf-detect in digital mode (PLCI=%#x)\n",
|
||||||
i->vname, i->PLCI);
|
i->vname, i->PLCI);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -590,17 +590,6 @@ static int local_queue_frame(struct capi_pvt *i, struct ast_frame *f)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
|
||||||
if (f->frametype == AST_FRAME_VOICE) {
|
|
||||||
/* NULL PLCI data is written directly */
|
|
||||||
ast_write(chan, f);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: frame %d/%d not queued for NULL-PLCI.\n",
|
|
||||||
i->vname, f->frametype, f->subclass);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(i->isdnstate & CAPI_ISDN_STATE_PBX)) {
|
if (!(i->isdnstate & CAPI_ISDN_STATE_PBX)) {
|
||||||
/* if there is no PBX running yet,
|
/* if there is no PBX running yet,
|
||||||
we don't need any frames sent */
|
we don't need any frames sent */
|
||||||
|
@ -1096,7 +1085,7 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout)
|
||||||
MESSAGE_EXCHANGE_ERROR error;
|
MESSAGE_EXCHANGE_ERROR error;
|
||||||
|
|
||||||
cc_copy_string(buffer, idest, sizeof(buffer));
|
cc_copy_string(buffer, idest, sizeof(buffer));
|
||||||
parse_dialstring(buffer, &interface, &dest, ¶m, &ocid);
|
capi_parse_dialstring(buffer, &interface, &dest, ¶m, &ocid);
|
||||||
|
|
||||||
/* init param settings */
|
/* init param settings */
|
||||||
i->doB3 = CAPI_B3_DONT;
|
i->doB3 = CAPI_B3_DONT;
|
||||||
|
@ -1213,7 +1202,7 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout)
|
||||||
dsa = calledsubaddress;
|
dsa = calledsubaddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tcap_is_digital(c->transfercapability)) {
|
if (capi_tcap_is_digital(c->transfercapability)) {
|
||||||
i->bproto = CC_BPROTO_TRANSPARENT;
|
i->bproto = CC_BPROTO_TRANSPARENT;
|
||||||
cc_verbose(4, 0, VERBOSE_PREFIX_2 "%s: is digital call, set proto to TRANSPARENT\n",
|
cc_verbose(4, 0, VERBOSE_PREFIX_2 "%s: is digital call, set proto to TRANSPARENT\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
|
@ -1358,7 +1347,7 @@ static int pbx_capi_answer(struct ast_channel *c)
|
||||||
i->bproto = CC_BPROTO_TRANSPARENT;
|
i->bproto = CC_BPROTO_TRANSPARENT;
|
||||||
|
|
||||||
if (i->rtp) {
|
if (i->rtp) {
|
||||||
if (!tcap_is_digital(c->transfercapability))
|
if (!capi_tcap_is_digital(c->transfercapability))
|
||||||
i->bproto = CC_BPROTO_RTP;
|
i->bproto = CC_BPROTO_RTP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1371,47 +1360,12 @@ static int pbx_capi_answer(struct ast_channel *c)
|
||||||
*/
|
*/
|
||||||
static struct ast_frame *pbx_capi_read(struct ast_channel *c)
|
static struct ast_frame *pbx_capi_read(struct ast_channel *c)
|
||||||
{
|
{
|
||||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||||
struct ast_frame *f;
|
struct ast_frame *f;
|
||||||
int readsize;
|
|
||||||
|
|
||||||
if (i == NULL) {
|
f = capi_read_pipeframe(i);
|
||||||
cc_log(LOG_ERROR, "channel has no interface\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (i->readerfd == -1) {
|
|
||||||
cc_log(LOG_ERROR, "no readerfd\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
f = &i->f;
|
if ((f) && (f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) {
|
||||||
f->frametype = AST_FRAME_NULL;
|
|
||||||
f->subclass = 0;
|
|
||||||
|
|
||||||
readsize = read(i->readerfd, f, sizeof(struct ast_frame));
|
|
||||||
if ((readsize != sizeof(struct ast_frame)) && (readsize > 0)) {
|
|
||||||
cc_log(LOG_ERROR, "did not read a whole frame (len=%d, err=%d)\n",
|
|
||||||
readsize, errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
f->mallocd = 0;
|
|
||||||
f->data = NULL;
|
|
||||||
|
|
||||||
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) {
|
|
||||||
if (f->datalen > sizeof(i->frame_data)) {
|
|
||||||
cc_log(LOG_ERROR, "f.datalen(%d) greater than space of frame_data(%d)\n",
|
|
||||||
f->datalen, sizeof(i->frame_data));
|
|
||||||
f->datalen = sizeof(i->frame_data);
|
|
||||||
}
|
|
||||||
readsize = read(i->readerfd, i->frame_data + AST_FRIENDLY_OFFSET, f->datalen);
|
|
||||||
if (readsize != f->datalen) {
|
|
||||||
cc_log(LOG_ERROR, "did not read whole frame data\n");
|
|
||||||
}
|
|
||||||
f->data = i->frame_data + AST_FRIENDLY_OFFSET;
|
|
||||||
if ((i->doDTMF > 0) && (i->vad != NULL) ) {
|
if ((i->doDTMF > 0) && (i->vad != NULL) ) {
|
||||||
f = ast_dsp_process(c, i->vad, f);
|
f = ast_dsp_process(c, i->vad, f);
|
||||||
}
|
}
|
||||||
|
@ -1425,122 +1379,10 @@ static struct ast_frame *pbx_capi_read(struct ast_channel *c)
|
||||||
static int pbx_capi_write(struct ast_channel *c, struct ast_frame *f)
|
static int pbx_capi_write(struct ast_channel *c, struct ast_frame *f)
|
||||||
{
|
{
|
||||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||||
MESSAGE_EXCHANGE_ERROR error;
|
|
||||||
int j = 0;
|
|
||||||
unsigned char *buf;
|
|
||||||
struct ast_frame *fsmooth;
|
|
||||||
int txavg=0;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!i) {
|
ret = capi_write_frame(i, f);
|
||||||
cc_log(LOG_ERROR, "channel has no interface\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) || (!i->NCCI) ||
|
|
||||||
((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI)))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!(i->ntmode)) && (i->state != CAPI_STATE_CONNECTED)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f->frametype == AST_FRAME_NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (f->frametype == AST_FRAME_DTMF) {
|
|
||||||
cc_log(LOG_ERROR, "dtmf frame should be written\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (f->frametype != AST_FRAME_VOICE) {
|
|
||||||
cc_log(LOG_ERROR,"not a voice frame\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (i->FaxState & CAPI_FAX_STATE_ACTIVE) {
|
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax activity?\n",
|
|
||||||
i->vname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((!f->data) || (!f->datalen)) {
|
|
||||||
cc_log(LOG_DEBUG, "No data for FRAME_VOICE %s\n", c->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (i->isdnstate & CAPI_ISDN_STATE_RTP) {
|
|
||||||
if ((!(f->subclass & i->codec)) &&
|
|
||||||
(f->subclass != capi_capability)) {
|
|
||||||
cc_log(LOG_ERROR, "don't know how to write subclass %s(%d)\n",
|
|
||||||
ast_getformatname(f->subclass), f->subclass);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return capi_write_rtp(c, f);
|
|
||||||
}
|
|
||||||
if (i->B3count >= CAPI_MAX_B3_BLOCKS) {
|
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: B3count is full, dropping packet.\n",
|
|
||||||
i->vname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) {
|
|
||||||
cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (fsmooth = ast_smoother_read(i->smoother);
|
|
||||||
fsmooth != NULL;
|
|
||||||
fsmooth = ast_smoother_read(i->smoother)) {
|
|
||||||
buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) *
|
|
||||||
(CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)]);
|
|
||||||
i->send_buffer_handle++;
|
|
||||||
|
|
||||||
if ((i->doES == 1) && (!tcap_is_digital(c->transfercapability))) {
|
|
||||||
for (j = 0; j < fsmooth->datalen; j++) {
|
|
||||||
buf[j] = reversebits[ ((unsigned char *)fsmooth->data)[j] ];
|
|
||||||
if (capi_capability == AST_FORMAT_ULAW) {
|
|
||||||
txavg += abs( capiULAW2INT[reversebits[ ((unsigned char*)fsmooth->data)[j]]] );
|
|
||||||
} else {
|
|
||||||
txavg += abs( capiALAW2INT[reversebits[ ((unsigned char*)fsmooth->data)[j]]] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
txavg = txavg / j;
|
|
||||||
for(j = 0; j < ECHO_TX_COUNT - 1; j++) {
|
|
||||||
i->txavg[j] = i->txavg[j+1];
|
|
||||||
}
|
|
||||||
i->txavg[ECHO_TX_COUNT - 1] = txavg;
|
|
||||||
} else {
|
|
||||||
if ((i->txgain == 1.0) || (tcap_is_digital(c->transfercapability))) {
|
|
||||||
for (j = 0; j < fsmooth->datalen; j++) {
|
|
||||||
buf[j] = reversebits[((unsigned char *)fsmooth->data)[j]];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (j = 0; j < fsmooth->datalen; j++) {
|
|
||||||
buf[j] = i->g.txgains[reversebits[((unsigned char *)fsmooth->data)[j]]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
error = 1;
|
|
||||||
if (i->B3q > 0) {
|
|
||||||
error = capi_sendf(NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(),
|
|
||||||
"dwww",
|
|
||||||
buf,
|
|
||||||
fsmooth->datalen,
|
|
||||||
i->send_buffer_handle,
|
|
||||||
0);
|
|
||||||
} else {
|
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: too much voice to send for NCCI=%#x\n",
|
|
||||||
i->vname, i->NCCI);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
cc_mutex_lock(&i->lock);
|
|
||||||
i->B3count++;
|
|
||||||
i->B3q -= fsmooth->datalen;
|
|
||||||
if (i->B3q < 0)
|
|
||||||
i->B3q = 0;
|
|
||||||
cc_mutex_unlock(&i->lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1793,8 +1635,6 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
|
||||||
{
|
{
|
||||||
struct ast_channel *tmp;
|
struct ast_channel *tmp;
|
||||||
int fmt;
|
int fmt;
|
||||||
int fds[2];
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
#ifdef CC_AST_HAS_EXT_CHAN_ALLOC
|
#ifdef CC_AST_HAS_EXT_CHAN_ALLOC
|
||||||
tmp = ast_channel_alloc(0, state, i->cid, NULL,
|
tmp = ast_channel_alloc(0, state, i->cid, NULL,
|
||||||
|
@ -1824,19 +1664,10 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
|
||||||
tmp->type = channeltype;
|
tmp->type = channeltype;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pipe(fds) != 0) {
|
if (!(capi_create_reader_writer_pipe(i))) {
|
||||||
cc_log(LOG_ERROR, "%s: unable to create pipe.\n",
|
|
||||||
i->vname);
|
|
||||||
ast_channel_free(tmp);
|
ast_channel_free(tmp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
i->readerfd = fds[0];
|
|
||||||
i->writerfd = fds[1];
|
|
||||||
flags = fcntl(i->readerfd, F_GETFL);
|
|
||||||
fcntl(i->readerfd, F_SETFL, flags | O_NONBLOCK);
|
|
||||||
flags = fcntl(i->writerfd, F_GETFL);
|
|
||||||
fcntl(i->writerfd, F_SETFL, flags | O_NONBLOCK);
|
|
||||||
|
|
||||||
tmp->fds[0] = i->readerfd;
|
tmp->fds[0] = i->readerfd;
|
||||||
|
|
||||||
if (i->smoother != NULL) {
|
if (i->smoother != NULL) {
|
||||||
|
@ -1965,7 +1796,7 @@ pbx_capi_request(const char *type, int format, void *data, int *cause)
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "data = %s format=%d\n", (char *)data, format);
|
cc_verbose(1, 1, VERBOSE_PREFIX_4 "data = %s format=%d\n", (char *)data, format);
|
||||||
|
|
||||||
cc_copy_string(buffer, (char *)data, sizeof(buffer));
|
cc_copy_string(buffer, (char *)data, sizeof(buffer));
|
||||||
parse_dialstring(buffer, &interface, &dest, ¶m, &ocid);
|
capi_parse_dialstring(buffer, &interface, &dest, ¶m, &ocid);
|
||||||
|
|
||||||
if ((!interface) || (!dest)) {
|
if ((!interface) || (!dest)) {
|
||||||
cc_log(LOG_ERROR, "Syntax error in dialstring. Read the docs!\n");
|
cc_log(LOG_ERROR, "Syntax error in dialstring. Read the docs!\n");
|
||||||
|
@ -1998,7 +1829,7 @@ pbx_capi_request(const char *type, int format, void *data, int *cause)
|
||||||
|
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
|
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if ((i->used) || (i->channeltype != CAPI_CHANNELTYPE_B)) {
|
if ((i->used) || (i->channeltype != CAPI_CHANNELTYPE_B)) {
|
||||||
/* if already in use or no real channel */
|
/* if already in use or no real channel */
|
||||||
continue;
|
continue;
|
||||||
|
@ -2527,7 +2358,7 @@ static void capidev_handle_did_digits(_cmsg *CMSG, unsigned int PLCI, unsigned i
|
||||||
/*
|
/*
|
||||||
* send control according to cause code
|
* send control according to cause code
|
||||||
*/
|
*/
|
||||||
void queue_cause_control(struct capi_pvt *i, int control)
|
void capi_queue_cause_control(struct capi_pvt *i, int control)
|
||||||
{
|
{
|
||||||
struct ast_frame fr = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, };
|
struct ast_frame fr = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP, };
|
||||||
|
|
||||||
|
@ -2566,14 +2397,14 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
||||||
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 1\n",
|
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 1\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
if (i->state == CAPI_STATE_CONNECTED) {
|
if (i->state == CAPI_STATE_CONNECTED) {
|
||||||
queue_cause_control(i, 0);
|
capi_queue_cause_control(i, 0);
|
||||||
} else {
|
} else {
|
||||||
if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) {
|
if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) {
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online hangup frame queued.\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online hangup frame queued.\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
i->whentoqueuehangup = time(NULL) + 1;
|
i->whentoqueuehangup = time(NULL) + 1;
|
||||||
} else {
|
} else {
|
||||||
queue_cause_control(i, 1);
|
capi_queue_cause_control(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -2584,7 +2415,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
||||||
(i->state == CAPI_STATE_CONNECTED) && (i->outgoing == 1)) {
|
(i->state == CAPI_STATE_CONNECTED) && (i->outgoing == 1)) {
|
||||||
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 2\n",
|
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 2\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
queue_cause_control(i, 1);
|
capi_queue_cause_control(i, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2601,7 +2432,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
||||||
capi_send_disconnect(i->PLCI, NULL);
|
capi_send_disconnect(i->PLCI, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queue_cause_control(i, 0);
|
capi_queue_cause_control(i, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2611,7 +2442,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
||||||
i->vname);
|
i->vname);
|
||||||
if ((i->state == CAPI_STATE_CONNECTED) &&
|
if ((i->state == CAPI_STATE_CONNECTED) &&
|
||||||
(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) {
|
(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) {
|
||||||
queue_cause_control(i, 1);
|
capi_queue_cause_control(i, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network */
|
/* wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network */
|
||||||
|
@ -2816,7 +2647,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig
|
||||||
if (i->doB3 == CAPI_B3_DONT) {
|
if (i->doB3 == CAPI_B3_DONT) {
|
||||||
if ((i->owner) &&
|
if ((i->owner) &&
|
||||||
(i->owner->hangupcause == AST_CAUSE_USER_BUSY)) {
|
(i->owner->hangupcause == AST_CAUSE_USER_BUSY)) {
|
||||||
queue_cause_control(i, 1);
|
capi_queue_cause_control(i, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3041,13 +2872,13 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un
|
||||||
i->B3q += b3len;
|
i->B3q += b3len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((i->doES == 1) && (!tcap_is_digital(chan->transfercapability))) {
|
if ((i->doES == 1) && (!capi_tcap_is_digital(chan->transfercapability))) {
|
||||||
for (j = 0; j < b3len; j++) {
|
for (j = 0; j < b3len; j++) {
|
||||||
*(b3buf + j) = reversebits[*(b3buf + j)];
|
*(b3buf + j) = capi_reversebits[*(b3buf + j)];
|
||||||
if (capi_capability == AST_FORMAT_ULAW) {
|
if (capi_capability == AST_FORMAT_ULAW) {
|
||||||
rxavg += abs(capiULAW2INT[ reversebits[*(b3buf + j)]]);
|
rxavg += abs(capiULAW2INT[ capi_reversebits[*(b3buf + j)]]);
|
||||||
} else {
|
} else {
|
||||||
rxavg += abs(capiALAW2INT[ reversebits[*(b3buf + j)]]);
|
rxavg += abs(capiALAW2INT[ capi_reversebits[*(b3buf + j)]]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rxavg = rxavg / j;
|
rxavg = rxavg / j;
|
||||||
|
@ -3066,13 +2897,13 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un
|
||||||
i->vname, rxavg, txavg);
|
i->vname, rxavg, txavg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((i->rxgain == 1.0) || (tcap_is_digital(chan->transfercapability))) {
|
if ((i->rxgain == 1.0) || (capi_tcap_is_digital(chan->transfercapability))) {
|
||||||
for (j = 0; j < b3len; j++) {
|
for (j = 0; j < b3len; j++) {
|
||||||
*(b3buf + j) = reversebits[*(b3buf + j)];
|
*(b3buf + j) = capi_reversebits[*(b3buf + j)];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (j = 0; j < b3len; j++) {
|
for (j = 0; j < b3len; j++) {
|
||||||
*(b3buf + j) = reversebits[i->g.rxgains[*(b3buf + j)]];
|
*(b3buf + j) = capi_reversebits[i->g.rxgains[*(b3buf + j)]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3474,7 +3305,7 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un
|
||||||
|
|
||||||
/* well...somebody is calling us. let's set up a channel */
|
/* well...somebody is calling us. let's set up a channel */
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if (i->used) {
|
if (i->used) {
|
||||||
/* is already used */
|
/* is already used */
|
||||||
continue;
|
continue;
|
||||||
|
@ -3541,7 +3372,7 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i->owner->transfercapability = cip2tcap(i->cip);
|
i->owner->transfercapability = cip2tcap(i->cip);
|
||||||
if (tcap_is_digital(i->owner->transfercapability)) {
|
if (capi_tcap_is_digital(i->owner->transfercapability)) {
|
||||||
i->bproto = CC_BPROTO_TRANSPARENT;
|
i->bproto = CC_BPROTO_TRANSPARENT;
|
||||||
}
|
}
|
||||||
i->owner->cid.cid_pres = callpres;
|
i->owner->cid.cid_pres = callpres;
|
||||||
|
@ -3735,7 +3566,7 @@ void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI,
|
||||||
"defined interface received\n");
|
"defined interface received\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*i = find_interface_by_msgnum(wMsgNum);
|
*i = capi_find_interface_by_msgnum(wMsgNum);
|
||||||
ii = *i;
|
ii = *i;
|
||||||
if (ii == NULL) {
|
if (ii == NULL) {
|
||||||
return;
|
return;
|
||||||
|
@ -3764,7 +3595,7 @@ static void capidev_handle_msg(_cmsg *CMSG)
|
||||||
unsigned short wCmd = HEADER_CMD(CMSG);
|
unsigned short wCmd = HEADER_CMD(CMSG);
|
||||||
unsigned short wMsgNum = HEADER_MSGNUM(CMSG);
|
unsigned short wMsgNum = HEADER_MSGNUM(CMSG);
|
||||||
unsigned short wInfo = 0xffff;
|
unsigned short wInfo = 0xffff;
|
||||||
struct capi_pvt *i = find_interface_by_plci(PLCI);
|
struct capi_pvt *i = capi_find_interface_by_plci(PLCI);
|
||||||
|
|
||||||
if ((wCmd == CAPI_P_IND(DATA_B3)) ||
|
if ((wCmd == CAPI_P_IND(DATA_B3)) ||
|
||||||
(wCmd == CAPI_P_CONF(DATA_B3))) {
|
(wCmd == CAPI_P_CONF(DATA_B3))) {
|
||||||
|
@ -4020,7 +3851,7 @@ static int pbx_capi_retrieve(struct ast_channel *c, char *param)
|
||||||
if (param) {
|
if (param) {
|
||||||
plci = (unsigned int)strtoul(param, NULL, 0);
|
plci = (unsigned int)strtoul(param, NULL, 0);
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if (i->onholdPLCI == plci)
|
if (i->onholdPLCI == plci)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4107,7 +3938,7 @@ static int pbx_capi_ect(struct ast_channel *c, char *param)
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
for (ii = iflist; ii; ii = ii->next) {
|
for (ii = capi_iflist; ii; ii = ii->next) {
|
||||||
if (ii->onholdPLCI == plci)
|
if (ii->onholdPLCI == plci)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4351,7 +4182,7 @@ static int pbx_capi_realhangup(struct ast_channel *c, char *param)
|
||||||
struct capi_pvt *i;
|
struct capi_pvt *i;
|
||||||
|
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if (i->peer == c)
|
if (i->peer == c)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4424,7 +4255,7 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param)
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
for (ii = iflist; ii; ii = ii->next) {
|
for (ii = capi_iflist; ii; ii = ii->next) {
|
||||||
if (ii->onholdPLCI == plci)
|
if (ii->onholdPLCI == plci)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4755,7 +4586,7 @@ static void capidev_run_secondly(time_t now)
|
||||||
|
|
||||||
/* check for channels to hangup (timeout) */
|
/* check for channels to hangup (timeout) */
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if (i->used == NULL) {
|
if (i->used == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -4768,7 +4599,7 @@ static void capidev_run_secondly(time_t now)
|
||||||
if ((i->whentoqueuehangup) && (i->whentoqueuehangup < now)) {
|
if ((i->whentoqueuehangup) && (i->whentoqueuehangup < now)) {
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online queue-hangup.\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online queue-hangup.\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
queue_cause_control(i, 1);
|
capi_queue_cause_control(i, 1);
|
||||||
i->whentoqueuehangup = 0;
|
i->whentoqueuehangup = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4961,8 +4792,8 @@ int mkif(struct cc_capi_conf *conf)
|
||||||
|
|
||||||
tmp->qsigfeat = conf->qsigfeat;
|
tmp->qsigfeat = conf->qsigfeat;
|
||||||
|
|
||||||
tmp->next = iflist; /* prepend */
|
tmp->next = capi_iflist; /* prepend */
|
||||||
iflist = tmp;
|
capi_iflist = tmp;
|
||||||
cc_verbose(2, 0, VERBOSE_PREFIX_3 "capi %c %s (%s:%s) contr=%d devs=%d EC=%d,opt=%d,tail=%d\n",
|
cc_verbose(2, 0, VERBOSE_PREFIX_3 "capi %c %s (%s:%s) contr=%d devs=%d EC=%d,opt=%d,tail=%d\n",
|
||||||
(tmp->channeltype == CAPI_CHANNELTYPE_B)? 'B' : 'D',
|
(tmp->channeltype == CAPI_CHANNELTYPE_B)? 'B' : 'D',
|
||||||
tmp->vname, tmp->incomingmsn, tmp->context, tmp->controller,
|
tmp->vname, tmp->incomingmsn, tmp->context, tmp->controller,
|
||||||
|
@ -5152,7 +4983,7 @@ static int pbxcli_capi_show_channels(int fd, int argc, char *argv[])
|
||||||
|
|
||||||
cc_mutex_lock(&iflock);
|
cc_mutex_lock(&iflock);
|
||||||
|
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if (i->channeltype != CAPI_CHANNELTYPE_B)
|
if (i->channeltype != CAPI_CHANNELTYPE_B)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -5472,7 +5303,7 @@ static int cc_post_init_capi(void)
|
||||||
int rtp_ext_size = 0;
|
int rtp_ext_size = 0;
|
||||||
unsigned needchannels = 0;
|
unsigned needchannels = 0;
|
||||||
|
|
||||||
for (i = iflist; i && !rtp_ext_size; i = i->next) {
|
for (i = capi_iflist; i && !rtp_ext_size; i = i->next) {
|
||||||
/* if at least one line wants RTP, we need to re-register with
|
/* if at least one line wants RTP, we need to re-register with
|
||||||
bigger block size for RTP-header */
|
bigger block size for RTP-header */
|
||||||
if (capi_controllers[i->controller]->rtpcodec & i->capability) {
|
if (capi_controllers[i->controller]->rtpcodec & i->capability) {
|
||||||
|
@ -5490,7 +5321,7 @@ static int cc_post_init_capi(void)
|
||||||
|
|
||||||
for (controller = 1; controller <= capi_num_controllers; controller++) {
|
for (controller = 1; controller <= capi_num_controllers; controller++) {
|
||||||
if (capi_used_controllers & (1 << controller)) {
|
if (capi_used_controllers & (1 << controller)) {
|
||||||
if ((error = ListenOnController(ALL_SERVICES, controller)) != 0) {
|
if ((error = capi_ListenOnController(ALL_SERVICES, controller)) != 0) {
|
||||||
cc_log(LOG_ERROR,"Unable to listen on contr%d (error=0x%x)\n",
|
cc_log(LOG_ERROR,"Unable to listen on contr%d (error=0x%x)\n",
|
||||||
controller, error);
|
controller, error);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5817,7 +5648,7 @@ int unload_module(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i = iflist;
|
i = capi_iflist;
|
||||||
while (i) {
|
while (i) {
|
||||||
if ((i->owner) || (i->used))
|
if ((i->owner) || (i->used))
|
||||||
cc_log(LOG_WARNING, "On unload, interface still has owner or is used.\n");
|
cc_log(LOG_WARNING, "On unload, interface still has owner or is used.\n");
|
||||||
|
|
|
@ -568,10 +568,12 @@ struct cc_capi_controller {
|
||||||
* prototypes
|
* prototypes
|
||||||
*/
|
*/
|
||||||
extern const struct ast_channel_tech capi_tech;
|
extern const struct ast_channel_tech capi_tech;
|
||||||
|
extern int capi_capability;
|
||||||
extern unsigned capi_ApplID;
|
extern unsigned capi_ApplID;
|
||||||
extern struct capi_pvt *iflist;
|
extern struct capi_pvt *capi_iflist;
|
||||||
extern void cc_start_b3(struct capi_pvt *i);
|
extern void cc_start_b3(struct capi_pvt *i);
|
||||||
extern void queue_cause_control(struct capi_pvt *i, int control);
|
extern unsigned char capi_tcap_is_digital(unsigned short tcap);
|
||||||
|
extern void capi_queue_cause_control(struct capi_pvt *i, int control);
|
||||||
extern void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI,
|
extern void capidev_handle_connection_conf(struct capi_pvt **i, unsigned int PLCI,
|
||||||
unsigned short wInfo, unsigned short wMsgNum);
|
unsigned short wInfo, unsigned short wMsgNum);
|
||||||
extern void capi_wait_for_answered(struct capi_pvt *i);
|
extern void capi_wait_for_answered(struct capi_pvt *i);
|
||||||
|
|
121
chan_capi_chat.c
121
chan_capi_chat.c
|
@ -14,6 +14,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/signal.h>
|
||||||
|
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
|
@ -27,7 +29,6 @@ struct capichat_s {
|
||||||
unsigned int number;
|
unsigned int number;
|
||||||
struct ast_channel *chan;
|
struct ast_channel *chan;
|
||||||
struct capi_pvt *i;
|
struct capi_pvt *i;
|
||||||
_cdword plci;
|
|
||||||
struct capichat_s *next;
|
struct capichat_s *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,8 +38,9 @@ AST_MUTEX_DEFINE_STATIC(chat_lock);
|
||||||
/*
|
/*
|
||||||
* update the capi mixer for the given char room
|
* update the capi mixer for the given char room
|
||||||
*/
|
*/
|
||||||
static void update_capi_mixer(int remove, unsigned int roomnumber, _cdword plci)
|
static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_pvt *i)
|
||||||
{
|
{
|
||||||
|
struct capi_pvt *ii;
|
||||||
struct capichat_s *room;
|
struct capichat_s *room;
|
||||||
unsigned char p_list[360];
|
unsigned char p_list[360];
|
||||||
_cdword dest;
|
_cdword dest;
|
||||||
|
@ -51,18 +53,22 @@ static void update_capi_mixer(int remove, unsigned int roomnumber, _cdword plci)
|
||||||
room = chat_list;
|
room = chat_list;
|
||||||
while (room) {
|
while (room) {
|
||||||
if ((room->number == roomnumber) &&
|
if ((room->number == roomnumber) &&
|
||||||
(room->plci != plci)) {
|
(room->i != i)) {
|
||||||
found++;
|
found++;
|
||||||
if (j + 9 > sizeof(p_list)) {
|
if (j + 9 > sizeof(p_list)) {
|
||||||
/* maybe we need to split capi messages here */
|
/* maybe we need to split capi messages here */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
ii = room->i;
|
||||||
p_list[j++] = 8;
|
p_list[j++] = 8;
|
||||||
p_list[j++] = (_cbyte)(room->plci);
|
p_list[j++] = (_cbyte)(ii->PLCI);
|
||||||
p_list[j++] = (_cbyte)(room->plci >> 8);
|
p_list[j++] = (_cbyte)(ii->PLCI >> 8);
|
||||||
p_list[j++] = (_cbyte)(room->plci >> 16);
|
p_list[j++] = (_cbyte)(ii->PLCI >> 16);
|
||||||
p_list[j++] = (_cbyte)(room->plci >> 24);
|
p_list[j++] = (_cbyte)(ii->PLCI >> 24);
|
||||||
dest = (remove) ? 0x00000000 : 0x00000003;
|
dest = (remove) ? 0x00000000 : 0x00000003;
|
||||||
|
if (ii->channeltype == CAPI_CHANNELTYPE_NULL) {
|
||||||
|
dest |= 0x00000030;
|
||||||
|
}
|
||||||
p_list[j++] = (_cbyte)(dest);
|
p_list[j++] = (_cbyte)(dest);
|
||||||
p_list[j++] = (_cbyte)(dest >> 8);
|
p_list[j++] = (_cbyte)(dest >> 8);
|
||||||
p_list[j++] = (_cbyte)(dest >> 16);
|
p_list[j++] = (_cbyte)(dest >> 16);
|
||||||
|
@ -80,14 +86,17 @@ static void update_capi_mixer(int remove, unsigned int roomnumber, _cdword plci)
|
||||||
datapath = 0x00000000;
|
datapath = 0x00000000;
|
||||||
if (remove) {
|
if (remove) {
|
||||||
/* now we need DATA_B3 again */
|
/* now we need DATA_B3 again */
|
||||||
datapath = 0x000000c0;
|
datapath = 0x0000000c;
|
||||||
if (found == 1) {
|
if (found == 1) {
|
||||||
/* only one left, enable DATA_B3 too */
|
/* only one left, enable DATA_B3 too */
|
||||||
p_list[5] |= 0x30;
|
p_list[5] |= 0x30;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
||||||
|
datapath |= 0x0000000c;
|
||||||
|
}
|
||||||
|
|
||||||
capi_sendf(NULL, 0, CAPI_FACILITY_REQ, plci, get_capi_MessageNumber(),
|
capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
|
||||||
"w(w(dc))",
|
"w(w(dc))",
|
||||||
FACILITYSELECTOR_LINE_INTERCONNECT,
|
FACILITYSELECTOR_LINE_INTERCONNECT,
|
||||||
0x0001, /* CONNECT */
|
0x0001, /* CONNECT */
|
||||||
|
@ -105,7 +114,7 @@ static void del_chat_member(struct capichat_s *room)
|
||||||
struct capichat_s *tmproom;
|
struct capichat_s *tmproom;
|
||||||
struct capichat_s *tmproom2 = NULL;
|
struct capichat_s *tmproom2 = NULL;
|
||||||
unsigned int roomnumber = room->number;
|
unsigned int roomnumber = room->number;
|
||||||
_cdword plci = room->plci;
|
struct capi_pvt *i = room->i;
|
||||||
|
|
||||||
cc_mutex_lock(&chat_lock);
|
cc_mutex_lock(&chat_lock);
|
||||||
tmproom = chat_list;
|
tmproom = chat_list;
|
||||||
|
@ -125,7 +134,7 @@ static void del_chat_member(struct capichat_s *room)
|
||||||
}
|
}
|
||||||
cc_mutex_unlock(&chat_lock);
|
cc_mutex_unlock(&chat_lock);
|
||||||
|
|
||||||
update_capi_mixer(1, roomnumber, plci);
|
update_capi_mixer(1, roomnumber, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -149,7 +158,6 @@ static struct capichat_s *add_chat_member(char *roomname,
|
||||||
room->name[sizeof(room->name) - 1] = 0;
|
room->name[sizeof(room->name) - 1] = 0;
|
||||||
room->chan = chan;
|
room->chan = chan;
|
||||||
room->i = i;
|
room->i = i;
|
||||||
room->plci = i->PLCI;
|
|
||||||
|
|
||||||
cc_mutex_lock(&chat_lock);
|
cc_mutex_lock(&chat_lock);
|
||||||
|
|
||||||
|
@ -176,11 +184,85 @@ static struct capichat_s *add_chat_member(char *roomname,
|
||||||
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' (%d)\n",
|
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' (%d)\n",
|
||||||
i->vname, roomname, roomnumber);
|
i->vname, roomname, roomnumber);
|
||||||
|
|
||||||
update_capi_mixer(0, roomnumber, room->plci);
|
update_capi_mixer(0, roomnumber, i);
|
||||||
|
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* loop during chat
|
||||||
|
*/
|
||||||
|
static void chat_handle_events(struct ast_channel *chan, struct capi_pvt *i)
|
||||||
|
{
|
||||||
|
struct ast_frame *f;
|
||||||
|
int ms;
|
||||||
|
int exception;
|
||||||
|
int ready_fd;
|
||||||
|
int waitfds[1];
|
||||||
|
int nfds = 0;
|
||||||
|
struct ast_channel *rchan;
|
||||||
|
|
||||||
|
waitfds[0] = i->readerfd;
|
||||||
|
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
||||||
|
nfds = 1;
|
||||||
|
ast_set_read_format(chan, capi_capability);
|
||||||
|
ast_set_write_format(chan, capi_capability);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
|
||||||
|
cc_log(LOG_NOTICE, "%s: is zombie.\n", chan->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ast_check_hangup(chan)) {
|
||||||
|
cc_log(LOG_NOTICE, "%s: got check_hangup.\n", chan->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ready_fd = 0;
|
||||||
|
ms = 100;
|
||||||
|
errno = 0;
|
||||||
|
exception = 0;
|
||||||
|
|
||||||
|
rchan = ast_waitfor_nandfds(&chan, 1, waitfds, nfds, &exception, &ready_fd, &ms);
|
||||||
|
|
||||||
|
if (rchan) {
|
||||||
|
f = ast_read(chan);
|
||||||
|
if (!f) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
|
||||||
|
ast_frfree(f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (f->frametype == AST_FRAME_VOICE) {
|
||||||
|
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
||||||
|
capi_write_frame(i, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast_frfree(f);
|
||||||
|
} else if (ready_fd == i->readerfd) {
|
||||||
|
if (exception) {
|
||||||
|
cc_verbose(1, 0, VERBOSE_PREFIX_3 "%s: chat: exception on readerfd\n",
|
||||||
|
i->vname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f = capi_read_pipeframe(i);
|
||||||
|
if (f->frametype == AST_FRAME_VOICE) {
|
||||||
|
ast_write(chan, f);
|
||||||
|
}
|
||||||
|
/* ignore other nullplci frames */
|
||||||
|
} else {
|
||||||
|
if ((ready_fd < 0) && ms) {
|
||||||
|
if (errno == 0 || errno == EINTR)
|
||||||
|
continue;
|
||||||
|
cc_log(LOG_WARNING, "%s: Wait failed (%s).\n",
|
||||||
|
chan->name, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* start the chat
|
* start the chat
|
||||||
*/
|
*/
|
||||||
|
@ -189,7 +271,6 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
||||||
struct capi_pvt *i = NULL;
|
struct capi_pvt *i = NULL;
|
||||||
char *roomname, *controller, *options;
|
char *roomname, *controller, *options;
|
||||||
struct capichat_s *room;
|
struct capichat_s *room;
|
||||||
struct ast_frame *f;
|
|
||||||
int state;
|
int state;
|
||||||
unsigned int contr = 1;
|
unsigned int contr = 1;
|
||||||
|
|
||||||
|
@ -214,7 +295,7 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
||||||
i = CC_CHANNEL_PVT(c);
|
i = CC_CHANNEL_PVT(c);
|
||||||
} else {
|
} else {
|
||||||
/* virtual CAPI channel */
|
/* virtual CAPI channel */
|
||||||
i = mknullif(c, contr);
|
i = capi_mknullif(c, contr);
|
||||||
if (!i) {
|
if (!i) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -234,15 +315,7 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ast_waitfor(c, 500) >= 0) {
|
chat_handle_events(c, i);
|
||||||
f = ast_read(c);
|
|
||||||
if (f) {
|
|
||||||
ast_frfree(f);
|
|
||||||
} else {
|
|
||||||
/* channel was hung up or something else happened */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
del_chat_member(room);
|
del_chat_member(room);
|
||||||
|
|
||||||
|
|
|
@ -778,7 +778,7 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
|
||||||
i->qsig_data.calltransfer = 1;
|
i->qsig_data.calltransfer = 1;
|
||||||
i->qsig_data.partner_plci = atoi(pp);
|
i->qsig_data.partner_plci = atoi(pp);
|
||||||
/* set the other channel as partner to me */
|
/* set the other channel as partner to me */
|
||||||
struct capi_pvt *ii = find_interface_by_plci(i->qsig_data.partner_plci);
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
||||||
if (ii)
|
if (ii)
|
||||||
ii->qsig_data.partner_plci = i->PLCI;
|
ii->qsig_data.partner_plci = i->PLCI;
|
||||||
|
|
||||||
|
@ -794,7 +794,7 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
|
||||||
i->qsig_data.calltransfer_onring = 1;
|
i->qsig_data.calltransfer_onring = 1;
|
||||||
i->qsig_data.partner_plci = atoi(pp);
|
i->qsig_data.partner_plci = atoi(pp);
|
||||||
/* set the other channel as partner to me */
|
/* set the other channel as partner to me */
|
||||||
struct capi_pvt *ii = find_interface_by_plci(i->qsig_data.partner_plci);
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
||||||
if (ii)
|
if (ii)
|
||||||
ii->qsig_data.partner_plci = i->PLCI;
|
ii->qsig_data.partner_plci = i->PLCI;
|
||||||
|
|
||||||
|
@ -948,7 +948,7 @@ int pbx_capi_qsig_ct(struct ast_channel *c, char *param)
|
||||||
callmark = atoi(marker);
|
callmark = atoi(marker);
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_CT: using call marker %i(%s)\n", callmark, marker);
|
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_CT: using call marker %i(%s)\n", callmark, marker);
|
||||||
|
|
||||||
for (ii = iflist; ii; ii = ii->next) {
|
for (ii = capi_iflist; ii; ii = ii->next) {
|
||||||
if (ii->qsig_data.callmark == callmark)
|
if (ii->qsig_data.callmark == callmark)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1031,7 +1031,7 @@ void pbx_capi_qsig_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsign
|
||||||
qsiginvoke = cc_qsig_handle_capi_facilityind( (unsigned char*) INFO_IND_INFOELEMENT(CMSG), i);
|
qsiginvoke = cc_qsig_handle_capi_facilityind( (unsigned char*) INFO_IND_INFOELEMENT(CMSG), i);
|
||||||
/*
|
/*
|
||||||
if (i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) {
|
if (i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) {
|
||||||
struct capi_pvt *ii = find_interface_by_plci(i->qsig_data.partner_plci);
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
||||||
|
|
||||||
if (ii) {
|
if (ii) {
|
||||||
unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE];
|
unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE];
|
||||||
|
@ -1077,7 +1077,7 @@ void pbx_capi_qsig_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsign
|
||||||
/* TODO: some checks, if there's any work here */
|
/* TODO: some checks, if there's any work here */
|
||||||
if (i->qsig_data.calltransfer_onring) {
|
if (i->qsig_data.calltransfer_onring) {
|
||||||
unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE];
|
unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE];
|
||||||
struct capi_pvt *ii = find_interface_by_plci(i->qsig_data.partner_plci);
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
||||||
|
|
||||||
/* needed for Path Replacement */
|
/* needed for Path Replacement */
|
||||||
ii->qsig_data.partner_plci = i->PLCI;
|
ii->qsig_data.partner_plci = i->PLCI;
|
||||||
|
@ -1112,7 +1112,7 @@ void pbx_capi_qsig_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsign
|
||||||
case 0x8007: /* CONNECT */
|
case 0x8007: /* CONNECT */
|
||||||
/* {
|
/* {
|
||||||
if (i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) {
|
if (i->qsig_data.pr_propose_cid && i->qsig_data.pr_propose_pn) {
|
||||||
struct capi_pvt *ii = find_interface_by_plci(i->qsig_data.partner_plci);
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
||||||
|
|
||||||
if (ii) {
|
if (ii) {
|
||||||
unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE];
|
unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE];
|
||||||
|
|
|
@ -158,7 +158,7 @@ static void new_ccbsnr_id(char type, unsigned int plci,
|
||||||
/* if the hangup frame was deferred, it can be done now and here */
|
/* if the hangup frame was deferred, it can be done now and here */
|
||||||
if (i->whentoqueuehangup) {
|
if (i->whentoqueuehangup) {
|
||||||
i->whentoqueuehangup = 0;
|
i->whentoqueuehangup = 0;
|
||||||
queue_cause_control(i, 1);
|
capi_queue_cause_control(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,14 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "xlaw.h"
|
||||||
#include "chan_capi20.h"
|
#include "chan_capi20.h"
|
||||||
#include "chan_capi.h"
|
#include "chan_capi.h"
|
||||||
|
#include "chan_capi_rtp.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
#include "chan_capi_supplementary.h"
|
#include "chan_capi_supplementary.h"
|
||||||
|
|
||||||
|
@ -51,6 +57,16 @@ void cc_verbose(int o_v, int c_d, char *text, ...)
|
||||||
vsnprintf(line, sizeof(line), text, ap);
|
vsnprintf(line, sizeof(line), text, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
if ((fp = fopen("/tmp/cclog", "a")) != NULL) {
|
||||||
|
fprintf(fp, "%s", line);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((o_v == 0) || (option_verbose > o_v)) {
|
if ((o_v == 0) || (option_verbose > o_v)) {
|
||||||
if ((!c_d) || ((c_d) && (capidebug))) {
|
if ((!c_d) || ((c_d) && (capidebug))) {
|
||||||
cc_mutex_lock(&verbose_lock);
|
cc_mutex_lock(&verbose_lock);
|
||||||
|
@ -83,6 +99,8 @@ int capi_remove_nullif(struct capi_pvt *i)
|
||||||
}
|
}
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: removed null-interface.\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: removed null-interface.\n",
|
||||||
i->vname);
|
i->vname);
|
||||||
|
if (i->smoother)
|
||||||
|
ast_smoother_free(i->smoother);
|
||||||
free(i);
|
free(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +115,7 @@ int capi_remove_nullif(struct capi_pvt *i)
|
||||||
/*
|
/*
|
||||||
* create new null-interface
|
* create new null-interface
|
||||||
*/
|
*/
|
||||||
struct capi_pvt *mknullif(struct ast_channel *c, unsigned int controller)
|
struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned int controller)
|
||||||
{
|
{
|
||||||
struct capi_pvt *tmp;
|
struct capi_pvt *tmp;
|
||||||
|
|
||||||
|
@ -127,6 +145,13 @@ struct capi_pvt *mknullif(struct ast_channel *c, unsigned int controller)
|
||||||
tmp->ecTail = EC_DEFAULT_TAIL;
|
tmp->ecTail = EC_DEFAULT_TAIL;
|
||||||
tmp->isdnmode = CAPI_ISDNMODE_MSN;
|
tmp->isdnmode = CAPI_ISDNMODE_MSN;
|
||||||
tmp->ecSelector = FACILITYSELECTOR_ECHO_CANCEL;
|
tmp->ecSelector = FACILITYSELECTOR_ECHO_CANCEL;
|
||||||
|
|
||||||
|
if (!(capi_create_reader_writer_pipe(tmp))) {
|
||||||
|
free(tmp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp->smoother = ast_smoother_new(CAPI_MAX_B3_BLOCK_SIZE);
|
||||||
|
|
||||||
cc_mutex_lock(&nullif_lock);
|
cc_mutex_lock(&nullif_lock);
|
||||||
tmp->next = nulliflist; /* prepend */
|
tmp->next = nulliflist; /* prepend */
|
||||||
|
@ -171,14 +196,14 @@ _cword get_capi_MessageNumber(void)
|
||||||
/*
|
/*
|
||||||
* find the interface (pvt) the PLCI belongs to
|
* find the interface (pvt) the PLCI belongs to
|
||||||
*/
|
*/
|
||||||
struct capi_pvt *find_interface_by_plci(unsigned int plci)
|
struct capi_pvt *capi_find_interface_by_plci(unsigned int plci)
|
||||||
{
|
{
|
||||||
struct capi_pvt *i;
|
struct capi_pvt *i;
|
||||||
|
|
||||||
if (plci == 0)
|
if (plci == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if (i->PLCI == plci)
|
if (i->PLCI == plci)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -196,14 +221,14 @@ struct capi_pvt *find_interface_by_plci(unsigned int plci)
|
||||||
/*
|
/*
|
||||||
* find the interface (pvt) the messagenumber belongs to
|
* find the interface (pvt) the messagenumber belongs to
|
||||||
*/
|
*/
|
||||||
struct capi_pvt *find_interface_by_msgnum(unsigned short msgnum)
|
struct capi_pvt *capi_find_interface_by_msgnum(unsigned short msgnum)
|
||||||
{
|
{
|
||||||
struct capi_pvt *i;
|
struct capi_pvt *i;
|
||||||
|
|
||||||
if (msgnum == 0x0000)
|
if (msgnum == 0x0000)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (i = iflist; i; i = i->next) {
|
for (i = capi_iflist; i; i = i->next) {
|
||||||
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
|
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -813,7 +838,7 @@ void show_capi_info(struct capi_pvt *i, _cword info)
|
||||||
/*
|
/*
|
||||||
* send Listen to specified controller
|
* send Listen to specified controller
|
||||||
*/
|
*/
|
||||||
unsigned ListenOnController(unsigned int CIPmask, unsigned controller)
|
unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller)
|
||||||
{
|
{
|
||||||
MESSAGE_EXCHANGE_ERROR error;
|
MESSAGE_EXCHANGE_ERROR error;
|
||||||
int waitcount = 50;
|
int waitcount = 50;
|
||||||
|
@ -880,7 +905,7 @@ char *capi_number_func(unsigned char *data, unsigned int strip, char *buf)
|
||||||
/*
|
/*
|
||||||
* parse the dialstring
|
* parse the dialstring
|
||||||
*/
|
*/
|
||||||
void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid)
|
void capi_parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid)
|
||||||
{
|
{
|
||||||
int cp = 0;
|
int cp = 0;
|
||||||
char *buffer_p = buffer;
|
char *buffer_p = buffer;
|
||||||
|
@ -973,3 +998,201 @@ struct ast_channel *cc_get_peer_link_id(const char *p)
|
||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create pipe for interface connection
|
||||||
|
*/
|
||||||
|
int capi_create_reader_writer_pipe(struct capi_pvt *i)
|
||||||
|
{
|
||||||
|
int fds[2];
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
if (pipe(fds) != 0) {
|
||||||
|
cc_log(LOG_ERROR, "%s: unable to create pipe.\n",
|
||||||
|
i->vname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
i->readerfd = fds[0];
|
||||||
|
i->writerfd = fds[1];
|
||||||
|
flags = fcntl(i->readerfd, F_GETFL);
|
||||||
|
fcntl(i->readerfd, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
flags = fcntl(i->writerfd, F_GETFL);
|
||||||
|
fcntl(i->writerfd, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read a frame from the pipe
|
||||||
|
*/
|
||||||
|
struct ast_frame *capi_read_pipeframe(struct capi_pvt *i)
|
||||||
|
{
|
||||||
|
struct ast_frame *f;
|
||||||
|
int readsize;
|
||||||
|
|
||||||
|
if (i == NULL) {
|
||||||
|
cc_log(LOG_ERROR, "channel has no interface\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (i->readerfd == -1) {
|
||||||
|
cc_log(LOG_ERROR, "no readerfd\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = &i->f;
|
||||||
|
f->frametype = AST_FRAME_NULL;
|
||||||
|
f->subclass = 0;
|
||||||
|
|
||||||
|
readsize = read(i->readerfd, f, sizeof(struct ast_frame));
|
||||||
|
if ((readsize != sizeof(struct ast_frame)) && (readsize > 0)) {
|
||||||
|
cc_log(LOG_ERROR, "did not read a whole frame (len=%d, err=%d)\n",
|
||||||
|
readsize, errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
f->mallocd = 0;
|
||||||
|
f->data = NULL;
|
||||||
|
|
||||||
|
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) {
|
||||||
|
if (f->datalen > sizeof(i->frame_data)) {
|
||||||
|
cc_log(LOG_ERROR, "f.datalen(%d) greater than space of frame_data(%d)\n",
|
||||||
|
f->datalen, sizeof(i->frame_data));
|
||||||
|
f->datalen = sizeof(i->frame_data);
|
||||||
|
}
|
||||||
|
readsize = read(i->readerfd, i->frame_data + AST_FRIENDLY_OFFSET, f->datalen);
|
||||||
|
if (readsize != f->datalen) {
|
||||||
|
cc_log(LOG_ERROR, "did not read whole frame data\n");
|
||||||
|
}
|
||||||
|
f->data = i->frame_data + AST_FRIENDLY_OFFSET;
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* write for a channel
|
||||||
|
*/
|
||||||
|
int capi_write_frame(struct capi_pvt *i, struct ast_frame *f)
|
||||||
|
{
|
||||||
|
struct ast_channel *c;
|
||||||
|
MESSAGE_EXCHANGE_ERROR error;
|
||||||
|
int j = 0;
|
||||||
|
unsigned char *buf;
|
||||||
|
struct ast_frame *fsmooth;
|
||||||
|
int txavg=0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!i) {
|
||||||
|
cc_log(LOG_ERROR, "channel has no interface\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
c = i->owner;
|
||||||
|
|
||||||
|
if ((!(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) || (!i->NCCI) ||
|
||||||
|
((i->isdnstate & (CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI)))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!(i->ntmode)) && (i->state != CAPI_STATE_CONNECTED)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->frametype == AST_FRAME_NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (f->frametype == AST_FRAME_DTMF) {
|
||||||
|
cc_log(LOG_ERROR, "dtmf frame should be written\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (f->frametype != AST_FRAME_VOICE) {
|
||||||
|
cc_log(LOG_ERROR,"not a voice frame\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (i->FaxState & CAPI_FAX_STATE_ACTIVE) {
|
||||||
|
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax activity?\n",
|
||||||
|
i->vname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((!f->data) || (!f->datalen)) {
|
||||||
|
cc_log(LOG_DEBUG, "No data for FRAME_VOICE %s\n", c->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (i->isdnstate & CAPI_ISDN_STATE_RTP) {
|
||||||
|
if ((!(f->subclass & i->codec)) &&
|
||||||
|
(f->subclass != capi_capability)) {
|
||||||
|
cc_log(LOG_ERROR, "don't know how to write subclass %s(%d)\n",
|
||||||
|
ast_getformatname(f->subclass), f->subclass);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return capi_write_rtp(c, f);
|
||||||
|
}
|
||||||
|
if (i->B3count >= CAPI_MAX_B3_BLOCKS) {
|
||||||
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: B3count is full, dropping packet.\n",
|
||||||
|
i->vname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) {
|
||||||
|
cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (fsmooth = ast_smoother_read(i->smoother);
|
||||||
|
fsmooth != NULL;
|
||||||
|
fsmooth = ast_smoother_read(i->smoother)) {
|
||||||
|
buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) *
|
||||||
|
(CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)]);
|
||||||
|
i->send_buffer_handle++;
|
||||||
|
|
||||||
|
if ((i->doES == 1) && (!capi_tcap_is_digital(c->transfercapability))) {
|
||||||
|
for (j = 0; j < fsmooth->datalen; j++) {
|
||||||
|
buf[j] = capi_reversebits[ ((unsigned char *)fsmooth->data)[j] ];
|
||||||
|
if (capi_capability == AST_FORMAT_ULAW) {
|
||||||
|
txavg += abs( capiULAW2INT[capi_reversebits[ ((unsigned char*)fsmooth->data)[j]]] );
|
||||||
|
} else {
|
||||||
|
txavg += abs( capiALAW2INT[capi_reversebits[ ((unsigned char*)fsmooth->data)[j]]] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
txavg = txavg / j;
|
||||||
|
for(j = 0; j < ECHO_TX_COUNT - 1; j++) {
|
||||||
|
i->txavg[j] = i->txavg[j+1];
|
||||||
|
}
|
||||||
|
i->txavg[ECHO_TX_COUNT - 1] = txavg;
|
||||||
|
} else {
|
||||||
|
if ((i->txgain == 1.0) || (capi_tcap_is_digital(c->transfercapability))) {
|
||||||
|
for (j = 0; j < fsmooth->datalen; j++) {
|
||||||
|
buf[j] = capi_reversebits[((unsigned char *)fsmooth->data)[j]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (j = 0; j < fsmooth->datalen; j++) {
|
||||||
|
buf[j] = i->g.txgains[capi_reversebits[((unsigned char *)fsmooth->data)[j]]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error = 1;
|
||||||
|
if (i->B3q > 0) {
|
||||||
|
error = capi_sendf(NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(),
|
||||||
|
"dwww",
|
||||||
|
buf,
|
||||||
|
fsmooth->datalen,
|
||||||
|
i->send_buffer_handle,
|
||||||
|
0);
|
||||||
|
} else {
|
||||||
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: too much voice to send for NCCI=%#x\n",
|
||||||
|
i->vname, i->NCCI);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
cc_mutex_lock(&i->lock);
|
||||||
|
i->B3count++;
|
||||||
|
i->B3q -= fsmooth->datalen;
|
||||||
|
if (i->B3q < 0)
|
||||||
|
i->B3q = 0;
|
||||||
|
cc_mutex_unlock(&i->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,19 +22,22 @@ extern char *emptyid;
|
||||||
|
|
||||||
extern void cc_verbose(int o_v, int c_d, char *text, ...);
|
extern void cc_verbose(int o_v, int c_d, char *text, ...);
|
||||||
extern _cword get_capi_MessageNumber(void);
|
extern _cword get_capi_MessageNumber(void);
|
||||||
extern struct capi_pvt *find_interface_by_msgnum(unsigned short msgnum);
|
extern struct capi_pvt *capi_find_interface_by_msgnum(unsigned short msgnum);
|
||||||
extern struct capi_pvt *find_interface_by_plci(unsigned int plci);
|
extern struct capi_pvt *capi_find_interface_by_plci(unsigned int plci);
|
||||||
extern MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd);
|
extern MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd);
|
||||||
extern MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG);
|
extern MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG);
|
||||||
extern char *capi_info_string(unsigned int info);
|
extern char *capi_info_string(unsigned int info);
|
||||||
extern void show_capi_info(struct capi_pvt *i, _cword info);
|
extern void show_capi_info(struct capi_pvt *i, _cword info);
|
||||||
extern unsigned ListenOnController(unsigned int CIPmask, unsigned controller);
|
extern unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller);
|
||||||
extern void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid);
|
extern void capi_parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid);
|
||||||
extern char *capi_number_func(unsigned char *data, unsigned int strip, char *buf);
|
extern char *capi_number_func(unsigned char *data, unsigned int strip, char *buf);
|
||||||
extern int cc_add_peer_link_id(struct ast_channel *c);
|
extern int cc_add_peer_link_id(struct ast_channel *c);
|
||||||
extern struct ast_channel *cc_get_peer_link_id(const char *p);
|
extern struct ast_channel *cc_get_peer_link_id(const char *p);
|
||||||
extern int capi_remove_nullif(struct capi_pvt *i);
|
extern int capi_remove_nullif(struct capi_pvt *i);
|
||||||
extern struct capi_pvt *mknullif(struct ast_channel *c, unsigned int controller);
|
extern struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned int controller);
|
||||||
|
extern int capi_create_reader_writer_pipe(struct capi_pvt *i);
|
||||||
|
extern struct ast_frame *capi_read_pipeframe(struct capi_pvt *i);
|
||||||
|
extern int capi_write_frame(struct capi_pvt *i, struct ast_frame *f);
|
||||||
|
|
||||||
#define capi_number(data, strip) \
|
#define capi_number(data, strip) \
|
||||||
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
||||||
|
|
Loading…
Reference in New Issue