New signaling module to handle analog operations in chan_dahdi
This branch splits all the analog signaling logic out of chan_dahdi.c into
sig_analog.c. Functionality in theory should not change at all. As noted
in the code, there is still some unused code remaining that will be cleaned
up in a later commit.
Simplify the Makefile and avoid needing to specify each object file.
Instead of specifying every object file, use make's magic to generate
it.
This will generate less conflicts in team branches when a new file is
added in trunk.
Resolve issues with choppy sound when using res_timing_pthread.
The situation that caused this problem was when continuous mode was being
turned on and off while a rate was set for a timing interface. A very easy
way to replicate this bug was to do a Playback() from behind a Local channel.
In this scenario, a rate gets set on the channel for doing file playback.
At the same time, continuous mode gets turned on and off about every 20 ms
as frames get queued on to the PBX side channel from the other side of the
Local channel.
Essentially, this module treated continuous mode and a set rate as mutually
exclusive states for the timer to be in. When I dug deep enough, I observed
the following pattern:
1) Set timer to tick every 20 ms.
2) Wait almost 20 ms ...
3) Continuous mode gets turned on for a queued up frame
4) Continuous mode gets turned off
5) The timer goes back to its tick per 20 ms. state but starts counting
at 0 ms.
6) Goto step 2.
Sometimes, res_timing_pthread would make it 20 ms and produce a timer tick,
but not most of the time. This is what produced the choppy sound (or sometimes
no sound at all).
Now, the module treats continuous mode and a set rate as completely independent
timer modes. They can be enabled and disabled independently of each other and
things work as expected.
(closes issue #14412)
Reported by: dome
Patches:
issue14412.diff.txt uploaded by russell (license 2)
issue14412-1.6.1.0.diff.txt uploaded by russell (license 2)
Tested by: DennisD, russell
........
r198182 | twilson | 2009-05-29 18:21:42 -0400 (Fri, 29 May 2009) | 2 lines
Add a couple of TODO items so I don't forget
........
r198183 | russell | 2009-05-29 18:33:31 -0400 (Fri, 29 May 2009) | 2 lines
Improve handling of trying to ACK too many timer expirations.
........
r198186 | russell | 2009-05-29 19:04:31 -0400 (Fri, 29 May 2009) | 2 lines
Suggesting that only a single timing module be loaded is no longer necessary.
........
r198217 | eliel | 2009-05-29 21:04:57 -0400 (Fri, 29 May 2009) | 10 lines
Remove not used code in the Agent channel.
This code was there because of the AgentCallbackLogin() application.
->loginchan[] member was only used by AgentCallbackLogin().
Agent where dumped to astdb if they where logged in using AgentCallbacklogin()
so they are not being dumper anymore.
static int dahdi_sendtext(struct ast_channel *c, const char *text);
+static int analog_lib_handles(int signalling, int radio, int oprmode);
+
static void mwi_event_cb(const struct ast_event *event, void *userdata)
{
/* This module does not handle MWI in an event-based manner. However, it
@@ -753,6 +756,7 @@
static struct dahdi_pvt {
ast_mutex_t lock;
+ struct callerid_state *cs;
struct ast_channel *owner; /*!< Our current active owner (if applicable) */
/*!< Up to three channels can be associated with this call */
@@ -1333,6 +1337,7 @@
char begindigit;
/*! \brief TRUE if confrence is muted. */
int muting;
+ void *sig_pvt;
} *iflist = NULL, *ifend = NULL;
/*! \brief Channel configuration from chan_dahdi.conf .
@@ -1527,6 +1532,911 @@
#else
#define GET_CHANNEL(p) ((p)->channel)
#endif
+
+static enum analog_sigtype dahdisig_to_analogsig(int sig)
+{
+ switch (sig) {
+ case SIG_FXOLS:
+ return ANALOG_SIG_FXOLS;
+ case SIG_FXOGS:
+ return ANALOG_SIG_FXOGS;
+ case SIG_FXOKS:
+ return ANALOG_SIG_FXOKS;
+ case SIG_FXSLS:
+ return ANALOG_SIG_FXSLS;
+ case SIG_FXSGS:
+ return ANALOG_SIG_FXSGS;
+ case SIG_FXSKS:
+ return ANALOG_SIG_FXSKS;
+ case SIG_EMWINK:
+ return ANALOG_SIG_EMWINK;
+ case SIG_EM:
+ return ANALOG_SIG_EM;
+ case SIG_EM_E1:
+ return ANALOG_SIG_EM_E1;
+ case SIG_FEATD:
+ return ANALOG_SIG_FEATD;
+ case SIG_FEATDMF:
+ return ANALOG_SIG_FEATDMF;
+ case SIG_E911:
+ return SIG_E911;
+ case SIG_FGC_CAMA:
+ return ANALOG_SIG_FGC_CAMA;
+ case SIG_FGC_CAMAMF:
+ return ANALOG_SIG_FGC_CAMAMF;
+ case SIG_FEATB:
+ return ANALOG_SIG_FEATB;
+ case SIG_SFWINK:
+ return ANALOG_SIG_SFWINK;
+ case SIG_SF:
+ return ANALOG_SIG_SF;
+ case SIG_SF_FEATD:
+ return ANALOG_SIG_SF_FEATD;
+ case SIG_SF_FEATDMF:
+ return ANALOG_SIG_SF_FEATDMF;
+ case SIG_FEATDMF_TA:
+ return ANALOG_SIG_FEATDMF_TA;
+ case SIG_SF_FEATB:
+ return ANALOG_SIG_FEATB;
+ default:
+ return -1;
+ }
+}
+
+
+static int analog_tone_to_dahditone(enum analog_tone tone)
+{
+ switch (tone) {
+ case ANALOG_TONE_RINGTONE:
+ return DAHDI_TONE_RINGTONE;
+ case ANALOG_TONE_STUTTER:
+ return DAHDI_TONE_STUTTER;
+ case ANALOG_TONE_CONGESTION:
+ return DAHDI_TONE_CONGESTION;
+ case ANALOG_TONE_DIALTONE:
+ return DAHDI_TONE_DIALTONE;
+ case ANALOG_TONE_DIALRECALL:
+ return DAHDI_TONE_DIALRECALL;
+ case ANALOG_TONE_INFO:
+ return DAHDI_TONE_INFO;
+ default:
+ return -1;
+ }
+}
+
+static int analogsub_to_dahdisub(enum analog_sub analogsub)
+{
+ int index;
+
+ switch (analogsub) {
+ case ANALOG_SUB_REAL:
+ index = SUB_REAL;
+ break;
+ case ANALOG_SUB_CALLWAIT:
+ index = SUB_CALLWAIT;
+ break;
+ case ANALOG_SUB_THREEWAY:
+ index = SUB_THREEWAY;
+ break;
+ default:
+ ast_log(LOG_ERROR, "Unidentified sub!\n");
+ index = SUB_REAL;
+ }
+
+ return index;
+}
+
+static enum analog_event dahdievent_to_analogevent(int event);
+static int bump_gains(struct dahdi_pvt *p);
+static int dahdi_setlinear(int dfd, int linear);
+
+static int my_start_cid_detect(void *pvt, int cid_signalling)
+{
+ struct dahdi_pvt *p = pvt;
+ int index = SUB_REAL;
+ p->cs = callerid_new(cid_signalling);
+ if (!p->cs) {
+ ast_log(LOG_ERROR, "Unable to alloc callerid\n");
+ return -1;
+ }
+ bump_gains(p);
+ dahdi_setlinear(p->subs[index].dfd, 0);
+
+ return 0;
+}
+
+static int my_stop_cid_detect(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int index = SUB_REAL;
+ if (p->cs)
+ callerid_free(p->cs);
+ dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
+ return 0;
+}
+
+static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
+{
+ struct dahdi_pvt *p = pvt;
+ struct pollfd poller;
+ char *name, *num;
+ int index = SUB_REAL;
+ int res;
+ unsigned char buf[256];
+ int flags;
+
+ poller.fd = p->subs[SUB_REAL].dfd;
+ poller.events = POLLPRI | POLLIN;
+ poller.revents = 0;
+
+ res = poll(&poller, 1, timeout);
+
+ if (poller.revents & POLLPRI) {
+ *ev = dahdievent_to_analogevent(dahdi_get_event(p->subs[SUB_REAL].dfd));
+ return 1;
+ }
+
+ if (poller.revents & POLLIN) {
+ /*** NOTES ***/
+ /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
+ * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
+ * either a timeout occurss or CID is detected (returns 0). returning 1 should be event received, and -1 should be fail
+ * and die */
+ res = read(p->subs[index].dfd, buf, sizeof(buf));
+ if (res < 0) {
+ if (errno != ELAST) {
+ ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
+ callerid_free(p->cs);
+ return -1;
+ }
+ }
+ res = callerid_feed(p->cs, buf, res, AST_LAW(p));
+ if (res < 0) {
+ ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (res == 1) {
+ callerid_get(p->cs, &name, &num, &flags);
+ if (name)
+ ast_copy_string(namebuf, name, ANALOG_MAX_CID);
+ if (num)
+ ast_copy_string(numbuf, num, ANALOG_MAX_CID);
+
+ ast_log(LOG_DEBUG, "CallerID number: %s, name: %s, flags=%d\n", num, name, flags);
+ return 0;
+ }
+ }
+
+ *ev = ANALOG_EVENT_NONE;
+ return 1;
+}
+
+static int send_callerid(struct dahdi_pvt *p);
+
+static int my_stop_callwait(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ p->callwaitingrepeat = 0;
+ p->cidcwexpire = 0;
+
+ return 0;
+}
+
+static int save_conference(struct dahdi_pvt *p);
+
+static int my_callwait(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
+ if (p->cidspill) {
+ ast_log(LOG_WARNING, "Spill already exists?!?\n");
+ free(p->cidspill);
+ }
+ if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
+ return -1;
+ save_conference(p);
+ /* Silence */
+ memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
+ if (!p->callwaitrings && p->callwaitingcallerid) {
+ ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
+ p->callwaitcas = 1;
+ p->cidlen = 2400 + 680 + READ_SIZE * 4;
+ } else {
+ ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
+ p->callwaitcas = 0;
+ p->cidlen = 2400 + READ_SIZE * 4;
+ }
+ p->cidpos = 0;
+ send_callerid(p);
+
+ return 0;
+}
+
+static int my_send_callerid(void *pvt, int cwcid, struct ast_callerid *cid)
+{
+ struct dahdi_pvt *p = pvt;
+
+ ast_log(LOG_ERROR, "Starting cid spill\n");
+
+ if (p->cidspill) {
+ ast_log(LOG_WARNING, "cidspill already exists??\n");
+ free(p->cidspill);
+ }
+
+ if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
+ if (cwcid == 0) {
+ p->cidlen = ast_callerid_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
+ } else {
+ p->callwaitcas = 0;
+ p->cidcwexpire = 0;
+ p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, cid->cid_name, cid->cid_num, AST_LAW(p));
+ p->cidlen += READ_SIZE * 4;
+ }
+ p->cidpos = 0;
+ send_callerid(p);
+ }
+ return 0;
+}
+
+static int my_dsp_reset_and_flush_digits(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ if (p->dsp)
+ ast_dsp_digitreset(p->dsp);
+
+ return 0;
+}
+
+static int my_dsp_set_digitmode(void *pvt, enum analog_dsp_digitmode mode)
+{
+ struct dahdi_pvt *p = pvt;
+
+ if (p->channel == CHAN_PSEUDO)
+ ast_log(LOG_ERROR, "You have assumed incorrectly sir!\n");
+
+ if (mode == ANALOG_DIGITMODE_DTMF) {
+ /* If we do hardware dtmf, no need for a DSP */
+ if (p->hardwaredtmf) {
+ if (p->dsp) {
+ ast_dsp_free(p->dsp);
+ p->dsp = NULL;
+ }
+ return 0;
+ }
+
+ if (!p->dsp) {
+ p->dsp = ast_dsp_new();
+ if (!p->dsp) {
+ ast_log(LOG_ERROR, "Unable to allocate DSP\n");
+ return -1;
+ }
+ }
+
+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
+ } else if (mode == ANALOG_DIGITMODE_MF) {
+ if (!p->dsp) {
+ p->dsp = ast_dsp_new();
+ if (!p->dsp) {
+ ast_log(LOG_ERROR, "Unable to allocate DSP\n");
+ return -1;
+ }
+ }
+ ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
+ }
+ return 0;
+}
+
+static int dahdi_wink(struct dahdi_pvt *p, int index);
+
+static int my_wink(void *pvt, enum analog_sub sub)
+{
+ struct dahdi_pvt *p = pvt;
+ int index = analogsub_to_dahdisub(sub);
+ if (index != SUB_REAL) {
+ ast_log(LOG_ERROR, "We used a sub other than SUB_REAL (incorrect assumption sir)\n");
+ }
+ return dahdi_wink(p, index);
+}
+
+static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri);
+
+static int reset_conf(struct dahdi_pvt *p);
+
+static inline int dahdi_confmute(struct dahdi_pvt *p, int muted);
+
+static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub analog_index, struct ast_frame **dest)
+{
+ struct ast_frame *f = *dest;
+ struct dahdi_pvt *p = pvt;
+ int idx = analogsub_to_dahdisub(analog_index);
+
+ ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
+
+ if (f->subclass == 'f') {
+ /* Fax tone -- Handle and return NULL */
+ if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
+ /* If faxbuffers are configured, use them for the fax transmission */
+ if (p->usefaxbuffers && !p->bufferoverrideinuse) {
+ struct dahdi_bufferinfo bi = {
+ .txbufpolicy = p->faxbuf_policy,
+ .bufsize = p->bufsize,
+ .numbufs = p->faxbuf_no
+ };
+ int res;
+
+ if ((res = ioctl(p->subs[idx].dfd, DAHDI_SET_BUFINFO, &bi)) < 0) {
+ ast_log(LOG_WARNING, "Channel '%s' unable to set buffer policy, reason: %s\n", ast->name, strerror(errno));
+ } else {
+ p->bufferoverrideinuse = 1;
+ }
+ }
+ p->faxhandled = 1;
+ if (strcmp(ast->exten, "fax")) {
+ const char *target_context = S_OR(ast->macrocontext, ast->context);
+
+ /* We need to unlock 'ast' here because ast_exists_extension has the
+ * potential to start autoservice on the channel. Such action is prone
+ * to deadlock.
+ */
+ ast_mutex_unlock(&p->lock);
+ ast_channel_unlock(ast);
+ if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
+ /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
+ pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
+ if (ast_async_goto(ast, target_context, "fax", 1))
+ ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
+ } else {
+ ast_channel_lock(ast);
+ ast_mutex_lock(&p->lock);
+ ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
+ }
+ } else {
+ ast_debug(1, "Already in a fax extension, not redirecting\n");
+ }
+ } else {
+ ast_debug(1, "Fax already handled\n");
+ }
+ dahdi_confmute(p, 0);
+ p->subs[idx].f.frametype = AST_FRAME_NULL;
+ p->subs[idx].f.subclass = 0;
+ *dest = &p->subs[idx].f;
+ }
+}
+
+static void my_lock_private(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ ast_mutex_lock(&p->lock);
+}
+
+static void my_unlock_private(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+
+ ast_mutex_unlock(&p->lock);
+}
+
+static void my_increase_ss_count(void)
+{
+ ast_mutex_lock(&ss_thread_lock);
+ ss_thread_count++;
+ ast_mutex_unlock(&ss_thread_lock);
+}
+
+static void my_decrease_ss_count(void)
+{
+ ast_mutex_lock(&ss_thread_lock);
+ ss_thread_count--;
+ ast_cond_signal(&ss_thread_complete);
+ ast_mutex_unlock(&ss_thread_lock);
+}
+
+static void my_all_subchannels_hungup(void *pvt)
+{
+ struct dahdi_pvt *p = pvt;
+ int res, law;
+
+ p->faxhandled = 0;
+ p->didtdd = 0;
+
+ if (p->dsp) {
+ ast_dsp_free(p->dsp);
+ p->dsp = NULL;
+ }
+
+ law = DAHDI_LAW_DEFAULT;
[... 3180 lines stripped ...]
_______________________________________________
--Bandwidth and Colocation Provided by http://www.api-digital.com--
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum