📄 chan_skinny.c
字号:
d->type = letohl(req->data.reg.type); if (ast_strlen_zero(d->version_id)) { ast_copy_string(d->version_id, version_id, sizeof(d->version_id)); } d->registered = 1; d->session = s; slen = sizeof(sin); if (getsockname(s->fd, (struct sockaddr *)&sin, &slen)) { ast_log(LOG_WARNING, "Cannot get socket name\n"); sin.sin_addr = __ourip; } d->ourip = sin.sin_addr; break; } } ast_mutex_unlock(&devicelock); if (!d) { return 0; } return 1;}static int skinny_unregister(struct skinny_req *req, struct skinnysession *s){ struct skinny_device *d; d = s->device; if (d) { d->session = NULL; d->registered = 0; } return -1; /* main loop will destroy the session */}static int transmit_response(struct skinnysession *s, struct skinny_req *req){ int res = 0; if (!s) { ast_log(LOG_WARNING, "Asked to transmit to a non-existant session!\n"); return -1; } ast_mutex_lock(&s->lock); if (skinnydebug) ast_log(LOG_VERBOSE, "writing packet type %04X (%d bytes) to socket %d\n", letohl(req->e), letohl(req->len)+8, s->fd); if (letohl(req->len > SKINNY_MAX_PACKET) || letohl(req->len < 0)) { ast_log(LOG_WARNING, "transmit_response: the length of the request is out of bounds\n"); ast_mutex_unlock(&s->lock); return -1; } memset(s->outbuf,0,sizeof(s->outbuf)); memcpy(s->outbuf, req, skinny_header_size); memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len)); res = write(s->fd, s->outbuf, letohl(req->len)+8); if (res != letohl(req->len)+8) { ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno)); if (res == -1) { if (skinnydebug) ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n"); skinny_unregister(NULL, s); } } ast_mutex_unlock(&s->lock); return 1;}static void transmit_speaker_mode(struct skinnysession *s, int mode){ struct skinny_req *req; if (!(req = req_alloc(sizeof(struct set_speaker_message), SET_SPEAKER_MESSAGE))) return; req->data.setspeaker.mode = htolel(mode); transmit_response(s, req);}/*static void transmit_microphone_mode(struct skinnysession *s, int mode){ struct skinny_req *req; if (!(req = req_alloc(sizeof(struct set_microphone_message), SET_MICROPHONE_MESSAGE))) return; req->data.setmicrophone.mode = htolel(mode); transmit_response(s, req);}*/static void transmit_callinfo(struct skinnysession *s, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype){ struct skinny_req *req; if (!(req = req_alloc(sizeof(struct call_info_message), CALL_INFO_MESSAGE))) return; if (skinnydebug) ast_verbose("Setting Callinfo to %s(%s) from %s(%s) on %s(%d)\n", fromname, fromnum, toname, tonum, s->device->name, instance); if (fromname) { ast_copy_string(req->data.callinfo.callingPartyName, fromname, sizeof(req->data.callinfo.callingPartyName)); } if (fromnum) { ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty)); } if (toname) { ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName)); } if (tonum) { ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty)); } req->data.callinfo.instance = htolel(instance); req->data.callinfo.reference = htolel(callid); req->data.callinfo.type = htolel(calltype); transmit_response(s, req);}static void transmit_connect(struct skinnysession *s, struct skinny_subchannel *sub){ struct skinny_req *req; struct skinny_line *l = sub->parent; struct ast_format_list fmt; if (!(req = req_alloc(sizeof(struct open_receive_channel_message), OPEN_RECEIVE_CHANNEL_MESSAGE))) return; fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability)); req->data.openreceivechannel.conferenceId = htolel(sub->callid); req->data.openreceivechannel.partyId = htolel(sub->callid); req->data.openreceivechannel.packets = htolel(fmt.cur_ms); req->data.openreceivechannel.capability = htolel(codec_ast2skinny(fmt.bits)); req->data.openreceivechannel.echo = htolel(0); req->data.openreceivechannel.bitrate = htolel(0); transmit_response(s, req);}static void transmit_tone(struct skinnysession *s, int tone, int instance, int reference){ struct skinny_req *req; if (tone == SKINNY_NOTONE) { /* This is bad, mmm'kay? */ return; } if (tone > 0) { if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE))) return; req->data.starttone.tone = htolel(tone); req->data.starttone.instance = htolel(instance); req->data.starttone.reference = htolel(reference); } else { if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE))) return; req->data.stoptone.instance = htolel(instance); req->data.stoptone.reference = htolel(reference); } if (tone > 0) { req->data.starttone.tone = htolel(tone); } transmit_response(s, req);}static void transmit_selectsoftkeys(struct skinnysession *s, int instance, int callid, int softkey){ struct skinny_req *req; if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE))) return; req->data.selectsoftkey.instance = htolel(instance); req->data.selectsoftkey.reference = htolel(callid); req->data.selectsoftkey.softKeySetIndex = htolel(softkey); req->data.selectsoftkey.validKeyMask = htolel(0xFFFFFFFF); transmit_response(s, req);}static void transmit_lamp_indication(struct skinnysession *s, int stimulus, int instance, int indication){ struct skinny_req *req; if (!(req = req_alloc(sizeof(struct set_lamp_message), SET_LAMP_MESSAGE))) return; req->data.setlamp.stimulus = htolel(stimulus); req->data.setlamp.stimulusInstance = htolel(instance); req->data.setlamp.deviceStimulus = htolel(indication); transmit_response(s, req);}static void transmit_ringer_mode(struct skinnysession *s, int mode){ struct skinny_req *req; if (skinnydebug) ast_verbose("Setting ringer mode to '%d'.\n", mode); if (!(req = req_alloc(sizeof(struct set_ringer_message), SET_RINGER_MESSAGE))) return; req->data.setringer.ringerMode = htolel(mode); /* XXX okay, I don't quite know what this is, but here's what happens (on a 7960). Note: The phone will always show as ringing on the display. 1: phone will audibly ring over and over 2: phone will audibly ring only once any other value, will NOT cause the phone to audibly ring */ req->data.setringer.unknown1 = htolel(1); /* XXX the value here doesn't seem to change anything. Must be higher than 0. Perhaps a packet capture can shed some light on this. */ req->data.setringer.unknown2 = htolel(1); transmit_response(s, req);}static void transmit_displaymessage(struct skinnysession *s, const char *text, int instance, int reference){ struct skinny_req *req; if (text == 0) { if (!(req = req_alloc(0, CLEAR_DISPLAY_MESSAGE))) return; req->data.clearpromptstatus.lineInstance = instance; req->data.clearpromptstatus.callReference = reference; if (skinnydebug) ast_verbose("Clearing Display\n"); } else { if (!(req = req_alloc(sizeof(struct displaytext_message), DISPLAYTEXT_MESSAGE))) return; ast_copy_string(req->data.displaytext.text, text, sizeof(req->data.displaytext.text)); if (skinnydebug) ast_verbose("Displaying message '%s'\n", req->data.displaytext.text); } transmit_response(s, req);}static void transmit_displaynotify(struct skinnysession *s, const char *text, int t){ struct skinny_req *req; if (!(req = req_alloc(sizeof(struct display_notify_message), DISPLAY_NOTIFY_MESSAGE))) return; ast_copy_string(req->data.displaynotify.displayMessage, text, sizeof(req->data.displaynotify.displayMessage)); req->data.displaynotify.displayTimeout = htolel(t); if (skinnydebug) ast_verbose("Displaying notify '%s'\n", text); transmit_response(s, req);}static void transmit_displaypromptstatus(struct skinnysession *s, const char *text, int t, int instance, int callid){ struct skinny_req *req; if (text == 0) { if (!(req = req_alloc(sizeof(struct clear_prompt_message), CLEAR_PROMPT_MESSAGE))) return; req->data.clearpromptstatus.lineInstance = htolel(instance); req->data.clearpromptstatus.callReference = htolel(callid); if (skinnydebug) ast_verbose("Clearing Prompt\n"); } else { if (!(req = req_alloc(sizeof(struct display_prompt_status_message), DISPLAY_PROMPT_STATUS_MESSAGE))) return; ast_copy_string(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage)); req->data.displaypromptstatus.messageTimeout = htolel(t); req->data.displaypromptstatus.lineInstance = htolel(instance); req->data.displaypromptstatus.callReference = htolel(callid); if (skinnydebug) ast_verbose("Displaying Prompt Status '%s'\n", text); } transmit_response(s, req);}static void transmit_dialednumber(struct skinnysession *s, const char *text, int instance, int callid){ struct skinny_req *req; if (!(req = req_alloc(sizeof(struct dialed_number_message), DIALED_NUMBER_MESSAGE))) return; ast_copy_string(req->data.dialednumber.dialedNumber, text, sizeof(req->data.dialednumber.dialedNumber)); req->data.dialednumber.lineInstance = htolel(instance); req->data.dialednumber.callReference = htolel(callid); transmit_response(s, req);}static void transmit_callstate(struct skinnysession *s, int instance, int state, unsigned callid){ struct skinny_req *req; if (state == SKINNY_ONHOOK) { if (!(req = req_alloc(sizeof(struct close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE))) return; req->data.closereceivechannel.conferenceId = htolel(callid); req->data.closereceivechannel.partyId = htolel(callid); transmit_response(s, req); if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE))) return; req->data.stopmedia.conferenceId = htolel(callid); req->data.stopmedia.passThruPartyId = htolel(callid); transmit_response(s, req); transmit_speaker_mode(s, SKINNY_SPEAKEROFF); transmit_displaypromptstatus(s, NULL, 0, instance, callid); } if (!(req = req_alloc(sizeof(struct call_state_message), CALL_STATE_MESSAGE))) return; req->data.callstate.callState = htolel(state); req->data.callstate.lineInstance = htolel(instance); req->data.callstate.callReference = htolel(callid); transmit_response(s, req); if (state == SKINNY_ONHOOK) { transmit_selectsoftkeys(s, 0, 0, KEYDEF_ONHOOK); } if (state == SKINNY_OFFHOOK || state == SKINNY_ONHOOK) { if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE))) return; req->data.activatecallplane.lineInstance = htolel(instance); transmit_response(s, req); }}/*static int has_voicemail(struct skinny_line *l){ return ast_app_has_voicemail(l->mailbox, NULL);}*/static void do_housekeeping(struct skinnysession *s){/* int new; int old; struct skinny_device *d = s->device; struct skinny_line *l;*/ /* Update time on device */ handle_time_date_req_message(NULL, s);/* for (l = d->lines; l; l = l->next) { if (has_voicemail(l)) { if (skinnydebug) ast_verbose("Checking for voicemail Skinny %s@%s\n", l->name, d->name); ast_app_inboxcount(l->mailbox, &new, &old); if (skinnydebug) ast_verbose("Skinny %s@%s has voicemail!\n", l->name, d->name); transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON); } else { transmit_lamp_indication(s, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF); } }*/}/* I do not believe skinny can deal with video. Anyone know differently? *//* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */static enum ast_rtp_get_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp **rtp){ struct skinny_subchannel *sub = NULL; if (!(sub = c->tech_pvt) || !(sub->vrtp)) return AST_RTP_GET_FAILED; *rtp = sub->vrtp; return AST_RTP_TRY_NATIVE;}static enum ast_rtp_get_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp **rtp){ struct skinny_subchannel *sub = NULL; if (!(sub = c->tech_pvt) || !(sub->rtp)) return AST_RTP_GET_FAILED; *rtp = sub->rtp; return AST_RTP_TRY_NATIVE;}static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active){ struct skinny_subchannel *sub; sub = c->tech_pvt; if (sub) { /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */ return 0; } return -1;}static struct ast_rtp_protocol skinny_rtp = { .type = "Skinny", .get_rtp_info = skinny_get_rtp_peer, .get_vrtp_info = skinny_get_vrtp_peer, .set_rtp_peer = skinny_set_rtp_peer,};static int skinny_do_debug(int fd, int argc, char *argv[]){ if (argc != 3) { return RESULT_SHOWUSAGE; } skinnydebug = 1; ast_cli(fd, "Skinny Debugging Enabled\n"); return RESULT_SUCCESS;}static int skinny_no_debug(int fd, int argc, char *argv[]){ if (argc != 4) { return RESULT_SHOWUSAGE; } skinnydebug = 0; ast_cli(fd, "Skinny Debugging Disabled\n"); return RESULT_SUCCESS;}static char *complete_skinny_reset(const char *line, const char *word, int pos, int state){ struct skinny_device *d; char *result = NULL; int wordlen = strlen(word); int which = 0; if (pos == 2) { for (d = devices; d && !result; d = d->next) { if (!strncasecmp(word, d->id, wordlen) && ++which > state) result = ast_strdup(d->id); } } return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -