parent
1b125d4d7e
commit
1b50367e34
2
Makefile
2
Makefile
|
@ -92,7 +92,7 @@ INSTALL=install
|
|||
|
||||
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_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
|
||||
AST_MUTEX_DEFINE_STATIC(iflock);
|
||||
|
||||
static int capi_capability = AST_FORMAT_ALAW;
|
||||
|
||||
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 int capi_num_controllers = 0;
|
||||
|
@ -162,6 +160,8 @@ static char capi_international_prefix[AST_MAX_EXTENSION];
|
|||
|
||||
static char default_language[MAX_LANGUAGE] = "";
|
||||
|
||||
int capi_capability = AST_FORMAT_ALAW;
|
||||
|
||||
#ifdef CC_AST_HAS_VERSION_1_4
|
||||
/* Global jitterbuffer configuration - by default, jb is disabled */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
|
@ -365,7 +365,7 @@ static int tcap2cip(unsigned short tcap)
|
|||
return CAPI_CIPI_SPEECH;
|
||||
}
|
||||
|
||||
static unsigned char tcap_is_digital(unsigned short tcap)
|
||||
unsigned char capi_tcap_is_digital(unsigned short tcap)
|
||||
{
|
||||
int x;
|
||||
|
||||
|
@ -493,7 +493,7 @@ static void capi_echo_canceller(struct capi_pvt *i, int function)
|
|||
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",
|
||||
i->vname, i->PLCI);
|
||||
return;
|
||||
|
@ -535,7 +535,7 @@ static int capi_detect_dtmf(struct capi_pvt *i, int flag)
|
|||
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",
|
||||
i->vname, i->PLCI);
|
||||
return 0;
|
||||
|
@ -590,17 +590,6 @@ static int local_queue_frame(struct capi_pvt *i, struct ast_frame *f)
|
|||
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 there is no PBX running yet,
|
||||
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;
|
||||
|
||||
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 */
|
||||
i->doB3 = CAPI_B3_DONT;
|
||||
|
@ -1213,7 +1202,7 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout)
|
|||
dsa = calledsubaddress;
|
||||
}
|
||||
|
||||
if (tcap_is_digital(c->transfercapability)) {
|
||||
if (capi_tcap_is_digital(c->transfercapability)) {
|
||||
i->bproto = CC_BPROTO_TRANSPARENT;
|
||||
cc_verbose(4, 0, VERBOSE_PREFIX_2 "%s: is digital call, set proto to TRANSPARENT\n",
|
||||
i->vname);
|
||||
|
@ -1358,7 +1347,7 @@ static int pbx_capi_answer(struct ast_channel *c)
|
|||
i->bproto = CC_BPROTO_TRANSPARENT;
|
||||
|
||||
if (i->rtp) {
|
||||
if (!tcap_is_digital(c->transfercapability))
|
||||
if (!capi_tcap_is_digital(c->transfercapability))
|
||||
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)
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
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 = capi_read_pipeframe(i);
|
||||
|
||||
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;
|
||||
if ((f) && (f->frametype == AST_FRAME_VOICE) && (f->datalen > 0)) {
|
||||
if ((i->doDTMF > 0) && (i->vad != NULL) ) {
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!i) {
|
||||
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;
|
||||
}
|
||||
ret = capi_write_frame(i, f);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1793,8 +1635,6 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
|
|||
{
|
||||
struct ast_channel *tmp;
|
||||
int fmt;
|
||||
int fds[2];
|
||||
int flags;
|
||||
|
||||
#ifdef CC_AST_HAS_EXT_CHAN_ALLOC
|
||||
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;
|
||||
#endif
|
||||
|
||||
if (pipe(fds) != 0) {
|
||||
cc_log(LOG_ERROR, "%s: unable to create pipe.\n",
|
||||
i->vname);
|
||||
if (!(capi_create_reader_writer_pipe(i))) {
|
||||
ast_channel_free(tmp);
|
||||
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;
|
||||
|
||||
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_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)) {
|
||||
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);
|
||||
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if ((i->used) || (i->channeltype != CAPI_CHANNELTYPE_B)) {
|
||||
/* if already in use or no real channel */
|
||||
continue;
|
||||
|
@ -2527,7 +2358,7 @@ static void capidev_handle_did_digits(_cmsg *CMSG, unsigned int PLCI, unsigned i
|
|||
/*
|
||||
* 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, };
|
||||
|
||||
|
@ -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",
|
||||
i->vname);
|
||||
if (i->state == CAPI_STATE_CONNECTED) {
|
||||
queue_cause_control(i, 0);
|
||||
capi_queue_cause_control(i, 0);
|
||||
} else {
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) {
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online hangup frame queued.\n",
|
||||
i->vname);
|
||||
i->whentoqueuehangup = time(NULL) + 1;
|
||||
} else {
|
||||
queue_cause_control(i, 1);
|
||||
capi_queue_cause_control(i, 1);
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
cc_verbose(4, 1, VERBOSE_PREFIX_3 "%s: Disconnect case 2\n",
|
||||
i->vname);
|
||||
queue_cause_control(i, 1);
|
||||
capi_queue_cause_control(i, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2601,7 +2432,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
capi_send_disconnect(i->PLCI, NULL);
|
||||
return;
|
||||
}
|
||||
queue_cause_control(i, 0);
|
||||
capi_queue_cause_control(i, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2611,7 +2442,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
i->vname);
|
||||
if ((i->state == CAPI_STATE_CONNECTED) &&
|
||||
(i->isdnstate & CAPI_ISDN_STATE_B3_UP)) {
|
||||
queue_cause_control(i, 1);
|
||||
capi_queue_cause_control(i, 1);
|
||||
return;
|
||||
}
|
||||
/* 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->owner) &&
|
||||
(i->owner->hangupcause == AST_CAUSE_USER_BUSY)) {
|
||||
queue_cause_control(i, 1);
|
||||
capi_queue_cause_control(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3041,13 +2872,13 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un
|
|||
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++) {
|
||||
*(b3buf + j) = reversebits[*(b3buf + j)];
|
||||
*(b3buf + j) = capi_reversebits[*(b3buf + j)];
|
||||
if (capi_capability == AST_FORMAT_ULAW) {
|
||||
rxavg += abs(capiULAW2INT[ reversebits[*(b3buf + j)]]);
|
||||
rxavg += abs(capiULAW2INT[ capi_reversebits[*(b3buf + j)]]);
|
||||
} else {
|
||||
rxavg += abs(capiALAW2INT[ reversebits[*(b3buf + j)]]);
|
||||
rxavg += abs(capiALAW2INT[ capi_reversebits[*(b3buf + 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);
|
||||
}
|
||||
} 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++) {
|
||||
*(b3buf + j) = reversebits[*(b3buf + j)];
|
||||
*(b3buf + j) = capi_reversebits[*(b3buf + j)];
|
||||
}
|
||||
} else {
|
||||
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 */
|
||||
cc_mutex_lock(&iflock);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if (i->used) {
|
||||
/* is already used */
|
||||
continue;
|
||||
|
@ -3541,7 +3372,7 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un
|
|||
break;
|
||||
}
|
||||
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->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");
|
||||
return;
|
||||
}
|
||||
*i = find_interface_by_msgnum(wMsgNum);
|
||||
*i = capi_find_interface_by_msgnum(wMsgNum);
|
||||
ii = *i;
|
||||
if (ii == NULL) {
|
||||
return;
|
||||
|
@ -3764,7 +3595,7 @@ static void capidev_handle_msg(_cmsg *CMSG)
|
|||
unsigned short wCmd = HEADER_CMD(CMSG);
|
||||
unsigned short wMsgNum = HEADER_MSGNUM(CMSG);
|
||||
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)) ||
|
||||
(wCmd == CAPI_P_CONF(DATA_B3))) {
|
||||
|
@ -4020,7 +3851,7 @@ static int pbx_capi_retrieve(struct ast_channel *c, char *param)
|
|||
if (param) {
|
||||
plci = (unsigned int)strtoul(param, NULL, 0);
|
||||
cc_mutex_lock(&iflock);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if (i->onholdPLCI == plci)
|
||||
break;
|
||||
}
|
||||
|
@ -4107,7 +3938,7 @@ static int pbx_capi_ect(struct ast_channel *c, char *param)
|
|||
}
|
||||
|
||||
cc_mutex_lock(&iflock);
|
||||
for (ii = iflist; ii; ii = ii->next) {
|
||||
for (ii = capi_iflist; ii; ii = ii->next) {
|
||||
if (ii->onholdPLCI == plci)
|
||||
break;
|
||||
}
|
||||
|
@ -4351,7 +4182,7 @@ static int pbx_capi_realhangup(struct ast_channel *c, char *param)
|
|||
struct capi_pvt *i;
|
||||
|
||||
cc_mutex_lock(&iflock);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if (i->peer == c)
|
||||
break;
|
||||
}
|
||||
|
@ -4424,7 +4255,7 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param)
|
|||
}
|
||||
|
||||
cc_mutex_lock(&iflock);
|
||||
for (ii = iflist; ii; ii = ii->next) {
|
||||
for (ii = capi_iflist; ii; ii = ii->next) {
|
||||
if (ii->onholdPLCI == plci)
|
||||
break;
|
||||
}
|
||||
|
@ -4755,7 +4586,7 @@ static void capidev_run_secondly(time_t now)
|
|||
|
||||
/* check for channels to hangup (timeout) */
|
||||
cc_mutex_lock(&iflock);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if (i->used == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
@ -4768,7 +4599,7 @@ static void capidev_run_secondly(time_t now)
|
|||
if ((i->whentoqueuehangup) && (i->whentoqueuehangup < now)) {
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online queue-hangup.\n",
|
||||
i->vname);
|
||||
queue_cause_control(i, 1);
|
||||
capi_queue_cause_control(i, 1);
|
||||
i->whentoqueuehangup = 0;
|
||||
}
|
||||
}
|
||||
|
@ -4961,8 +4792,8 @@ int mkif(struct cc_capi_conf *conf)
|
|||
|
||||
tmp->qsigfeat = conf->qsigfeat;
|
||||
|
||||
tmp->next = iflist; /* prepend */
|
||||
iflist = tmp;
|
||||
tmp->next = capi_iflist; /* prepend */
|
||||
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",
|
||||
(tmp->channeltype == CAPI_CHANNELTYPE_B)? 'B' : 'D',
|
||||
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);
|
||||
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if (i->channeltype != CAPI_CHANNELTYPE_B)
|
||||
continue;
|
||||
|
||||
|
@ -5472,7 +5303,7 @@ static int cc_post_init_capi(void)
|
|||
int rtp_ext_size = 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
|
||||
bigger block size for RTP-header */
|
||||
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++) {
|
||||
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",
|
||||
controller, error);
|
||||
} else {
|
||||
|
@ -5817,7 +5648,7 @@ int unload_module(void)
|
|||
}
|
||||
}
|
||||
|
||||
i = iflist;
|
||||
i = capi_iflist;
|
||||
while (i) {
|
||||
if ((i->owner) || (i->used))
|
||||
cc_log(LOG_WARNING, "On unload, interface still has owner or is used.\n");
|
||||
|
|
|
@ -568,10 +568,12 @@ struct cc_capi_controller {
|
|||
* prototypes
|
||||
*/
|
||||
extern const struct ast_channel_tech capi_tech;
|
||||
extern int capi_capability;
|
||||
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 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,
|
||||
unsigned short wInfo, unsigned short wMsgNum);
|
||||
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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
#include "chan_capi20.h"
|
||||
#include "chan_capi.h"
|
||||
|
@ -27,7 +29,6 @@ struct capichat_s {
|
|||
unsigned int number;
|
||||
struct ast_channel *chan;
|
||||
struct capi_pvt *i;
|
||||
_cdword plci;
|
||||
struct capichat_s *next;
|
||||
};
|
||||
|
||||
|
@ -37,8 +38,9 @@ AST_MUTEX_DEFINE_STATIC(chat_lock);
|
|||
/*
|
||||
* 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;
|
||||
unsigned char p_list[360];
|
||||
_cdword dest;
|
||||
|
@ -51,18 +53,22 @@ static void update_capi_mixer(int remove, unsigned int roomnumber, _cdword plci)
|
|||
room = chat_list;
|
||||
while (room) {
|
||||
if ((room->number == roomnumber) &&
|
||||
(room->plci != plci)) {
|
||||
(room->i != i)) {
|
||||
found++;
|
||||
if (j + 9 > sizeof(p_list)) {
|
||||
/* maybe we need to split capi messages here */
|
||||
break;
|
||||
}
|
||||
ii = room->i;
|
||||
p_list[j++] = 8;
|
||||
p_list[j++] = (_cbyte)(room->plci);
|
||||
p_list[j++] = (_cbyte)(room->plci >> 8);
|
||||
p_list[j++] = (_cbyte)(room->plci >> 16);
|
||||
p_list[j++] = (_cbyte)(room->plci >> 24);
|
||||
p_list[j++] = (_cbyte)(ii->PLCI);
|
||||
p_list[j++] = (_cbyte)(ii->PLCI >> 8);
|
||||
p_list[j++] = (_cbyte)(ii->PLCI >> 16);
|
||||
p_list[j++] = (_cbyte)(ii->PLCI >> 24);
|
||||
dest = (remove) ? 0x00000000 : 0x00000003;
|
||||
if (ii->channeltype == CAPI_CHANNELTYPE_NULL) {
|
||||
dest |= 0x00000030;
|
||||
}
|
||||
p_list[j++] = (_cbyte)(dest);
|
||||
p_list[j++] = (_cbyte)(dest >> 8);
|
||||
p_list[j++] = (_cbyte)(dest >> 16);
|
||||
|
@ -80,14 +86,17 @@ static void update_capi_mixer(int remove, unsigned int roomnumber, _cdword plci)
|
|||
datapath = 0x00000000;
|
||||
if (remove) {
|
||||
/* now we need DATA_B3 again */
|
||||
datapath = 0x000000c0;
|
||||
datapath = 0x0000000c;
|
||||
if (found == 1) {
|
||||
/* only one left, enable DATA_B3 too */
|
||||
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))",
|
||||
FACILITYSELECTOR_LINE_INTERCONNECT,
|
||||
0x0001, /* CONNECT */
|
||||
|
@ -105,7 +114,7 @@ static void del_chat_member(struct capichat_s *room)
|
|||
struct capichat_s *tmproom;
|
||||
struct capichat_s *tmproom2 = NULL;
|
||||
unsigned int roomnumber = room->number;
|
||||
_cdword plci = room->plci;
|
||||
struct capi_pvt *i = room->i;
|
||||
|
||||
cc_mutex_lock(&chat_lock);
|
||||
tmproom = chat_list;
|
||||
|
@ -125,7 +134,7 @@ static void del_chat_member(struct capichat_s *room)
|
|||
}
|
||||
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->chan = chan;
|
||||
room->i = i;
|
||||
room->plci = i->PLCI;
|
||||
|
||||
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",
|
||||
i->vname, roomname, roomnumber);
|
||||
|
||||
update_capi_mixer(0, roomnumber, room->plci);
|
||||
update_capi_mixer(0, roomnumber, i);
|
||||
|
||||
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
|
||||
*/
|
||||
|
@ -189,7 +271,6 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
|||
struct capi_pvt *i = NULL;
|
||||
char *roomname, *controller, *options;
|
||||
struct capichat_s *room;
|
||||
struct ast_frame *f;
|
||||
int state;
|
||||
unsigned int contr = 1;
|
||||
|
||||
|
@ -214,7 +295,7 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
|||
i = CC_CHANNEL_PVT(c);
|
||||
} else {
|
||||
/* virtual CAPI channel */
|
||||
i = mknullif(c, contr);
|
||||
i = capi_mknullif(c, contr);
|
||||
if (!i) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -234,15 +315,7 @@ int pbx_capi_chat(struct ast_channel *c, char *param)
|
|||
return -1;
|
||||
}
|
||||
|
||||
while (ast_waitfor(c, 500) >= 0) {
|
||||
f = ast_read(c);
|
||||
if (f) {
|
||||
ast_frfree(f);
|
||||
} else {
|
||||
/* channel was hung up or something else happened */
|
||||
break;
|
||||
}
|
||||
}
|
||||
chat_handle_events(c, i);
|
||||
|
||||
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.partner_plci = atoi(pp);
|
||||
/* 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)
|
||||
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.partner_plci = atoi(pp);
|
||||
/* 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)
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
/*
|
||||
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) {
|
||||
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 */
|
||||
if (i->qsig_data.calltransfer_onring) {
|
||||
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 */
|
||||
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 */
|
||||
/* {
|
||||
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) {
|
||||
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 (i->whentoqueuehangup) {
|
||||
i->whentoqueuehangup = 0;
|
||||
queue_cause_control(i, 1);
|
||||
capi_queue_cause_control(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,14 @@
|
|||
|
||||
#include <stdio.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_capi.h"
|
||||
#include "chan_capi_rtp.h"
|
||||
#include "chan_capi_utils.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);
|
||||
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 ((!c_d) || ((c_d) && (capidebug))) {
|
||||
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",
|
||||
i->vname);
|
||||
if (i->smoother)
|
||||
ast_smoother_free(i->smoother);
|
||||
free(i);
|
||||
break;
|
||||
}
|
||||
|
@ -97,7 +115,7 @@ int capi_remove_nullif(struct capi_pvt *i)
|
|||
/*
|
||||
* 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;
|
||||
|
||||
|
@ -127,6 +145,13 @@ struct capi_pvt *mknullif(struct ast_channel *c, unsigned int controller)
|
|||
tmp->ecTail = EC_DEFAULT_TAIL;
|
||||
tmp->isdnmode = CAPI_ISDNMODE_MSN;
|
||||
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);
|
||||
tmp->next = nulliflist; /* prepend */
|
||||
|
@ -171,14 +196,14 @@ _cword get_capi_MessageNumber(void)
|
|||
/*
|
||||
* 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;
|
||||
|
||||
if (plci == 0)
|
||||
return NULL;
|
||||
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if (i->PLCI == plci)
|
||||
return i;
|
||||
}
|
||||
|
@ -196,14 +221,14 @@ struct capi_pvt *find_interface_by_plci(unsigned int plci)
|
|||
/*
|
||||
* 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;
|
||||
|
||||
if (msgnum == 0x0000)
|
||||
return NULL;
|
||||
|
||||
for (i = iflist; i; i = i->next) {
|
||||
for (i = capi_iflist; i; i = i->next) {
|
||||
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
|
||||
return i;
|
||||
}
|
||||
|
@ -813,7 +838,7 @@ void show_capi_info(struct capi_pvt *i, _cword info)
|
|||
/*
|
||||
* send Listen to specified controller
|
||||
*/
|
||||
unsigned ListenOnController(unsigned int CIPmask, unsigned controller)
|
||||
unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller)
|
||||
{
|
||||
MESSAGE_EXCHANGE_ERROR error;
|
||||
int waitcount = 50;
|
||||
|
@ -880,7 +905,7 @@ char *capi_number_func(unsigned char *data, unsigned int strip, char *buf)
|
|||
/*
|
||||
* 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;
|
||||
char *buffer_p = buffer;
|
||||
|
@ -973,3 +998,201 @@ struct ast_channel *cc_get_peer_link_id(const char *p)
|
|||
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 _cword get_capi_MessageNumber(void);
|
||||
extern struct capi_pvt *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_msgnum(unsigned short msgnum);
|
||||
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 capidev_check_wait_get_cmsg(_cmsg *CMSG);
|
||||
extern char *capi_info_string(unsigned int info);
|
||||
extern void show_capi_info(struct capi_pvt *i, _cword info);
|
||||
extern unsigned ListenOnController(unsigned int CIPmask, unsigned controller);
|
||||
extern void parse_dialstring(char *buffer, char **interface, char **dest, char **param, char **ocid);
|
||||
extern unsigned capi_ListenOnController(unsigned int CIPmask, unsigned controller);
|
||||
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 int cc_add_peer_link_id(struct ast_channel *c);
|
||||
extern struct ast_channel *cc_get_peer_link_id(const char *p);
|
||||
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) \
|
||||
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
||||
|
|
Loading…
Reference in New Issue