Introduce capi_sendf() for easy capi message creation.
This commit is contained in:
parent
9d4968ab3a
commit
e9d1bbe5c5
77
chan_capi.c
77
chan_capi.c
|
@ -513,8 +513,6 @@ static void capi_channel_task(struct ast_channel *c, int task)
|
|||
static void capi_echo_canceller(struct ast_channel *c, int function)
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
_cmsg CMSG;
|
||||
char buf[10];
|
||||
int ecAvail = 0;
|
||||
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_DISCONNECT))
|
||||
|
@ -552,28 +550,20 @@ static void capi_echo_canceller(struct ast_channel *c, int function)
|
|||
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Setting up echo canceller (PLCI=%#x, function=%d, options=%d, tail=%d)\n",
|
||||
i->vname, i->PLCI, function, i->ecOption, i->ecTail);
|
||||
|
||||
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
FACILITY_REQ_PLCI(&CMSG) = i->PLCI;
|
||||
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = i->ecSelector;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] = 9; /* msg size */
|
||||
write_capi_word(&buf[1], function);
|
||||
if (function == EC_FUNCTION_ENABLE) {
|
||||
buf[3] = 6; /* echo cancel param struct size */
|
||||
write_capi_word(&buf[4], i->ecOption); /* bit field - ignore echo canceller disable tone */
|
||||
write_capi_word(&buf[6], i->ecTail); /* Tail length, ms */
|
||||
/* buf 8 and 9 are "pre-delay lenght ms" */
|
||||
i->isdnstate |= CAPI_ISDN_STATE_EC;
|
||||
} else {
|
||||
i->isdnstate &= ~CAPI_ISDN_STATE_EC;
|
||||
}
|
||||
|
||||
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf;
|
||||
|
||||
if (_capi_put_cmsg(&CMSG) != 0) {
|
||||
return;
|
||||
}
|
||||
capi_sendf(CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
|
||||
"w(w(www))",
|
||||
i->ecSelector,
|
||||
function,
|
||||
i->ecOption, /* bit field - ignore echo canceller disable tone */
|
||||
i->ecTail, /* Tail length, ms */
|
||||
0
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -585,8 +575,6 @@ static int capi_detect_dtmf(struct ast_channel *c, int flag)
|
|||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
MESSAGE_EXCHANGE_ERROR error;
|
||||
_cmsg CMSG;
|
||||
char buf[9];
|
||||
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_DISCONNECT))
|
||||
return 0;
|
||||
|
@ -609,23 +597,18 @@ static int capi_detect_dtmf(struct ast_channel *c, int flag)
|
|||
if ((capi_controllers[i->controller]->dtmf != 1) || (i->doDTMF != 0))
|
||||
return 0;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Setting up DTMF detector (PLCI=%#x, flag=%d)\n",
|
||||
i->vname, i->PLCI, flag);
|
||||
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
FACILITY_REQ_PLCI(&CMSG) = i->PLCI;
|
||||
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_DTMF;
|
||||
buf[0] = 8; /* msg length */
|
||||
if (flag == 1) {
|
||||
write_capi_word(&buf[1], 1); /* start DTMF listen */
|
||||
} else {
|
||||
write_capi_word(&buf[1], 2); /* stop DTMF listen */
|
||||
}
|
||||
write_capi_word(&buf[3], CAPI_DTMF_DURATION);
|
||||
write_capi_word(&buf[5], CAPI_DTMF_DURATION);
|
||||
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf;
|
||||
|
||||
if ((error = _capi_put_cmsg(&CMSG)) != 0) {
|
||||
error = capi_sendf(CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
|
||||
"w(www()())",
|
||||
FACILITYSELECTOR_DTMF,
|
||||
(flag == 1) ? 1:2, /* start/stop DTMF listen */
|
||||
CAPI_DTMF_DURATION,
|
||||
CAPI_DTMF_DURATION
|
||||
);
|
||||
|
||||
if (error != 0) {
|
||||
return error;
|
||||
}
|
||||
if (flag == 1) {
|
||||
|
@ -761,8 +744,6 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit)
|
|||
#endif
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
_cmsg CMSG;
|
||||
char buf[10];
|
||||
char did[2];
|
||||
int ret = 0;
|
||||
|
||||
|
@ -771,8 +752,6 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit)
|
|||
return -1;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
cc_mutex_lock(&i->lock);
|
||||
|
||||
if ((c->_state == AST_STATE_DIALING) &&
|
||||
|
@ -800,20 +779,16 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit)
|
|||
cc_mutex_unlock(&i->lock);
|
||||
return -1;
|
||||
}
|
||||
ret = capi_sendf(CAPI_FACILITY_REQ, i->NCCI, get_capi_MessageNumber(),
|
||||
"w(www(b)())",
|
||||
FACILITYSELECTOR_DTMF,
|
||||
3, /* send DTMF digit */
|
||||
CAPI_DTMF_DURATION, /* XXX: duration comes from asterisk in 1.4 */
|
||||
CAPI_DTMF_DURATION,
|
||||
digit
|
||||
);
|
||||
|
||||
FACILITY_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
FACILITY_REQ_PLCI(&CMSG) = i->NCCI;
|
||||
FACILITY_REQ_FACILITYSELECTOR(&CMSG) = FACILITYSELECTOR_DTMF;
|
||||
buf[0] = 8;
|
||||
write_capi_word(&buf[1], 3); /* send DTMF digit */
|
||||
/* XXX: duration comes from asterisk in 1.4 */
|
||||
write_capi_word(&buf[3], CAPI_DTMF_DURATION);
|
||||
write_capi_word(&buf[5], CAPI_DTMF_DURATION);
|
||||
buf[7] = 1;
|
||||
buf[8] = digit;
|
||||
FACILITY_REQ_FACILITYREQUESTPARAMETER(&CMSG) = (_cstruct)buf;
|
||||
|
||||
if ((ret = _capi_put_cmsg(&CMSG)) == 0) {
|
||||
if (ret == 0) {
|
||||
cc_verbose(3, 0, VERBOSE_PREFIX_4 "%s: sent dtmf '%c'\n",
|
||||
i->vname, digit);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
*
|
||||
* Armin Schindler <armin@melware.de>
|
||||
*
|
||||
* capi_sendf() by Eicon Networks / Dialogic
|
||||
*
|
||||
* This program is free software and may be modified and
|
||||
* distributed under the terms of the GNU Public License.
|
||||
*/
|
||||
|
@ -73,6 +75,28 @@ _cword get_capi_MessageNumber(void)
|
|||
return(mn);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void log_capi_message(MESSAGE_EXCHANGE_ERROR err, _cmsg *CMSG)
|
||||
{
|
||||
unsigned short wCmd;
|
||||
|
||||
if (err) {
|
||||
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
|
||||
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
|
||||
err, capi_info_string((unsigned int)err));
|
||||
} else {
|
||||
wCmd = HEADER_CMD(CMSG);
|
||||
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
|
||||
(wCmd == CAPI_P_RESP(DATA_B3))) {
|
||||
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
|
||||
} else {
|
||||
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* write a capi message to capi device
|
||||
*/
|
||||
|
@ -85,27 +109,42 @@ MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG)
|
|||
return -1;
|
||||
}
|
||||
|
||||
error = capi20_put_cmsg(CMSG);
|
||||
error = capi_put_cmsg(CMSG);
|
||||
|
||||
if (cc_mutex_unlock(&capi_put_lock)) {
|
||||
cc_log(LOG_WARNING, "Unable to unlock capi put!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
|
||||
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
|
||||
error, capi_info_string((unsigned int)error));
|
||||
} else {
|
||||
unsigned short wCmd = HEADER_CMD(CMSG);
|
||||
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
|
||||
(wCmd == CAPI_P_RESP(DATA_B3))) {
|
||||
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
|
||||
} else {
|
||||
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
|
||||
}
|
||||
log_capi_message(error, CMSG);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* write a capi message to capi device
|
||||
*/
|
||||
MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
|
||||
{
|
||||
MESSAGE_EXCHANGE_ERROR error;
|
||||
_cmsg CMSG;
|
||||
|
||||
if (cc_mutex_lock(&capi_put_lock)) {
|
||||
cc_log(LOG_WARNING, "Unable to lock capi put!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
capi_message2cmsg(&CMSG, msg);
|
||||
|
||||
error = capi20_put_message(CMSG.ApplId, msg);
|
||||
|
||||
if (cc_mutex_unlock(&capi_put_lock)) {
|
||||
cc_log(LOG_WARNING, "Unable to unlock capi put!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_capi_message(error, &CMSG);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -150,6 +189,109 @@ MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG)
|
|||
return Info;
|
||||
}
|
||||
|
||||
/*
|
||||
* Eicon's capi_sendf() function to create capi messages easily
|
||||
* and send this message.
|
||||
* Copyright by Eicon Networks / Dialogic
|
||||
*/
|
||||
MESSAGE_EXCHANGE_ERROR capi_sendf(
|
||||
_cword command, _cdword Id, _cword Number, char * format, ...)
|
||||
{
|
||||
MESSAGE_EXCHANGE_ERROR ret;
|
||||
int i, j;
|
||||
unsigned int d;
|
||||
unsigned char *p, *p_length;
|
||||
unsigned char *string;
|
||||
va_list ap;
|
||||
capi_prestruct_t *s;
|
||||
unsigned char msg[2048];
|
||||
|
||||
write_capi_word(&msg[2], capi_ApplID);
|
||||
write_capi_word(&msg[4], command);
|
||||
write_capi_word(&msg[6], Number);
|
||||
write_capi_dword(&msg[8], Id);
|
||||
|
||||
p = &msg[12];
|
||||
p_length = 0;
|
||||
|
||||
va_start(ap, format);
|
||||
for (i = 0; format[i]; i++) {
|
||||
if (((p - (&msg[0])) + 12) >= sizeof(msg)) {
|
||||
cc_log(LOG_ERROR, "capi_sendf: message too big (%d)\n",
|
||||
(p - (&msg[0])));
|
||||
return 0x1004;
|
||||
}
|
||||
switch(format[i]) {
|
||||
case 'b': /* byte */
|
||||
d = (unsigned char)va_arg(ap, unsigned int);
|
||||
*(p++) = (unsigned char) d;
|
||||
break;
|
||||
case 'w': /* word (2 bytes) */
|
||||
d = (unsigned short)va_arg(ap, unsigned int);
|
||||
*(p++) = (unsigned char) d;
|
||||
*(p++) = (unsigned char)(d >> 8);
|
||||
break;
|
||||
case 'd': /* double word (4 bytes) */
|
||||
d = va_arg(ap, unsigned int);
|
||||
*(p++) = (unsigned char) d;
|
||||
*(p++) = (unsigned char)(d >> 8);
|
||||
*(p++) = (unsigned char)(d >> 16);
|
||||
*(p++) = (unsigned char)(d >> 24);
|
||||
break;
|
||||
case 's': /* struct, length is the first byte */
|
||||
string = va_arg(ap, unsigned char *);
|
||||
for (j = 0; j <= string[0]; j++)
|
||||
*(p++) = string[j];
|
||||
break;
|
||||
case 'a': /* ascii string, NULL terminated string */
|
||||
string = va_arg(ap, unsigned char *);
|
||||
for (j = 0; string[j] != '\0'; j++)
|
||||
*(++p) = string[j];
|
||||
*((p++)-j) = (unsigned char) j;
|
||||
break;
|
||||
case 'c': /* predefined capi_prestruct_t */
|
||||
s = va_arg(ap, capi_prestruct_t *);
|
||||
if (s->wLen < 0xff) {
|
||||
*(p++) = (unsigned char)(s->wLen);
|
||||
} else {
|
||||
*(p++) = 0xff;
|
||||
*(p++) = (unsigned char)(s->wLen);
|
||||
*(p++) = (unsigned char)(s->wLen >> 8);
|
||||
}
|
||||
for (j = 0; j < s->wLen; j++)
|
||||
*(p++) = s->info[j];
|
||||
break;
|
||||
case '(': /* begin of a structure */
|
||||
*p = (p_length) ? p - p_length : 0;
|
||||
p_length = p++;
|
||||
break;
|
||||
case ')': /* end of structure */
|
||||
if (p_length) {
|
||||
j = *p_length;
|
||||
*p_length = (unsigned char)((p - p_length) - 1);
|
||||
p_length = (j != 0) ? p_length - j : 0;
|
||||
} else {
|
||||
cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n",
|
||||
format);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cc_log(LOG_ERROR, "capi_sendf: unknown format \"%s\"\n",
|
||||
format);
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
if (p_length) {
|
||||
cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n", format);
|
||||
}
|
||||
write_capi_word(&msg[0], (unsigned short)(p - (&msg[0])));
|
||||
|
||||
ret = _capi_put_msg(&msg[0]);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* decode capi 2.0 info word
|
||||
*/
|
||||
|
|
|
@ -35,4 +35,17 @@ extern struct ast_channel *cc_get_peer_link_id(const char *p);
|
|||
#define capi_number(data, strip) \
|
||||
capi_number_func(data, strip, alloca(AST_MAX_EXTENSION))
|
||||
|
||||
typedef struct capi_prestruct_s {
|
||||
unsigned short wLen;
|
||||
unsigned char *info;
|
||||
} capi_prestruct_t;
|
||||
|
||||
/*
|
||||
* Eicon's capi_sendf() function to create capi messages easily
|
||||
* and send this message.
|
||||
* Copyright by Eicon Networks / Dialogic
|
||||
*/
|
||||
extern MESSAGE_EXCHANGE_ERROR capi_sendf(
|
||||
_cword command, _cdword Id, _cword Number, char * format, ...);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue