--- channels/chan_unicall.c.orig 2005-10-29 09:56:18.000000000 -0500 +++ channels/chan_unicall.c 2007-02-04 17:10:14.000000000 -0600 @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -157,31 +157,42 @@ static int unicall_answer(struct ast_channel *c); static struct ast_frame *unicall_read(struct ast_channel *c); static int unicall_write(struct ast_channel *c, struct ast_frame *f); -static int unicall_indicate(struct ast_channel *c, int condition); +static int unicall_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen); static int unicall_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int unicall_digit(struct ast_channel *c, char digit); static int unicall_send_text(struct ast_channel *c, const char *text); -static int unicall_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); +static int unicall_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeout); struct ast_frame *unicall_exception(struct ast_channel *ast); static int unicall_setoption(struct ast_channel *chan, int option, void *data, int datalen); +/* TODO: implement missing interface methods */ static const struct ast_channel_tech unicall_tech = { .type = type, .description = tdesc, .capabilities = AST_FORMAT_ULAW, .requester = unicall_request, + .devicestate = NULL, + .send_digit_begin = unicall_digit, + .send_digit_end = NULL, .call = unicall_call, .hangup = unicall_hangup, .answer = unicall_answer, .read = unicall_read, .write = unicall_write, - .indicate = unicall_indicate, - .fixup = unicall_fixup, - .send_digit = unicall_digit, .send_text = unicall_send_text, - .bridge = unicall_bridge, + .send_image = NULL, + .send_html = NULL, .exception = unicall_exception, + .bridge = unicall_bridge, + .indicate = unicall_indicate, + .fixup = unicall_fixup, .setoption = unicall_setoption, + .queryoption = NULL, + .transfer = NULL, + .write_video = NULL, + .bridged_channel = NULL, + .func_channel_read = NULL, + .func_channel_write = NULL }; struct unicall_pvt; @@ -345,27 +356,6 @@ static int unicall_open(struct unicall_pvt *p, char *fn); static int unicall_close(int fd); -/* Translate between Unicall causes and ast */ -static int hangup_uc2cause(int cause) -{ - switch (cause) - { - case UC_CAUSE_USER_BUSY: - return AST_CAUSE_BUSY; - case UC_CAUSE_NORMAL_CLEARING: - return AST_CAUSE_NORMAL; - case UC_CAUSE_NETWORK_CONGESTION: - case UC_CAUSE_REQ_CHANNEL_NOT_AVAILABLE: - return AST_CAUSE_CONGESTION; - case UC_CAUSE_UNASSIGNED_NUMBER: - case UC_CAUSE_NUMBER_CHANGED: - return AST_CAUSE_UNALLOCATED; - default: - return AST_CAUSE_FAILURE; - } - return 0; -} - /* translate between ast cause and Unicall */ static int hangup_cause2uc(int cause) { @@ -380,7 +370,7 @@ return 0; } -int select_codec(struct unicall_pvt *p, int index, int new_codec) +static int select_codec(struct unicall_pvt *p, int index, int new_codec) { int res; @@ -549,8 +539,8 @@ { buf[0] = digit; buf[1] = '\0'; -ast_log(LOG_WARNING, "Sending DTMF digit\n"); - dtmf_put(&p->subs[SUB_REAL].dtmf_tx_state, buf); + ast_log(LOG_DEBUG, "Sending DTMF digit\n"); + dtmf_tx_put(&p->subs[SUB_REAL].dtmf_tx_state, buf); p->dialing = TRUE; } /*endif*/ @@ -791,19 +781,6 @@ return useslavenative; } -static int reset_conf(struct unicall_pvt *p) -{ - p->confno = -1; - if (p->subs[SUB_REAL].fd > -1) - { - if (uc_channel_switching(p->uc, 0, UC_SWITCHING_FREE, 0, 0) != UC_RET_OK) - ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d!\n", p->channel); - /*endif*/ - } - /*endif*/ - return 0; -} - static int update_conf(struct unicall_pvt *p) { int needconf; @@ -922,26 +899,6 @@ /*endif*/ } -static void unicall_train_ec(struct unicall_pvt *p) -{ - int x; - - if (p && p->echocancel && p->echotraining) - { - x = (p->echotraining) ? UC_ECHO_CANCEL_TRAINING : UC_ECHO_CANCEL_NOTRAINING; - if (uc_channel_echo_cancel(p->uc, 0, x) != UC_RET_OK) - ast_log(LOG_WARNING, "Unable to request echo training on channel %d\n", p->channel); - else - ast_log(LOG_DEBUG, "Engaged echo training on channel %d\n", p->channel); - /*endif*/ - } - else - { - ast_log(LOG_DEBUG, "No echo training requested\n"); - } - /*endif*/ -} - static void unicall_disable_ec(struct unicall_pvt *p) { if (p == NULL) @@ -1277,10 +1234,11 @@ /* Ditch the holding callwait call, and immediately make it availabe */ if (p->subs[SUB_CALLWAIT].inthreeway) { + struct ast_channel *bridged_chan = ast_bridged_channel(p->subs[SUB_THREEWAY].owner); /* This is actually part of a three way, placed on hold. Place the third part on music on hold now */ - if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) - ast_moh_start(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), NULL); + if (p->subs[SUB_THREEWAY].owner && bridged_chan ) + ast_moh_start(bridged_chan, bridged_chan->musicclass, NULL); /*endif*/ p->subs[SUB_THREEWAY].inthreeway = FALSE; /* Make it the call wait now */ @@ -1296,10 +1254,11 @@ case SUB_THREEWAY: if (p->subs[SUB_CALLWAIT].inthreeway) { + struct ast_channel *bridged_chan = ast_bridged_channel(p->subs[SUB_CALLWAIT].owner); /* The other party of the three way call is currently in a call-wait state. Start music on hold for them, and take the main guy out of the third call */ - if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) - ast_moh_start(ast_bridged_channel(p->subs[SUB_CALLWAIT].owner), NULL); + if (p->subs[SUB_CALLWAIT].owner && bridged_chan ) + ast_moh_start(bridged_chan, bridged_chan->musicclass, NULL); /*endif*/ p->subs[SUB_CALLWAIT].inthreeway = FALSE; } @@ -1408,7 +1367,7 @@ /*endif*/ if (p->crn) { - ast_log(LOG_WARNING, "Answer Call\n"); + ast_log(LOG_DEBUG, "Answer Call\n"); if ((ret = uc_call_control(p->uc, UC_OP_ANSWERCALL, p->crn, NULL))) ast_log(LOG_WARNING, "Answer call failed on %s - %s\n", ast->name, uc_ret2str(ret)); /*endif*/ @@ -1427,7 +1386,7 @@ char *cp; int x; - ast_log(LOG_WARNING, "unicall_setoption called - %d\n", option); + ast_log(LOG_DEBUG, "unicall_setoption called - %d\n", option); if (option != AST_OPTION_TONE_VERIFY && option != AST_OPTION_TDD @@ -1584,7 +1543,7 @@ ast_log(LOG_DEBUG, "Making %d slave to master %d\n", slave->channel, master->channel); } -static int unicall_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) +static enum ast_bridge_result unicall_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timoutms) { struct unicall_pvt *p0; struct unicall_pvt *p1; @@ -1617,16 +1576,16 @@ os2 = -1; inconf = FALSE; nothingok = FALSE; - ast_log(LOG_WARNING, "unicall_bridge called\n"); + ast_log(LOG_DEBUG, "unicall_bridge called\n"); /* If need DTMF, can't native bridge */ if ((flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) - return -2; + return AST_BRIDGE_FAILED_NOWARN; /*endif*/ p0 = c0->tech_pvt; p1 = c1->tech_pvt; /* Can't do pseudo-channels here */ if (p0->protocol_class == NULL || p1->protocol_class == NULL) - return -2; + return AST_BRIDGE_FAILED_NOWARN; /*endif*/ ast_mutex_lock(&c0->lock); ast_mutex_lock(&c1->lock); @@ -1641,7 +1600,7 @@ oc1 = p0->owner; oc2 = p1->owner; if (oi1 < 0 || oi2 < 0) - return -1; + return AST_BRIDGE_FAILED; /*endif*/ ast_mutex_lock(&p0->lock); if (ast_mutex_trylock(&p1->lock)) @@ -1651,7 +1610,7 @@ ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); ast_log(LOG_NOTICE, "Avoiding deadlock...\n"); - return -3; + return AST_BRIDGE_RETRY; } /*endif*/ if (oi1 == SUB_REAL && oi2 == SUB_REAL) @@ -1817,7 +1776,7 @@ /* Native bridge failed */ if ((master == NULL || slave == NULL) && !nothingok) - return -1; + return AST_BRIDGE_FAILED; /*endif*/ cs[SUB_REAL] = c0; cs[SUB_CALLWAIT] = c1; @@ -1871,7 +1830,7 @@ oi1, op1->channel, oi2); - return -3; + return AST_BRIDGE_RETRY; } /*endif*/ to = -1; @@ -1899,7 +1858,7 @@ if (slave && master) unicall_unlink(slave, master); /*endif*/ - return 0; + return AST_BRIDGE_COMPLETE; } /*endif*/ if (f->frametype == AST_FRAME_DTMF) @@ -1913,7 +1872,7 @@ if (slave && master) unicall_unlink(slave, master); /*endif*/ - return 0; + return AST_BRIDGE_COMPLETE; } /*endif*/ } @@ -1928,7 +1887,7 @@ /*endif*/ } -static int unicall_indicate(struct ast_channel *chan, int condition); +static int unicall_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen); static int unicall_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) { @@ -1937,7 +1896,7 @@ p = newchan->tech_pvt; ast_mutex_lock(&p->lock); - ast_log(LOG_WARNING, "New owner for channel %d is %s\n", p->channel, newchan->name); + ast_log(LOG_NOTICE, "New owner for channel %d is %s\n", p->channel, newchan->name); //ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name); if (p->owner == oldchan) p->owner = newchan; @@ -1955,7 +1914,7 @@ } /*endfor*/ if (newchan->_state == AST_STATE_RINGING) - unicall_indicate(newchan, AST_CONTROL_RINGING); + unicall_indicate(newchan, AST_CONTROL_RINGING, NULL, 0); /*endif*/ update_conf(p); ast_mutex_unlock(&p->lock); @@ -1997,7 +1956,7 @@ } /*endif*/ if (!p->radio) - ast_log(LOG_DEBUG, "Exception on %d, channel %d\n", ast->fds[0],p->channel); + ast_log(LOG_NOTICE, "Exception on %d, channel %d\n", ast->fds[0],p->channel); /*endif*/ /* If it's not us, return NULL immediately */ if (ast != p->owner) @@ -2011,7 +1970,7 @@ return &p->subs[index].f; } -void handle_uc_read(uc_t *uc, int ch, void *user_data, uint8_t *buf, int len) +static void handle_uc_read(uc_t *uc, int ch, void *user_data, uint8_t *buf, int len) { void *readbuf; struct unicall_pvt *p; @@ -2148,7 +2107,7 @@ /* Check first for any outstanding DTMF characters */ if (p->subs[index].dtmfq[0]) { - ast_log(LOG_WARNING, "got a DTMF %d\n", p->subs[index].dtmfq[0]); + ast_log(LOG_NOTICE, "got a DTMF %d\n", p->subs[index].dtmfq[0]); p->subs[index].f.subclass = p->subs[index].dtmfq[0]; memmove(&p->subs[index].dtmfq[0], &p->subs[index].dtmfq[1], sizeof(p->subs[index].dtmfq) - 1); p->subs[index].f.frametype = AST_FRAME_DTMF; @@ -2203,7 +2162,7 @@ /*endif*/ if (p->confirmanswer) { - ast_log(LOG_WARNING, "Confirm answer!\n"); + ast_log(LOG_NOTICE, "Confirm answer!\n"); /* Upon receiving a DTMF digit, consider this an answer confirmation instead of a DTMF digit */ p->subs[index].f.frametype = AST_FRAME_CONTROL; @@ -2430,7 +2389,8 @@ return 0; } -static int unicall_indicate(struct ast_channel *chan, int condition) +/* TODO: proper *data management */ +static int unicall_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen) { struct unicall_pvt *p; int res = -1; @@ -2438,7 +2398,7 @@ int ret; p = chan->tech_pvt; - ast_log(LOG_WARNING, "unicall_indicate %d\n", condition); + ast_log(LOG_NOTICE, "unicall_indicate %d\n", condition); if ((index = unicall_get_index(chan, p, 0)) != SUB_REAL) return 0; /*endif*/ @@ -2496,15 +2456,11 @@ static struct ast_channel *unicall_new(struct unicall_pvt *i, int state, int startpbx, int index, int law) { struct ast_channel *tmp; + char chan_name[AST_CHANNEL_NAME]; int deflaw; int x; int y; - if ((tmp = ast_channel_alloc(0)) == NULL) - { - ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); - return NULL; - } /*endif*/ if (law == 0) law = uc_channel_get_api_codec(i->uc, 0); @@ -2517,10 +2473,10 @@ y = 1; do { - snprintf(tmp->name, sizeof(tmp->name), "UniCall/%d-%d", i->channel, y); + snprintf(chan_name, sizeof(chan_name), "UniCall/%d-%d", i->channel, y); for (x = 0; x < 3; x++) { - if (index != x && i->subs[x].owner && strcasecmp(tmp->name, i->subs[x].owner->name) == 0) + if (index != x && i->subs[x].owner && strcasecmp(chan_name, i->subs[x].owner->name) == 0) break; /*endif*/ } @@ -2528,7 +2484,13 @@ y++; } while (x < 3); - tmp->type = type; + + if ( ( tmp = ast_channel_alloc(0, state, 0, 0, chan_name) ) == NULL) + { + ast_log(LOG_WARNING, "Unable to allocate channel structure\n"); + return NULL; + } + tmp->tech = &unicall_tech; tmp->fds[0] = i->subs[index].fd; tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw; @@ -2562,16 +2524,16 @@ /*endif*/ tmp->tech_pvt = i; if (strlen(i->language)) - strncpy(tmp->language, i->language, sizeof(tmp->language) - 1); + ast_string_field_set(tmp, language, i->language); /*endif*/ if (strlen(i->musicclass)) - strncpy(tmp->musicclass, i->musicclass, sizeof(tmp->musicclass) - 1); + ast_string_field_set(tmp, musicclass, i->musicclass); /*endif*/ if (i->owner == NULL) i->owner = tmp; /*endif*/ if (strlen(i->accountcode)) - strncpy(tmp->accountcode, i->accountcode, sizeof(tmp->accountcode) - 1); + ast_string_field_set(tmp, accountcode, i->accountcode); /*endif*/ if (i->amaflags) tmp->amaflags = i->amaflags; @@ -2580,14 +2542,13 @@ ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[index]); /*endif*/ i->subs[index].owner = tmp; - ast_setstate(tmp, state); ast_mutex_lock(&usecnt_lock); usecnt++; ast_mutex_unlock(&usecnt_lock); ast_update_use_count(); strncpy(tmp->context, i->context, sizeof(tmp->context) - 1); /* Copy call forward info */ - strncpy(tmp->call_forward, i->call_forward, sizeof(tmp->call_forward)); + ast_string_field_set(tmp, call_forward, i->call_forward); /* If we've been told "no ADSI" then enforce it */ if (!i->adsi) tmp->adsicpe = AST_ADSI_UNAVAILABLE; @@ -2621,13 +2582,7 @@ return tmp; } -int channel_error(uc_t *uc, int user_data, int cause) -{ - ast_log(LOG_ERROR, "Channel error - %d\n", cause); - return 0; -} - -void handle_uc_event(uc_t *uc, void *user_data, uc_event_t *ev) +static void handle_uc_event(uc_t *uc, void *user_data, uc_event_t *ev) { struct ast_channel *c; struct unicall_pvt *i; @@ -2641,12 +2596,11 @@ /*endif*/ /* Handle an event on a given channel for the monitor thread. */ - ast_log(LOG_WARNING, "Unicall/%d event %s\n", i->channel, uc_event2str(ev->e)); + ast_log(LOG_NOTICE, "Unicall/%d event %s\n", i->channel, uc_event2str(ev->e)); switch (ev->e) { case UC_EVENT_PROTOCOLFAIL: - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Unicall/%d protocol error. Cause %d\n", i->channel, ev->gen.data); + ast_log(LOG_ERROR, "Unicall/%d protocol error. Cause %d\n", i->channel, ev->gen.data); /*endif*/ if (!i->blocked) { @@ -2696,7 +2650,7 @@ break; case UC_EVENT_OFFERED: /* Check for callerid, digits, etc */ - ast_log(LOG_WARNING, + ast_log(LOG_NOTICE, "CRN %d - Offered on channel %d (ANI: %s, DNIS: %s, Cat: %d)\n", ev->offered.crn, ev->offered.channel, @@ -2783,7 +2737,7 @@ /*endif*/ break; case UC_EVENT_MOREDIGITS: - ast_log(LOG_WARNING, "Dest '%s'\n", ev->offered.parms.destination_number); + ast_log(LOG_NOTICE, "Dest '%s'\n", ev->offered.parms.destination_number); if ((ch = ev->offered.channel) >= 0) { /* Get caller ID */ @@ -2897,7 +2851,7 @@ else { i->dialing = TRUE; - dtmf_put(&i->subs[SUB_REAL].dtmf_tx_state, i->dialstr); + dtmf_tx_put(&i->subs[SUB_REAL].dtmf_tx_state, i->dialstr); ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", i->dialstr); i->dialstr[0] = '\0'; } @@ -2927,7 +2881,7 @@ case UC_EVENT_FARDISCONNECTED: if ((ch = ev->fardisconnected.channel) >= 0) { - ast_log(LOG_WARNING, "CRN %d - far disconnected cause=%s [%d]\n", ev->fardisconnected.crn, uc_cause2str(ev->fardisconnected.cause), ev->fardisconnected.cause); + ast_log(LOG_NOTICE, "CRN %d - far disconnected cause=%s [%d]\n", ev->fardisconnected.crn, uc_cause2str(ev->fardisconnected.cause), ev->fardisconnected.cause); if (i->owner) { i->alreadyhungup = TRUE; @@ -3717,7 +3671,7 @@ return group; } -static char *complete_span(char *line, char *word, int pos, int state) +static char *complete_span(const char *line, const char *word, int pos, int state) { int span; char tmp[50]; @@ -3814,11 +3768,11 @@ return RESULT_SUCCESS; } -static char uc_debug_help[] = +static const char uc_debug_help[] = "Usage: UC debug span \n" " Enables debugging on a given PRI span\n"; -static char uc_no_debug_help[] = +static const char uc_no_debug_help[] = "Usage: UC no debug span \n" " Disables debugging on a given PRI span\n"; @@ -3988,6 +3942,8 @@ {"UC", "destroy", "channel", NULL}, unicall_destroy_channel, "Destroy a channel", destroy_channel_usage, NULL }; +static int unload_module(void); + static int setup_unicall(int reload) { struct unicall_pvt *tmp; @@ -4271,7 +4227,7 @@ return 0; } -int load_module(void) +static int load_module(void) { uc_start(); uc_set_error_handler(unicall_report); @@ -4293,7 +4249,7 @@ return 0; } -int unload_module(void) +static int unload_module(void) { struct unicall_pvt *p; struct unicall_pvt *pl; @@ -4386,7 +4342,7 @@ return 0; } -int reload(void) +static int reload(void) { int res; @@ -4398,22 +4354,14 @@ return 0; } -int usecount(void) -{ - int res; +/* This is a workaround so that menuselect displays a proper description + * AST_MODULE_INFO(, , "Unicall / R2" + */ - ast_mutex_lock(&usecnt_lock); - res = usecnt; - ast_mutex_unlock(&usecnt_lock); - return res; -} +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc, + .load = load_module, + .unload = unload_module, + .reload = reload, +); -char *description(void) -{ - return (char *) desc; -} -char *key(void) -{ - return ASTERISK_GPL_KEY; -}