diff options
author | qwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-02-24 02:23:43 +0000 |
---|---|---|
committer | qwell <qwell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-02-24 02:23:43 +0000 |
commit | 951d5a9da0f85344b41a0eee84f38451f552dc75 (patch) | |
tree | 86420597cd2dcbbe4fcd78524755e56a3eb391ad /channels | |
parent | 90684f71938147f10ecb86c3ce55e6f69205cffc (diff) |
Allow a Skinny device to monitor a dialplan hint (w00t!).
See skinny.conf.sample for configuration example.
Note: Some devices (seen on 12SP+/30VIP) will lock up if they monitor too many hints.
This seems to be a hardware limitation - there isn't anything we can do about it.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@56594 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_skinny.c | 219 |
1 files changed, 180 insertions, 39 deletions
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c index c7d037959..730bf374d 100644 --- a/channels/chan_skinny.c +++ b/channels/chan_skinny.c @@ -409,8 +409,8 @@ struct button_definition_template { /* Custom button types - add our own between 0xB0 and 0xCF. This may need to be revised in the future, if stimuluses are ever added in this range. */ -#define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial */ -#define BT_CUST_HINT 0xB1 /* pipe dream */ +#define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial with/without hint */ +#define BT_CUST_LINE 0xB1 /* line or speeddial with hint only */ struct button_template_res_message { uint32_t buttonOffset; @@ -830,6 +830,7 @@ static int callnums = 1; #define SKINNY_TRANSFER 10 #define SKINNY_PARK 11 #define SKINNY_PROGRESS 12 +#define SKINNY_CALLREMOTEMULTILINE 13 #define SKINNY_INVALID 14 #define SKINNY_SILENCE 0x00 @@ -974,8 +975,12 @@ struct skinny_line { struct skinny_speeddial { ast_mutex_t lock; char label[42]; + char context[AST_MAX_CONTEXT]; char exten[AST_MAX_EXTENSION]; int instance; + int stateid; + int laststate; + int isHint; struct skinny_speeddial *next; struct skinny_device *parent; @@ -1059,6 +1064,8 @@ static const struct ast_channel_tech skinny_tech = { /* .bridge = ast_rtp_bridge, */ }; +static int skinny_extensionstate_cb(char *context, char* exten, int state, void *data); + static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn) { struct skinny_device *d = s->device; @@ -1070,7 +1077,7 @@ static void *get_button_template(struct skinnysession *s, struct button_definiti case SKINNY_DEVICE_30VIP: /* 13 rows, 2 columns */ for (i = 0; i < 4; i++) - (btn++)->buttonDefinition = BT_LINE; + (btn++)->buttonDefinition = BT_CUST_LINE; (btn++)->buttonDefinition = BT_REDIAL; (btn++)->buttonDefinition = BT_VOICEMAIL; (btn++)->buttonDefinition = BT_CALLPARK; @@ -1087,16 +1094,15 @@ static void *get_button_template(struct skinnysession *s, struct button_definiti case SKINNY_DEVICE_12: /* 6 rows, 2 columns */ for (i = 0; i < 2; i++) - (btn++)->buttonDefinition = BT_LINE; - (btn++)->buttonDefinition = BT_REDIAL; - for (i = 0; i < 3; i++) + (btn++)->buttonDefinition = BT_CUST_LINE; + for (i = 0; i < 4; i++) (btn++)->buttonDefinition = BT_SPEEDDIAL; (btn++)->buttonDefinition = BT_HOLD; + (btn++)->buttonDefinition = BT_REDIAL; (btn++)->buttonDefinition = BT_TRANSFER; (btn++)->buttonDefinition = BT_FORWARDALL; (btn++)->buttonDefinition = BT_CALLPARK; (btn++)->buttonDefinition = BT_VOICEMAIL; - (btn++)->buttonDefinition = BT_CONFERENCE; break; case SKINNY_DEVICE_7910: (btn++)->buttonDefinition = BT_LINE; @@ -1285,12 +1291,12 @@ static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_devi return sub; } -static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance) +static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance, int isHint) { struct skinny_speeddial *sd; for (sd = d->speeddials; sd; sd = sd->next) { - if (sd->instance == instance) + if (sd->isHint == isHint && sd->instance == instance) break; } @@ -1344,10 +1350,11 @@ static int codec_ast2skinny(int astcodec) } } - static int skinny_register(struct skinny_req *req, struct skinnysession *s) { struct skinny_device *d; + struct skinny_line *l; + struct skinny_speeddial *sd; struct sockaddr_in sin; socklen_t slen; @@ -1369,6 +1376,13 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s) sin.sin_addr = __ourip; } d->ourip = sin.sin_addr; + + for (sd = d->speeddials; sd; sd = sd->next) { + sd->stateid = ast_extension_state_add(sd->context, sd->exten, skinny_extensionstate_cb, sd); + } + for (l = d->lines; l; l = l->next) { + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + } break; } } @@ -1382,12 +1396,22 @@ static int skinny_register(struct skinny_req *req, struct skinnysession *s) static int skinny_unregister(struct skinny_req *req, struct skinnysession *s) { struct skinny_device *d; + struct skinny_line *l; + struct skinny_speeddial *sd; d = s->device; if (d) { d->session = NULL; d->registered = 0; + + for (sd = d->speeddials; sd; sd = sd->next) { + if (sd->stateid > -1) + ast_extension_state_del(sd->stateid, NULL); + } + for (l = d->lines; l; l = l->next) { + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + } } return -1; /* main loop will destroy the session */ @@ -1684,6 +1708,59 @@ static void transmit_dialednumber(struct skinnysession *s, const char *text, int transmit_response(s, req); } +static int skinny_extensionstate_cb(char *context, char *exten, int state, void *data) +{ + struct skinny_speeddial *sd = data; + struct skinny_device *d = sd->parent; + struct skinnysession *s = d->session; + char hint[AST_MAX_EXTENSION]; + int callstate = SKINNY_CALLREMOTEMULTILINE; + int lamp = SKINNY_LAMP_OFF; + + switch (state) { + case AST_EXTENSION_DEACTIVATED: /* Retry after a while */ + case AST_EXTENSION_REMOVED: /* Extension is gone */ + ast_verbose(VERBOSE_PREFIX_2 "Extension state: Watcher for hint %s %s. Notify Device %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", d->name); + sd->stateid = -1; + callstate = SKINNY_ONHOOK; + lamp = SKINNY_LAMP_OFF; + break; + case AST_EXTENSION_RINGING: + case AST_EXTENSION_UNAVAILABLE: + callstate = SKINNY_RINGIN; + lamp = SKINNY_LAMP_BLINK; + break; + case AST_EXTENSION_BUSY: /* callstate = SKINNY_BUSY wasn't wanting to work - I'll settle for this */ + case AST_EXTENSION_INUSE: + callstate = SKINNY_CALLREMOTEMULTILINE; + lamp = SKINNY_LAMP_ON; + break; + case AST_EXTENSION_ONHOLD: + callstate = SKINNY_HOLD; + lamp = SKINNY_LAMP_WINK; + break; + case AST_EXTENSION_NOT_INUSE: + default: + callstate = SKINNY_ONHOOK; + lamp = SKINNY_LAMP_OFF; + break; + } + + if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, sd->context, sd->exten)) { + /* If they are not registered, we will override notification and show no availability */ + if (ast_device_state(hint) == AST_DEVICE_UNAVAILABLE) { + callstate = SKINNY_ONHOOK; + lamp = SKINNY_LAMP_FLASH; + } + } + + transmit_lamp_indication(s, STIMULUS_LINE, sd->instance, lamp); + transmit_callstate(s, sd->instance, callstate, 0); + sd->laststate = state; + + return 0; +} + /* static int has_voicemail(struct skinny_line *l) { @@ -2099,17 +2176,25 @@ static struct skinny_device *build_device(const char *cat, struct ast_variable * if (!(sd = ast_calloc(1, sizeof(struct skinny_speeddial)))) { return NULL; } else { - char *stringp, *exten, *label; + char *stringp, *exten, *context, *label; stringp = v->value; exten = strsep(&stringp, ","); - label = strsep(&stringp, ","); + if ((context = strchr(exten, '@'))) { + *context++ = '\0'; + } + label = stringp; ast_mutex_init(&sd->lock); ast_copy_string(sd->exten, exten, sizeof(sd->exten)); - if (label) - ast_copy_string(sd->label, label, sizeof(sd->label)); - else - ast_copy_string(sd->label, exten, sizeof(sd->label)); - sd->instance = speeddialInstance++; + if (!ast_strlen_zero(context)) { + sd->isHint = 1; + sd->instance = lineInstance++; + ast_copy_string(sd->context, context, sizeof(sd->context)); + } else { + sd->isHint = 0; + sd->instance = speeddialInstance++; + sd->context[0] = '\0'; + } + ast_copy_string(sd->label, S_OR(label, exten), sizeof(sd->label)); sd->parent = d; @@ -2833,7 +2918,7 @@ static int skinny_hold(struct skinny_subchannel *sub) req->data.stopmedia.passThruPartyId = htolel(sub->callid); transmit_response(s, req); - transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK); + transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_WINK); sub->onhold = 1; return 1; } @@ -3058,7 +3143,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession ast_verbose("Received Stimulus: SpeedDial(%d)\n", instance); #if 0 - if (!(sd = find_speeddial_by_instance(d, instance))) { + if (!(sd = find_speeddial_by_instance(d, instance, 0))) { return 0; } @@ -3162,7 +3247,7 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession if (skinnydebug) ast_verbose("Received Stimulus: Line(%d)\n", instance); - l = find_line_by_instance(s->device, instance); + l = find_line_by_instance(d, instance); if (!l) { return 0; @@ -3175,6 +3260,8 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession l->hookstate = SKINNY_OFFHOOK; + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + if (sub && sub->outgoing) { /* We're answering a ringing call */ ast_queue_control(sub->owner, AST_CONTROL_ANSWER); @@ -3216,6 +3303,8 @@ static int handle_stimulus_message(struct skinny_req *req, struct skinnysession ast_verbose("RECEIVED UNKNOWN STIMULUS: %d(%d)\n", event, instance); break; } + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + return 1; } @@ -3243,15 +3332,16 @@ static int handle_offhook_message(struct skinny_req *req, struct skinnysession * l = sub->parent; } + transmit_ringer_mode(s, SKINNY_RING_OFF); + l->hookstate = SKINNY_OFFHOOK; + + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + if (sub && sub->onhold) { - transmit_ringer_mode(s, SKINNY_RING_OFF); - l->hookstate = SKINNY_OFFHOOK; return 1; } - transmit_ringer_mode(s, SKINNY_RING_OFF); transmit_lamp_indication(s, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON); - l->hookstate = SKINNY_OFFHOOK; if (sub && sub->outgoing) { /* We're answering a ringing call */ @@ -3308,17 +3398,19 @@ static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s } l = sub->parent; - if (sub->onhold) { - l->hookstate = SKINNY_ONHOOK; + if (l->hookstate == SKINNY_ONHOOK) { + /* Something else already put us back on hook */ return 0; } + l->hookstate = SKINNY_ONHOOK; - if (l->hookstate == SKINNY_ONHOOK) { - /* Something else already put us back on hook */ + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + + if (sub->onhold) { return 0; } + sub->cxmode = SKINNY_CX_RECVONLY; - l->hookstate = SKINNY_ONHOOK; transmit_callstate(s, l->instance, l->hookstate, sub->callid); if (skinnydebug) ast_verbose("Skinny %s@%s went on hook\n", l->name, d->name); @@ -3393,7 +3485,7 @@ static int handle_speed_dial_stat_req_message(struct skinny_req *req, struct ski instance = letohl(req->data.speeddialreq.speedDialNumber); - sd = find_speeddial_by_instance(d, instance); + sd = find_speeddial_by_instance(d, instance, 0); if (!sd) { return 0; @@ -3414,6 +3506,7 @@ static int handle_line_state_req_message(struct skinny_req *req, struct skinnyse { struct skinny_device *d = s->device; struct skinny_line *l; + struct skinny_speeddial *sd = NULL; int instance; instance = letohl(req->data.line.lineNumber); @@ -3423,6 +3516,10 @@ static int handle_line_state_req_message(struct skinny_req *req, struct skinnyse l = find_line_by_instance(d, instance); if (!l) { + sd = find_speeddial_by_instance(d, instance, 1); + } + + if (!l && !sd) { return 0; } @@ -3432,10 +3529,13 @@ static int handle_line_state_req_message(struct skinny_req *req, struct skinnyse return -1; req->data.linestat.lineNumber = letohl(instance); - memcpy(req->data.linestat.lineDirNumber, l->name, - sizeof(req->data.linestat.lineDirNumber)); - memcpy(req->data.linestat.lineDisplayName, l->label, - sizeof(req->data.linestat.lineDisplayName)); + if (!l) { + memcpy(req->data.linestat.lineDirNumber, sd->label, sizeof(req->data.linestat.lineDirNumber)); + memcpy(req->data.linestat.lineDisplayName, sd->label, sizeof(req->data.linestat.lineDisplayName)); + } else { + memcpy(req->data.linestat.lineDirNumber, l->name, sizeof(req->data.linestat.lineDirNumber)); + memcpy(req->data.linestat.lineDisplayName, l->label, sizeof(req->data.linestat.lineDisplayName)); + } transmit_response(s,req); return 1; } @@ -3483,6 +3583,37 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski for (i=0; i<42; i++) { int btnSet = 0; switch (btn[i].buttonDefinition) { + case BT_CUST_LINE: + /* assume failure */ + req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE; + req->data.buttontemplate.definition[i].instanceNumber = htolel(0); + + for (l = d->lines; l; l = l->next) { + if (l->instance == lineInstance) { + ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance); + req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE; + req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance); + lineInstance++; + buttonCount++; + btnSet = 1; + break; + } + } + + if (!btnSet) { + for (sd = d->speeddials; sd; sd = sd->next) { + if (sd->isHint && sd->instance == lineInstance) { + ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance); + req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE; + req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance); + lineInstance++; + buttonCount++; + btnSet = 1; + break; + } + } + } + break; case BT_CUST_LINESPEEDDIAL: /* assume failure */ req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE; @@ -3502,7 +3633,15 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski if (!btnSet) { for (sd = d->speeddials; sd; sd = sd->next) { - if (sd->instance == speeddialInstance) { + if (sd->isHint && sd->instance == lineInstance) { + ast_verbose("Adding button: %d, %d\n", BT_LINE, lineInstance); + req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE; + req->data.buttontemplate.definition[i].instanceNumber = htolel(lineInstance); + lineInstance++; + buttonCount++; + btnSet = 1; + break; + } else if (!sd->isHint && sd->instance == speeddialInstance) { ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance); req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL; req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance); @@ -3535,10 +3674,10 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski req->data.buttontemplate.definition[i].instanceNumber = 0; for (sd = d->speeddials; sd; sd = sd->next) { - if (sd->instance == speeddialInstance) { + if (!sd->isHint && sd->instance == speeddialInstance) { ast_verbose("Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance); req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL; - req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance); + req->data.buttontemplate.definition[i].instanceNumber = htolel(speeddialInstance - 1); speeddialInstance++; buttonCount++; btnSet = 1; @@ -3546,8 +3685,6 @@ static int handle_button_template_req_message(struct skinny_req *req, struct ski } } break; - case BT_CUST_HINT: - break; case BT_NONE: break; default: @@ -3738,6 +3875,8 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse return 0; } + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + switch(event) { case SOFTKEY_NONE: if (skinnydebug) @@ -3965,6 +4104,8 @@ static int handle_soft_key_event_message(struct skinny_req *req, struct skinnyse ast_verbose("Received unknown Softkey Event: %d(%d)\n", event, instance); break; } + ast_device_state_changed("Skinny/%s@%s", l->name, d->name); + return 1; } |