Use direct access to vocoder without RTP framing. Preserve implementation using RTP framing

This commit is contained in:
MelwareDE 2009-05-08 13:03:31 +00:00
parent 170b200474
commit b09d58c323
4 changed files with 117 additions and 34 deletions

View File

@ -203,6 +203,7 @@ static int pbx_capi_indicate(struct ast_channel *c, int condition, const void *d
static int pbx_capi_indicate(struct ast_channel *c, int condition); static int pbx_capi_indicate(struct ast_channel *c, int condition);
#endif #endif
static struct capi_pvt* get_active_plci (struct ast_channel *c); static struct capi_pvt* get_active_plci (struct ast_channel *c);
static _cstruct diva_get_b1_conf (struct capi_pvt *i);
static void clear_channel_fax_loop (struct ast_channel *c, struct capi_pvt *i); static void clear_channel_fax_loop (struct ast_channel *c, struct capi_pvt *i);
/* /*
@ -232,6 +233,11 @@ static struct {
/* (_cstruct) "\x04\x01\x00\x00\x02", */ /* (_cstruct) "\x04\x01\x00\x00\x02", */
(_cstruct) "\x06\x01\x00\x58\x02\x32\x00", (_cstruct) "\x06\x01\x00\x58\x02\x32\x00",
(_cstruct) "\x00" (_cstruct) "\x00"
},
{ 0x1f, 1, 0, /* 3 */
NULL,
NULL,
NULL
} }
}; };
@ -1512,7 +1518,7 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout)
b_protocol_table[i->bproto].b1protocol, b_protocol_table[i->bproto].b1protocol,
b_protocol_table[i->bproto].b2protocol, b_protocol_table[i->bproto].b2protocol,
b_protocol_table[i->bproto].b3protocol, b_protocol_table[i->bproto].b3protocol,
b_protocol_table[i->bproto].b1configuration, diva_get_b1_conf (i),
b_protocol_table[i->bproto].b2configuration, b_protocol_table[i->bproto].b2configuration,
b_protocol_table[i->bproto].b3configuration, b_protocol_table[i->bproto].b3configuration,
/* BC */ /* BC */
@ -1536,6 +1542,42 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout)
return 0; return 0;
} }
static _cstruct diva_get_b1_conf (struct capi_pvt *i) {
_cstruct b1conf = b_protocol_table[i->bproto].b1configuration;
if (i->bproto == CC_BPROTO_VOCODER) {
switch(i->codec) {
case AST_FORMAT_ALAW:
b1conf = (_cstruct)"\x06\x08\x04\x03\x00\xa0\x00";
break;
case AST_FORMAT_ULAW:
b1conf = (_cstruct)"\x06\x00\x04\x03\x00\xa0\x00";
break;
case AST_FORMAT_GSM:
b1conf = (_cstruct)"\x06\x03\x04\x0f\x00\xa0\x00";
break;
case AST_FORMAT_G723_1:
b1conf = (_cstruct)"\x06\x04\x04\x01\x00\xa0\x00";
break;
case AST_FORMAT_G726:
b1conf = (_cstruct)"\x06\x02\x04\x0f\x00\xa0\x00";
break;
case AST_FORMAT_ILBC: /* 30 mSec 240 samples */
b1conf = (_cstruct)"\x06\x1b\x04\x03\x00\xf0\x00";
break;
case AST_FORMAT_G729A:
b1conf = (_cstruct)"\x06\x12\x04\x0f\x00\xa0\x00";
break;
default:
cc_log(LOG_ERROR, "%s: format %s(%d) invalid.\n",
i->vname, ast_getformatname(i->codec), i->codec);
break;
}
}
return (b1conf);
}
/* /*
* answer a capi call * answer a capi call
*/ */
@ -1546,6 +1588,7 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf)
const char *dnid; const char *dnid;
const char *connectednumber; const char *connectednumber;
unsigned char *facilityarray = NULL; unsigned char *facilityarray = NULL;
_cstruct b1conf;
if (i->state == CAPI_STATE_DISCONNECTED) { if (i->state == CAPI_STATE_DISCONNECTED) {
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Not answering disconnected call.\n", cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Not answering disconnected call.\n",
@ -1576,6 +1619,8 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf)
b3conf = b_protocol_table[i->bproto].b3configuration; b3conf = b_protocol_table[i->bproto].b3configuration;
} }
b1conf = diva_get_b1_conf (i);
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Answering for %s\n", cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Answering for %s\n",
i->vname, dnid); i->vname, dnid);
@ -1594,7 +1639,7 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf)
b_protocol_table[i->bproto].b1protocol, b_protocol_table[i->bproto].b1protocol,
b_protocol_table[i->bproto].b2protocol, b_protocol_table[i->bproto].b2protocol,
b_protocol_table[i->bproto].b3protocol, b_protocol_table[i->bproto].b3protocol,
b_protocol_table[i->bproto].b1configuration, b1conf,
b_protocol_table[i->bproto].b2configuration, b_protocol_table[i->bproto].b2configuration,
b3conf, b3conf,
capi_set_global_configuration(i), capi_set_global_configuration(i),
@ -1622,7 +1667,7 @@ static int pbx_capi_answer(struct ast_channel *c)
struct capi_pvt *i = CC_CHANNEL_PVT(c); struct capi_pvt *i = CC_CHANNEL_PVT(c);
int ret; int ret;
i->bproto = CC_BPROTO_TRANSPARENT; i->bproto = ((i->bproto == CC_BPROTO_VOCODER) && (i->codec != 0)) ? i->bproto : CC_BPROTO_TRANSPARENT;
if (i->rtp) { if (i->rtp) {
if (!capi_tcap_is_digital(i->transfercapability)) if (!capi_tcap_is_digital(i->transfercapability))
@ -2146,7 +2191,9 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
tmp->pickupgroup = i->pickupgroup; tmp->pickupgroup = i->pickupgroup;
tmp->nativeformats = capi_capability; tmp->nativeformats = capi_capability;
i->bproto = CC_BPROTO_TRANSPARENT; i->bproto = CC_BPROTO_TRANSPARENT;
if ((i->rtpcodec = (capi_controllers[i->controller]->rtpcodec & i->capability))) { if ((i->rtpcodec = (capi_controllers[i->controller]->rtpcodec & i->capability))) {
#if 0 /* VOCODER */
if (capi_alloc_rtp(i)) { if (capi_alloc_rtp(i)) {
/* error on rtp alloc */ /* error on rtp alloc */
i->rtpcodec = 0; i->rtpcodec = 0;
@ -2155,6 +2202,10 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
tmp->nativeformats = i->rtpcodec; tmp->nativeformats = i->rtpcodec;
i->bproto = CC_BPROTO_RTP; i->bproto = CC_BPROTO_RTP;
} }
#else
tmp->nativeformats = i->rtpcodec;
i->bproto = CC_BPROTO_VOCODER;
#endif
} }
fmt = ast_best_codec(tmp->nativeformats); fmt = ast_best_codec(tmp->nativeformats);
i->codec = fmt; i->codec = fmt;
@ -2169,7 +2220,7 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
i->vname, ast_getformatname(fmt), i->vname, ast_getformatname(fmt),
ast_getformatname_multiple(alloca(80), 80, ast_getformatname_multiple(alloca(80), 80,
tmp->nativeformats), tmp->nativeformats),
(i->rtp) ? " (RTP)" : ""); (i->bproto == CC_BPROTO_VOCODER) ? "VOCODER" : ((i->rtp) ? " (RTP)" : ""));
if (!ast_strlen_zero(i->cid)) { if (!ast_strlen_zero(i->cid)) {
if (tmp->cid.cid_num) { if (tmp->cid.cid_num) {
@ -3802,44 +3853,48 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un
i->B3q += b3len; i->B3q += b3len;
} }
if ((i->doES == 1) && (!capi_tcap_is_digital(i->transfercapability))) { if (i->bproto != CC_BPROTO_VOCODER) {
for (j = 0; j < b3len; j++) { if ((i->doES == 1) && (!capi_tcap_is_digital(i->transfercapability))) {
*(b3buf + j) = capi_reversebits[*(b3buf + j)];
if (capi_capability == AST_FORMAT_ULAW) {
rxavg += abs(capiULAW2INT[ capi_reversebits[*(b3buf + j)]]);
} else {
rxavg += abs(capiALAW2INT[ capi_reversebits[*(b3buf + j)]]);
}
}
rxavg = rxavg / j;
for (j = 0; j < ECHO_EFFECTIVE_TX_COUNT; j++) {
txavg += i->txavg[j];
}
txavg = txavg / j;
if ( (txavg / ECHO_TXRX_RATIO) > rxavg) {
if (capi_capability == AST_FORMAT_ULAW) {
memset(b3buf, 255, b3len);
} else {
memset(b3buf, 85, b3len);
}
cc_verbose(6, 1, VERBOSE_PREFIX_3 "%s: SUPPRESSING ECHO rx=%d, tx=%d\n",
i->vname, rxavg, txavg);
}
} else {
if ((i->rxgain == 1.0) || (capi_tcap_is_digital(i->transfercapability))) {
for (j = 0; j < b3len; j++) { for (j = 0; j < b3len; j++) {
*(b3buf + j) = capi_reversebits[*(b3buf + j)]; *(b3buf + j) = capi_reversebits[*(b3buf + j)];
if (capi_capability == AST_FORMAT_ULAW) {
rxavg += abs(capiULAW2INT[ capi_reversebits[*(b3buf + j)]]);
} else {
rxavg += abs(capiALAW2INT[ capi_reversebits[*(b3buf + j)]]);
}
}
rxavg = rxavg / j;
for (j = 0; j < ECHO_EFFECTIVE_TX_COUNT; j++) {
txavg += i->txavg[j];
}
txavg = txavg / j;
if ( (txavg / ECHO_TXRX_RATIO) > rxavg) {
if (capi_capability == AST_FORMAT_ULAW) {
memset(b3buf, 255, b3len);
} else {
memset(b3buf, 85, b3len);
}
cc_verbose(6, 1, VERBOSE_PREFIX_3 "%s: SUPPRESSING ECHO rx=%d, tx=%d\n",
i->vname, rxavg, txavg);
} }
} else { } else {
for (j = 0; j < b3len; j++) { if ((i->rxgain == 1.0) || (capi_tcap_is_digital(i->transfercapability))) {
*(b3buf + j) = capi_reversebits[i->g.rxgains[*(b3buf + j)]]; for (j = 0; j < b3len; j++) {
*(b3buf + j) = capi_reversebits[*(b3buf + j)];
}
} else {
for (j = 0; j < b3len; j++) {
*(b3buf + j) = capi_reversebits[i->g.rxgains[*(b3buf + j)]];
}
} }
} }
fr.subclass = capi_capability;
} else {
fr.subclass = i->codec;
} }
fr.frametype = AST_FRAME_VOICE; fr.frametype = AST_FRAME_VOICE;
fr.subclass = capi_capability;
fr.FRAME_DATA_PTR = b3buf; fr.FRAME_DATA_PTR = b3buf;
fr.datalen = b3len; fr.datalen = b3len;
fr.samples = b3len; fr.samples = b3len;
@ -6747,6 +6802,8 @@ static char *show_bproto(int bproto)
return " fax "; return " fax ";
case CC_BPROTO_RTP: case CC_BPROTO_RTP:
return " rtp "; return " rtp ";
case CC_BPROTO_VOCODER:
return " vocoder ";
} }
return " ??? "; return " ??? ";
} }

View File

@ -139,6 +139,7 @@ static inline unsigned int read_capi_dword(void *m)
#define CC_BPROTO_TRANSPARENT 0 #define CC_BPROTO_TRANSPARENT 0
#define CC_BPROTO_FAXG3 1 #define CC_BPROTO_FAXG3 1
#define CC_BPROTO_RTP 2 #define CC_BPROTO_RTP 2
#define CC_BPROTO_VOCODER 3
/* FAX Resolutions */ /* FAX Resolutions */
#define FAX_STANDARD_RESOLUTION 0 #define FAX_STANDARD_RESOLUTION 0

View File

@ -391,6 +391,10 @@ void voice_over_ip_profile(struct cc_capi_controller *cp)
cp->rtpcodec |= AST_FORMAT_G729A; cp->rtpcodec |= AST_FORMAT_G729A;
cc_verbose(3, 0, "G.729"); cc_verbose(3, 0, "G.729");
} }
if (payload1 & (1U << 27)) {
cp->rtpcodec |= AST_FORMAT_ILBC;
cc_verbose(3, 0, "iLBC");
}
cc_verbose(3, 0, "\n"); cc_verbose(3, 0, "\n");
} }

View File

@ -1387,6 +1387,27 @@ int capi_write_frame(struct capi_pvt *i, struct ast_frame *f)
return 0; return 0;
} }
if (i->bproto == CC_BPROTO_VOCODER) {
buf = &(i->send_buffer[(i->send_buffer_handle % CAPI_MAX_B3_BLOCKS) *
(CAPI_MAX_B3_BLOCK_SIZE + AST_FRIENDLY_OFFSET)]);
i->send_buffer_handle++;
memcpy (buf, f->FRAME_DATA_PTR, f->datalen);
error = capi_sendf(NULL, 0, CAPI_DATA_B3_REQ, i->NCCI, get_capi_MessageNumber(),
"dwww", buf, f->datalen, i->send_buffer_handle, 0);
if (likely(error == 0)) {
cc_mutex_lock(&i->lock);
i->B3count++;
i->B3q -= f->datalen;
if (i->B3q < 0)
i->B3q = 0;
cc_mutex_unlock(&i->lock);
}
return 0;
}
if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) { if ((!i->smoother) || (ast_smoother_feed(i->smoother, f) != 0)) {
cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname); cc_log(LOG_ERROR, "%s: failed to fill smoother\n", i->vname);
return 0; return 0;