📄 chan_mgcp.c
字号:
if (p->hookstate == MGCP_OFFHOOK) { if (sub->next->owner && ast_bridged_channel(sub->next->owner)) { transmit_notify_request_with_callerid(p->sub, "L/wt", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name); } } else { /* set our other connection as the primary and swith over to it */ p->sub = sub->next; p->sub->cxmode = MGCP_CX_RECVONLY; transmit_modify_request(p->sub); if (sub->next->owner && ast_bridged_channel(sub->next->owner)) { transmit_notify_request_with_callerid(p->sub, "L/rg", ast_bridged_channel(sub->next->owner)->cid.cid_num, ast_bridged_channel(sub->next->owner)->cid.cid_name); } } } else if ((sub == p->sub->next) && p->hookstate == MGCP_OFFHOOK) { transmit_notify_request(sub, "L/v"); } else if (p->hookstate == MGCP_OFFHOOK) { transmit_notify_request(sub, "L/ro"); } else { transmit_notify_request(sub, ""); } ast->tech_pvt = NULL; sub->alreadygone = 0; sub->outgoing = 0; sub->cxmode = MGCP_CX_INACTIVE; sub->callid[0] = '\0'; if (p) { memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf)); } /* Reset temporary destination */ memset(&sub->tmpdest, 0, sizeof(sub->tmpdest)); if (sub->rtp) { ast_rtp_destroy(sub->rtp); sub->rtp = NULL; } ast_module_unref(ast_module_info->self); if ((p->hookstate == MGCP_ONHOOK) && (!sub->next->rtp)) { p->hidecallerid = 0; if (p->hascallwaiting && !p->callwaiting) { if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Enabling call waiting on %s\n", ast->name); p->callwaiting = -1; } if (has_voicemail(p)) { if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(+)\n", ast->name, p->name, p->parent->name); } transmit_notify_request(sub, "L/vmwi(+)"); } else { if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_hangup(%s) on %s@%s set vmwi(-)\n", ast->name, p->name, p->parent->name); } transmit_notify_request(sub, "L/vmwi(-)"); } } ast_mutex_unlock(&sub->lock); return 0;}static int mgcp_show_endpoints(int fd, int argc, char *argv[]){ struct mgcp_gateway *g; struct mgcp_endpoint *e; int hasendpoints = 0; if (argc != 3) return RESULT_SHOWUSAGE; ast_mutex_lock(&gatelock); g = gateways; while(g) { e = g->endpoints; ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? ast_inet_ntoa(g->addr.sin_addr) : ast_inet_ntoa(g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static"); while(e) { /* Don't show wilcard endpoint */ if (strcmp(e->name, g->wcardep) !=0) ast_cli(fd, " -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->sub->owner ? "active" : "idle"); hasendpoints = 1; e = e->next; } if (!hasendpoints) { ast_cli(fd, " << No Endpoints Defined >> "); } g = g->next; } ast_mutex_unlock(&gatelock); return RESULT_SUCCESS;}static char show_endpoints_usage[] = "Usage: mgcp show endpoints\n"" Lists all endpoints known to the MGCP (Media Gateway Control Protocol) subsystem.\n";static char audit_endpoint_usage[] = "Usage: mgcp audit endpoint <endpointid>\n"" Lists the capabilities of an endpoint in the MGCP (Media Gateway Control Protocol) subsystem.\n"" mgcp debug MUST be on to see the results of this command.\n";static char debug_usage[] = "Usage: mgcp set debug\n"" Enables dumping of MGCP packets for debugging purposes\n";static char no_debug_usage[] = "Usage: mgcp set debug off\n"" Disables dumping of MGCP packets for debugging purposes\n";static char mgcp_reload_usage[] ="Usage: mgcp reload\n"" Reloads MGCP configuration from mgcp.conf\n"" Deprecated: please use 'reload chan_mgcp.so' instead.\n";static int mgcp_audit_endpoint(int fd, int argc, char *argv[]){ struct mgcp_gateway *g; struct mgcp_endpoint *e; int found = 0; char *ename,*gname, *c; if (!mgcpdebug) { return RESULT_SHOWUSAGE; } if (argc != 4) return RESULT_SHOWUSAGE; /* split the name into parts by null */ ename = argv[3]; gname = ename; while (*gname) { if (*gname == '@') { *gname = 0; gname++; break; } gname++; } if (gname[0] == '[') gname++; if ((c = strrchr(gname, ']'))) *c = '\0'; ast_mutex_lock(&gatelock); g = gateways; while(g) { if (!strcasecmp(g->name, gname)) { e = g->endpoints; while(e) { if (!strcasecmp(e->name, ename)) { found = 1; transmit_audit_endpoint(e); break; } e = e->next; } if (found) { break; } } g = g->next; } if (!found) { ast_cli(fd, " << Could not find endpoint >> "); } ast_mutex_unlock(&gatelock); return RESULT_SUCCESS;}static int mgcp_do_debug(int fd, int argc, char *argv[]){ if (argc != 3) return RESULT_SHOWUSAGE; mgcpdebug = 1; ast_cli(fd, "MGCP Debugging Enabled\n"); return RESULT_SUCCESS;}static int mgcp_no_debug(int fd, int argc, char *argv[]){ if (argc != 4) return RESULT_SHOWUSAGE; mgcpdebug = 0; ast_cli(fd, "MGCP Debugging Disabled\n"); return RESULT_SUCCESS;}static struct ast_cli_entry cli_mgcp[] = { { { "mgcp", "audit", "endpoint", NULL }, mgcp_audit_endpoint, "Audit specified MGCP endpoint", audit_endpoint_usage }, { { "mgcp", "show", "endpoints", NULL }, mgcp_show_endpoints, "List defined MGCP endpoints", show_endpoints_usage }, { { "mgcp", "set", "debug", NULL }, mgcp_do_debug, "Enable MGCP debugging", debug_usage }, { { "mgcp", "set", "debug", "off", NULL }, mgcp_no_debug, "Disable MGCP debugging", no_debug_usage }, { { "mgcp", "reload", NULL }, mgcp_reload, "Reload MGCP configuration", mgcp_reload_usage },};static int mgcp_answer(struct ast_channel *ast){ int res = 0; struct mgcp_subchannel *sub = ast->tech_pvt; struct mgcp_endpoint *p = sub->parent; ast_mutex_lock(&sub->lock); sub->cxmode = MGCP_CX_SENDRECV; if (!sub->rtp) { start_rtp(sub); } else { transmit_modify_request(sub); } /* verbose level check */ if (option_verbose > 2) { ast_verbose(VERBOSE_PREFIX_3 "MGCP mgcp_answer(%s) on %s@%s-%d\n", ast->name, p->name, p->parent->name, sub->id); } if (ast->_state != AST_STATE_UP) { ast_setstate(ast, AST_STATE_UP); if (option_debug) ast_log(LOG_DEBUG, "mgcp_answer(%s)\n", ast->name); transmit_notify_request(sub, ""); transmit_modify_request(sub); } ast_mutex_unlock(&sub->lock); return res;}static struct ast_frame *mgcp_rtp_read(struct mgcp_subchannel *sub){ /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */ struct ast_frame *f; f = ast_rtp_read(sub->rtp); /* Don't send RFC2833 if we're not supposed to */ if (f && (f->frametype == AST_FRAME_DTMF) && !(sub->parent->dtmfmode & MGCP_DTMF_RFC2833)) return &ast_null_frame; if (sub->owner) { /* We already hold the channel lock */ if (f->frametype == AST_FRAME_VOICE) { if (f->subclass != sub->owner->nativeformats) { ast_log(LOG_DEBUG, "Oooh, format changed to %d\n", f->subclass); sub->owner->nativeformats = f->subclass; ast_set_read_format(sub->owner, sub->owner->readformat); ast_set_write_format(sub->owner, sub->owner->writeformat); } /* Courtesy fearnor aka alex@pilosoft.com */ if ((sub->parent->dtmfmode & MGCP_DTMF_INBAND) && (sub->parent->dsp)) {#if 0 ast_log(LOG_NOTICE, "MGCP ast_dsp_process\n");#endif f = ast_dsp_process(sub->owner, sub->parent->dsp, f); } } } return f;}static struct ast_frame *mgcp_read(struct ast_channel *ast){ struct ast_frame *f; struct mgcp_subchannel *sub = ast->tech_pvt; ast_mutex_lock(&sub->lock); f = mgcp_rtp_read(sub); ast_mutex_unlock(&sub->lock); return f;}static int mgcp_write(struct ast_channel *ast, struct ast_frame *frame){ struct mgcp_subchannel *sub = ast->tech_pvt; int res = 0; if (frame->frametype != AST_FRAME_VOICE) { if (frame->frametype == AST_FRAME_IMAGE) return 0; else { ast_log(LOG_WARNING, "Can't send %d type frames with MGCP write\n", frame->frametype); return 0; } } else { if (!(frame->subclass & ast->nativeformats)) { ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n", frame->subclass, ast->nativeformats, ast->readformat, ast->writeformat); return -1; } } if (sub) { ast_mutex_lock(&sub->lock); if ((sub->parent->sub == sub) || !sub->parent->singlepath) { if (sub->rtp) { res = ast_rtp_write(sub->rtp, frame); } } ast_mutex_unlock(&sub->lock); } return res;}static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan){ struct mgcp_subchannel *sub = newchan->tech_pvt; ast_mutex_lock(&sub->lock); ast_log(LOG_NOTICE, "mgcp_fixup(%s, %s)\n", oldchan->name, newchan->name); if (sub->owner != oldchan) { ast_mutex_unlock(&sub->lock); ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner); return -1; } sub->owner = newchan; ast_mutex_unlock(&sub->lock); return 0;}static int mgcp_senddigit_begin(struct ast_channel *ast, char digit){ struct mgcp_subchannel *sub = ast->tech_pvt; struct mgcp_endpoint *p = sub->parent; int res = 0; ast_mutex_lock(&sub->lock); if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) { ast_log(LOG_DEBUG, "Sending DTMF using inband/hybrid\n"); res = -1; /* Let asterisk play inband indications */ } else if (p->dtmfmode & MGCP_DTMF_RFC2833) { ast_log(LOG_DEBUG, "Sending DTMF using RFC2833"); ast_rtp_senddigit_begin(sub->rtp, digit); } else { ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode); } ast_mutex_unlock(&sub->lock); return res;}static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration){ struct mgcp_subchannel *sub = ast->tech_pvt; struct mgcp_endpoint *p = sub->parent; int res = 0; char tmp[4]; ast_mutex_lock(&sub->lock); if (p->dtmfmode & MGCP_DTMF_INBAND || p->dtmfmode & MGCP_DTMF_HYBRID) { ast_log(LOG_DEBUG, "Stopping DTMF using inband/hybrid\n"); res = -1; /* Tell Asterisk to stop inband indications */ } else if (p->dtmfmode & MGCP_DTMF_RFC2833) { ast_log(LOG_DEBUG, "Stopping DTMF using RFC2833\n"); tmp[0] = 'D'; tmp[1] = '/'; tmp[2] = digit; tmp[3] = '\0'; transmit_notify_request(sub, tmp); ast_rtp_senddigit_end(sub->rtp, digit); } else { ast_log(LOG_ERROR, "Don't know about DTMF_MODE %d\n", p->dtmfmode); } ast_mutex_unlock(&sub->lock); return res;}/*! * \brief mgcp_devicestate: channel callback for device status monitoring * \param data tech/resource name of MGCP device to query * * Callback for device state management in channel subsystem * to obtain device status (up/down) of a specific MGCP endpoint * * \return device status result (from devicestate.h) AST_DEVICE_INVALID (not available) or AST_DEVICE_UNKNOWN (available but unknown state) */static int mgcp_devicestate(void *data){ struct mgcp_gateway *g; struct mgcp_endpoint *e = NULL; char *tmp, *endpt, *gw; int ret = AST_DEVICE_INVALID; endpt = ast_strdupa(data); if ((tmp = strchr(endpt, '@'))) { *tmp++ = '\0'; gw = tmp; } else goto error; ast_mutex_lock(&gatelock); g = gateways; while (g) { if (strcasecmp(g->name, gw) == 0) { e = g->endpoints; break; } g = g->next; } if (!e) goto error; while (e) { if (strcasecmp(e->name, endpt) == 0) break; e = e->next; } if (!e) goto error; /* * As long as the gateway/endpoint is valid, we'll * assume that the device is available and its state * can be tracked. */ ret = AST_DEVICE_UNKNOWN;error: ast_mutex_unlock(&gatelock); return ret;}static char *control2str(int ind) { switch (ind) { case AST_CONTROL_HANGUP: return "Other end has hungup"; case AST_CONTROL_RING: return "Local ring"; case AST_CONTROL_RINGING: return "Remote end is ringing"; case AST_CONTROL_ANSWER: return "Remote end has answered"; case AST_CONTROL_BUSY: return "Remote end is busy"; case AST_CONTROL_TAKEOFFHOOK: return "Make it go off hook"; case AST_CONTROL_OFFHOOK: return "Line is off hook"; case AST_CONTROL_CONGESTION: return "Congestion (circuits busy)"; case AST_CONTROL_FLASH: return "Flash hook"; case AST_CONTROL_WINK: return "Wink"; case AST_CONTROL_OPTION: return "Set a low-level option"; case AST_CONTROL_RADIO_KEY: return "Key Radio"; case AST_CONTROL_RADIO_UNKEY: return "Un-Key Radio"; } return "UNKNOWN";}static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen){ struct mgcp_subchannel *sub = ast->tech_pvt; int res = 0; if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_3 "MGCP asked to indicate %d '%s' condition on channel %s\n", ind, control2str(ind), ast->name); } ast_mutex_lock(&sub->lock); switch(ind) { case AST_CONTROL_RINGING:#ifdef DLINK_BUGGY_FIRMWARE transmit_notify_request(sub, "rt");#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -