From 34b17bad86b02fae864505ae5fe7055a2bd63290 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 24 Jan 2010 14:22:34 +0100 Subject: [PATCH] Added queue buffer for chan_lcr sending faxes without interruption. Use options "t:q250" for disabling mISDN_dsp and adding a 250ms delay. modified: README modified: bchannel.c modified: bchannel.h modified: chan_lcr.c modified: chan_lcr.h modified: select.c --- README | 2 ++ bchannel.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- bchannel.h | 16 +++++++++++- chan_lcr.c | 14 +++++++++-- chan_lcr.h | 2 +- select.c | 12 ++++----- 6 files changed, 115 insertions(+), 13 deletions(-) diff --git a/README b/README index bc747c2..07c26ac 100644 --- a/README +++ b/README @@ -535,6 +535,8 @@ Changes after Version 1.7 - Replaced polling main loop by event driven "select()" loop. - Also replaced polling main loop by event driven "select()" loop on chan_lcr. - Added "release" action and timeout to "execute" action. +- Added queue buffer for chan_lcr sending faxes without interruption. + -> Use options "t:q250" for disabling mISDN_dsp and adding a 250ms delay. diff --git a/bchannel.c b/bchannel.c index 9e878fe..51423a1 100644 --- a/bchannel.c +++ b/bchannel.c @@ -54,6 +54,7 @@ #include "bchannel.h" #include "chan_lcr.h" #include "callerid.h" +#include "options.h" #ifndef ISDN_PID_L4_B_USER @@ -69,6 +70,7 @@ enum { BSTATE_DEACTIVATING, }; +static void bchannel_send_queue(struct bchannel *bchannel); int bchannel_initialize(void) { @@ -129,7 +131,7 @@ static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, /* * create stack */ -int bchannel_create(struct bchannel *bchannel, int mode) +int bchannel_create(struct bchannel *bchannel, int mode, int queue) { int ret; struct sockaddr_mISDN addr; @@ -140,7 +142,7 @@ int bchannel_create(struct bchannel *bchannel, int mode) } /* open socket */ - bchannel->b_mode = mode; + bchannel->b_mode = (mode & 3); switch(bchannel->b_mode) { case 0: CDEBUG(bchannel->call, NULL, "Open DSP audio\n"); @@ -181,6 +183,19 @@ int bchannel_create(struct bchannel *bchannel, int mode) bchannel->b_sock = -1; return 0; } + + /* queue */ + if (bchannel->b_mode == 1 && queue) { + bchannel->nodsp_queue_out = 0; + bchannel->nodsp_queue_in = queue * 8; + if (bchannel->nodsp_queue_in > QUEUE_BUFFER_MAX-1) + bchannel->nodsp_queue_in = QUEUE_BUFFER_MAX-1; + bchannel->nodsp_queue = bchannel->nodsp_queue_in; /* store initial load */ + memset(&bchannel->nodsp_queue_buffer, (options.law=='a')?0x2a:0xff, QUEUE_BUFFER_SIZE); + bchannel->queue_sent = 0; + } else + bchannel->nodsp_queue = 0; + return 1; } @@ -399,6 +414,7 @@ void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len) struct mISDNhead *frm = (struct mISDNhead *)buff; int ret; int i; + int space, in; if (bchannel->b_state != BSTATE_ACTIVE) return; @@ -425,6 +441,30 @@ void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len) break; } frm->id = 0; +#ifdef SEAMLESS_TEST + unsigned char test_tone[8] = {0x2a, 0x24, 0xb4, 0x24, 0x2a, 0x25, 0xb5, 0x25}; + p = buff + MISDN_HEADER_LEN; + for (i = 0; i < len; i++) + *p++ = test_tone[(bchannel->test + i) & 7]; + bchannel->test = (bchannel->test + len) & 7; +#endif + if (bchannel->nodsp_queue) { + space = (bchannel->nodsp_queue_out - bchannel->nodsp_queue_in) & (QUEUE_BUFFER_SIZE - 1); + if (len > space) { + CERROR(bchannel->call, NULL, "Queue buffer overflow.\n"); + return; + } + p = buff + MISDN_HEADER_LEN; + in = bchannel->nodsp_queue_in; + for (i = 0; i < len; i++) { + bchannel->nodsp_queue_buffer[in] = *p++; + in = (in + 1) & (QUEUE_BUFFER_SIZE - 1); + } + bchannel->nodsp_queue_in = in; + if (bchannel->queue_sent == 0) /* if there is no pending data */ + bchannel_send_queue(bchannel); + return; + } ret = sendto(bchannel->b_sock, buff, MISDN_HEADER_LEN+len, 0, NULL, 0); if (ret < 0) CERROR(bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock); @@ -432,6 +472,38 @@ void bchannel_transmit(struct bchannel *bchannel, unsigned char *data, int len) /* + * in case of a send queue, we send from that queue rather directly + */ +static void bchannel_send_queue(struct bchannel *bchannel) +{ + unsigned char buff[1024 + MISDN_HEADER_LEN], *p = buff + MISDN_HEADER_LEN; + struct mISDNhead *frm = (struct mISDNhead *)buff; + int ret; + int i; + int len, out; + + len = (bchannel->nodsp_queue_in - bchannel->nodsp_queue_out) & (QUEUE_BUFFER_SIZE - 1); + if (len == 0) + return; /* mISDN driver received all load */ + if (len > 1024) + len = 1024; + frm->prim = PH_DATA_REQ; + frm->id = 0; + out = bchannel->nodsp_queue_out; + for (i = 0; i < len; i++) { + *p++ = bchannel->nodsp_queue_buffer[out]; + out = (out + 1) & (QUEUE_BUFFER_SIZE - 1); + } + bchannel->nodsp_queue_out = out; + ret = sendto(bchannel->b_sock, buff, MISDN_HEADER_LEN+len, 0, NULL, 0); + if (ret < 0) + CERROR(bchannel->call, NULL, "Failed to send to socket %d\n", bchannel->b_sock); + else + bchannel->queue_sent = 1; +} + + +/* * join bchannel */ void bchannel_join(struct bchannel *bchannel, unsigned short id) @@ -526,8 +598,12 @@ static int bchannel_handle(struct lcr_fd *fd, unsigned int what, void *instance, ret = recv(bchannel->b_sock, buffer, sizeof(buffer), 0); if (ret >= (int)MISDN_HEADER_LEN) { switch(hh->prim) { - /* we don't care about confirms, we use rx data to sync tx */ + /* after a confim, we can send more from queue */ case PH_DATA_CNF: + if (bchannel->nodsp_queue) { + bchannel->queue_sent = 0; + bchannel_send_queue(bchannel); + } break; /* we receive audio data, we respond to it AND we send tones */ diff --git a/bchannel.h b/bchannel.h index 2b03444..55ce323 100644 --- a/bchannel.h +++ b/bchannel.h @@ -9,6 +9,11 @@ ** ** \*****************************************************************************/ +/* this test produces a test tone to test gaps in audio stream */ +//#define SEAMLESS_TEST + +#define QUEUE_BUFFER_SIZE 8192 /* must be the power of two */ +#define QUEUE_BUFFER_MAX 4096 /* half of size */ struct bchannel { struct bchannel *next; @@ -31,6 +36,15 @@ struct bchannel { int b_dtmf; int b_bf_len; unsigned char b_bf_key[128]; + int nodsp_queue; /* enables nodsp_queue_buffer */ + unsigned char nodsp_queue_buffer[QUEUE_BUFFER_SIZE]; + /* buffer for seamless transmission */ + unsigned int nodsp_queue_in, nodsp_queue_out; + /* in and out pointers */ + int queue_sent; /* data for mISDN was not confrmed yet */ +#ifdef SEAMLESS_TEST + int test; +#endif }; @@ -40,7 +54,7 @@ extern pid_t bchannel_pid; int bchannel_initialize(void); void bchannel_deinitialize(void); void bchannel_destroy(struct bchannel *bchannel); -int bchannel_create(struct bchannel *channel, int mode); +int bchannel_create(struct bchannel *channel, int mode, int queue); void bchannel_activate(struct bchannel *channel, int activate); void bchannel_transmit(struct bchannel *channel, unsigned char *data, int len); void bchannel_join(struct bchannel *channel, unsigned short id); diff --git a/chan_lcr.c b/chan_lcr.c index d0993b7..0013f2f 100644 --- a/chan_lcr.c +++ b/chan_lcr.c @@ -496,6 +496,14 @@ void apply_opt(struct chan_call *call, char *data) if (!call->nodsp) call->nodsp = 1; break; + case 'q': + if (opt[1] == '\0') { + CERROR(call, call->ast, "Option 'q' (queue) expects parameter.\n", opt); + break; + } + CDEBUG(call, call->ast, "Option 'q' (queue).\n"); + call->nodsp_queue = atoi(opt+1); + break; case 'e': if (opt[1] == '\0') { CERROR(call, call->ast, "Option 'e' (echo cancel) expects parameter.\n", opt); @@ -591,7 +599,7 @@ void apply_opt(struct chan_call *call, char *data) /* re-open, if bchannel is created */ if (call->bchannel && call->bchannel->b_sock > -1) { bchannel_destroy(call->bchannel); - if (bchannel_create(call->bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0))) + if (bchannel_create(call->bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0), call->nodsp_queue)) bchannel_activate(call->bchannel, 1); } } @@ -1287,7 +1295,7 @@ int receive_message(int message_type, unsigned int ref, union parameter *param) bchannel_join(bchannel, call->bridge_id); } /* create only, if call exists, othewhise it bchannel is freed below... */ - if (bchannel_create(bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0))) + if (bchannel_create(bchannel, ((call->nodsp || call->faxdetect > 0)?1:0) + ((call->hdlc)?2:0), call->nodsp_queue)) bchannel_activate(bchannel, 1); } /* acknowledge */ @@ -2802,6 +2810,8 @@ int load_module(void) " n - Don't detect dtmf tones on called channel.\n" " h - Force data call (HDLC).\n" " t - Disable mISDN_dsp features (required for fax application).\n" + " q - Add queue to make fax stream seamless (required for fax app).\n" + " Use queue size in miliseconds for optarg. (try 250)\n" " f - Adding fax detection. It it timeouts, mISDN_dsp is used.\n" " Use time to detect for optarg.\n" " c - Make crypted outgoing call, optarg is keyindex.\n" diff --git a/chan_lcr.h b/chan_lcr.h index 3a64593..e7ea0f5 100644 --- a/chan_lcr.h +++ b/chan_lcr.h @@ -71,7 +71,7 @@ struct chan_call { int bf_len; /* blowfish crypt key */ struct ast_dsp *dsp; /* ast dsp processor for fax/tone detection */ struct ast_trans_pvt *trans; /* Codec translation path as fax/tone detection requires slin */ - int nodsp, hdlc, faxdetect; + int nodsp, nodsp_queue, hdlc, faxdetect; /* flags for bchannel mode */ char queue_string[64]; /* queue for asterisk */ diff --git a/select.c b/select.c index ba9b563..8763739 100644 --- a/select.c +++ b/select.c @@ -104,9 +104,9 @@ again: } if (polling) timer = &no_time; -#warning TESTING - if (!timer) - printf("wait till infinity ..."); fflush(stdout); +//#warning TESTING +// if (!timer) +// printf("wait till infinity ..."); fflush(stdout); FD_ZERO(&readset); FD_ZERO(&writeset); @@ -129,9 +129,9 @@ again: rc = select(maxfd+1, &readset, &writeset, &exceptset, timer); if (lock) lock(); -#warning TESTING - if (!timer) - printf("interrupted.\n"); +//#warning TESTING +// if (!timer) +// printf("interrupted.\n"); if (rc < 0) return 0; if (global_change && *global_change) { -- 2.13.6