📄 chan_local.c
字号:
ast_mutex_unlock(&p->lock); return res;}static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration){ struct local_pvt *p = ast->tech_pvt; int res = -1; struct ast_frame f = { AST_FRAME_DTMF_END, }; int isoutbound; if (!p) return -1; ast_mutex_lock(&p->lock); isoutbound = IS_OUTBOUND(ast, p); f.subclass = digit; f.len = duration; if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) ast_mutex_unlock(&p->lock); return res;}static int local_sendtext(struct ast_channel *ast, const char *text){ struct local_pvt *p = ast->tech_pvt; int res = -1; struct ast_frame f = { AST_FRAME_TEXT, }; int isoutbound; if (!p) return -1; ast_mutex_lock(&p->lock); isoutbound = IS_OUTBOUND(ast, p); f.data = (char *) text; f.datalen = strlen(text) + 1; if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) ast_mutex_unlock(&p->lock); return res;}static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen){ struct local_pvt *p = ast->tech_pvt; int res = -1; struct ast_frame f = { AST_FRAME_HTML, }; int isoutbound; if (!p) return -1; ast_mutex_lock(&p->lock); isoutbound = IS_OUTBOUND(ast, p); f.subclass = subclass; f.data = (char *)data; f.datalen = datalen; if (!(res = local_queue_frame(p, isoutbound, &f, ast, 0))) ast_mutex_unlock(&p->lock); return res;}/*! \brief Initiate new call, part of PBX interface * dest is the dial string */static int local_call(struct ast_channel *ast, char *dest, int timeout){ struct local_pvt *p = ast->tech_pvt; int res; struct ast_var_t *varptr = NULL, *new; size_t len, namelen; if (!p) return -1; ast_mutex_lock(&p->lock); /* * Note that cid_num and cid_name aren't passed in the ast_channel_alloc * call, so it's done here instead. */ p->chan->cid.cid_num = ast_strdup(p->owner->cid.cid_num); p->chan->cid.cid_name = ast_strdup(p->owner->cid.cid_name); p->chan->cid.cid_rdnis = ast_strdup(p->owner->cid.cid_rdnis); p->chan->cid.cid_ani = ast_strdup(p->owner->cid.cid_ani); p->chan->cid.cid_pres = p->owner->cid.cid_pres; ast_string_field_set(p->chan, language, p->owner->language); ast_string_field_set(p->chan, accountcode, p->owner->accountcode); ast_cdr_update(p->chan); p->chan->cdrflags = p->owner->cdrflags; /* copy the channel variables from the incoming channel to the outgoing channel */ /* Note that due to certain assumptions, they MUST be in the same order */ AST_LIST_TRAVERSE(&p->owner->varshead, varptr, entries) { namelen = strlen(varptr->name); len = sizeof(struct ast_var_t) + namelen + strlen(varptr->value) + 2; if ((new = ast_calloc(1, len))) { memcpy(new, varptr, len); new->value = &(new->name[0]) + namelen + 1; AST_LIST_INSERT_TAIL(&p->chan->varshead, new, entries); } } ast_channel_datastore_inherit(p->owner, p->chan); /* Start switch on sub channel */ if (!(res = ast_pbx_start(p->chan))) ast_set_flag(p, LOCAL_LAUNCHED_PBX); ast_mutex_unlock(&p->lock); return res;}/*! \brief Hangup a call through the local proxy channel */static int local_hangup(struct ast_channel *ast){ struct local_pvt *p = ast->tech_pvt; int isoutbound; struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP }; struct ast_channel *ochan = NULL; int glaredetect = 0, res = 0; if (!p) return -1; while (ast_mutex_trylock(&p->lock)) { ast_channel_unlock(ast); usleep(1); ast_channel_lock(ast); } isoutbound = IS_OUTBOUND(ast, p); if (isoutbound) { const char *status = pbx_builtin_getvar_helper(p->chan, "DIALSTATUS"); if ((status) && (p->owner)) { /* Deadlock avoidance */ while (p->owner && ast_channel_trylock(p->owner)) { ast_mutex_unlock(&p->lock); if (ast) { ast_channel_unlock(ast); } usleep(1); if (ast) { ast_channel_lock(ast); } ast_mutex_lock(&p->lock); } if (p->owner) { pbx_builtin_setvar_helper(p->owner, "CHANLOCALSTATUS", status); ast_channel_unlock(p->owner); } } p->chan = NULL; ast_clear_flag(p, LOCAL_LAUNCHED_PBX); ast_module_user_remove(p->u_chan); } else { p->owner = NULL; ast_module_user_remove(p->u_owner); if (p->chan) { ast_queue_hangup(p->chan); } } ast->tech_pvt = NULL; if (!p->owner && !p->chan) { /* Okay, done with the private part now, too. */ glaredetect = ast_test_flag(p, LOCAL_GLARE_DETECT); /* If we have a queue holding, don't actually destroy p yet, but let local_queue do it. */ if (glaredetect) ast_set_flag(p, LOCAL_CANCEL_QUEUE); ast_mutex_unlock(&p->lock); /* Remove from list */ AST_LIST_LOCK(&locals); AST_LIST_REMOVE(&locals, p, list); AST_LIST_UNLOCK(&locals); /* Grab / release lock just in case */ ast_mutex_lock(&p->lock); ast_mutex_unlock(&p->lock); /* And destroy */ if (!glaredetect) { p = local_pvt_destroy(p); } return 0; } if (p->chan && !ast_test_flag(p, LOCAL_LAUNCHED_PBX)) /* Need to actually hangup since there is no PBX */ ochan = p->chan; else res = local_queue_frame(p, isoutbound, &f, NULL, 1); if (!res) ast_mutex_unlock(&p->lock); if (ochan) ast_hangup(ochan); return 0;}/*! \brief Create a call structure */static struct local_pvt *local_alloc(const char *data, int format){ struct local_pvt *tmp = NULL; char *c = NULL, *opts = NULL; if (!(tmp = ast_calloc(1, sizeof(*tmp)))) return NULL; /* Initialize private structure information */ ast_mutex_init(&tmp->lock); ast_copy_string(tmp->exten, data, sizeof(tmp->exten)); /* Look for options */ if ((opts = strchr(tmp->exten, '/'))) { *opts++ = '\0'; if (strchr(opts, 'n')) ast_set_flag(tmp, LOCAL_NO_OPTIMIZATION); } /* Look for a context */ if ((c = strchr(tmp->exten, '@'))) *c++ = '\0'; ast_copy_string(tmp->context, c ? c : "default", sizeof(tmp->context)); tmp->reqformat = format; if (!ast_exists_extension(NULL, tmp->context, tmp->exten, 1, NULL)) { ast_log(LOG_NOTICE, "No such extension/context %s@%s creating local channel\n", tmp->exten, tmp->context); tmp = local_pvt_destroy(tmp); } else { /* Add to list */ AST_LIST_LOCK(&locals); AST_LIST_INSERT_HEAD(&locals, tmp, list); AST_LIST_UNLOCK(&locals); } return tmp;}/*! \brief Start new local channel */static struct ast_channel *local_new(struct local_pvt *p, int state){ struct ast_channel *tmp = NULL, *tmp2 = NULL; int randnum = ast_random() & 0xffff, fmt = 0; const char *t; int ama; /* Allocate two new Asterisk channels */ /* safe accountcode */ if (p->owner && p->owner->accountcode) t = p->owner->accountcode; else t = ""; if (p->owner) ama = p->owner->amaflags; else ama = 0; if (!(tmp = ast_channel_alloc(1, state, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,1", p->exten, p->context, randnum)) || !(tmp2 = ast_channel_alloc(1, AST_STATE_RING, 0, 0, t, p->exten, p->context, ama, "Local/%s@%s-%04x,2", p->exten, p->context, randnum))) { if (tmp) ast_channel_free(tmp); if (tmp2) ast_channel_free(tmp2); ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n"); return NULL; } tmp2->tech = tmp->tech = &local_tech; tmp->nativeformats = p->reqformat; tmp2->nativeformats = p->reqformat; /* Determine our read/write format and set it on each channel */ fmt = ast_best_codec(p->reqformat); tmp->writeformat = fmt; tmp2->writeformat = fmt; tmp->rawwriteformat = fmt; tmp2->rawwriteformat = fmt; tmp->readformat = fmt; tmp2->readformat = fmt; tmp->rawreadformat = fmt; tmp2->rawreadformat = fmt; tmp->tech_pvt = p; tmp2->tech_pvt = p; p->owner = tmp; p->chan = tmp2; p->u_owner = ast_module_user_add(p->owner); p->u_chan = ast_module_user_add(p->chan); ast_copy_string(tmp->context, p->context, sizeof(tmp->context)); ast_copy_string(tmp2->context, p->context, sizeof(tmp2->context)); ast_copy_string(tmp2->exten, p->exten, sizeof(tmp->exten)); tmp->priority = 1; tmp2->priority = 1; return tmp;}/*! \brief Part of PBX interface */static struct ast_channel *local_request(const char *type, int format, void *data, int *cause){ struct local_pvt *p = NULL; struct ast_channel *chan = NULL; /* Allocate a new private structure and then Asterisk channel */ if ((p = local_alloc(data, format))) { if (!(chan = local_new(p, AST_STATE_DOWN))) { AST_LIST_LOCK(&locals); AST_LIST_REMOVE(&locals, p, list); AST_LIST_UNLOCK(&locals); p = local_pvt_destroy(p); } } return chan;}/*! \brief CLI command "local show channels" */static int locals_show(int fd, int argc, char **argv){ struct local_pvt *p = NULL; if (argc != 3) return RESULT_SHOWUSAGE; AST_LIST_LOCK(&locals); if (!AST_LIST_EMPTY(&locals)) { AST_LIST_TRAVERSE(&locals, p, list) { ast_mutex_lock(&p->lock); ast_cli(fd, "%s -- %s@%s\n", p->owner ? p->owner->name : "<unowned>", p->exten, p->context); ast_mutex_unlock(&p->lock); } } else ast_cli(fd, "No local channels in use\n"); AST_LIST_UNLOCK(&locals); return RESULT_SUCCESS;}static char show_locals_usage[] = "Usage: local show channels\n"" Provides summary information on active local proxy channels.\n";static struct ast_cli_entry cli_local[] = { { { "local", "show", "channels", NULL }, locals_show, "List status of local channels", show_locals_usage },};/*! \brief Load module into PBX, register channel */static int load_module(void){ /* Make sure we can register our channel type */ if (ast_channel_register(&local_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'Local'\n"); return -1; } ast_cli_register_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); return 0;}/*! \brief Unload the local proxy channel from Asterisk */static int unload_module(void){ struct local_pvt *p = NULL; /* First, take us out of the channel loop */ ast_cli_unregister_multiple(cli_local, sizeof(cli_local) / sizeof(struct ast_cli_entry)); ast_channel_unregister(&local_tech); if (!AST_LIST_LOCK(&locals)) { /* Hangup all interfaces if they have an owner */ AST_LIST_TRAVERSE(&locals, p, list) { if (p->owner) ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); } AST_LIST_UNLOCK(&locals); } else { ast_log(LOG_WARNING, "Unable to lock the monitor\n"); return -1; } return 0;}AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Local Proxy Channel (Note: used internally by other modules)");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -