- more restructuring

- chat handle null-plci voice frames
This commit is contained in:
MelwareDE 2007-04-29 22:28:30 +00:00
parent 1b125d4d7e
commit 1b50367e34
10 changed files with 2055 additions and 1909 deletions

View File

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

View File

@ -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, &param, &ocid); capi_parse_dialstring(buffer, &interface, &dest, &param, &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, &param, &ocid); capi_parse_dialstring(buffer, &interface, &dest, &param, &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");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1653
xlaw.c Normal file

File diff suppressed because it is too large Load Diff

1657
xlaw.h

File diff suppressed because it is too large Load Diff