- #define ORIGINATE_SYNTAX "<call url> <exten>|&<application_name>(<app_args>) [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>]"
- SWITCH_STANDARD_API(originate_function)
- {
- switch_channel_t *caller_channel;
- switch_core_session_t *caller_session = NULL;
- char *mycmd = NULL, *argv[10] = { 0 };
- int i = 0, x, argc = 0;
- char *aleg, *exten, *dp, *context, *cid_name, *cid_num;
- uint32_t timeout = 60;
- switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
- switch_status_t status = SWITCH_STATUS_SUCCESS;
- if (zstr(cmd)) {
- stream->write_function(stream, "-USAGE: %s\n", ORIGINATE_SYNTAX);
- return SWITCH_STATUS_SUCCESS;
- }
- /* log warning if part of ongoing session, as we'll block the session */
- if (session){
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Originate can take 60 seconds to complete, and blocks the existing session. Do not confuse with a lockup.\n");
- }
- mycmd = strdup(cmd);
- switch_assert(mycmd);
- argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
- if (argc < 2 || argc > 7) {
- stream->write_function(stream, "-USAGE: %s\n", ORIGINATE_SYNTAX);
- goto done;
- }
- for (x = 0; x < argc && argv[x]; x++) {
- if (!strcasecmp(argv[x], "undef")) {
- argv[x] = NULL;
- }
- }
- aleg = argv[i++];
- exten = argv[i++];
- dp = argv[i++];
- context = argv[i++];
- cid_name = argv[i++];
- cid_num = argv[i++];
- switch_assert(exten);
- if (!dp) {
- dp = "XML";
- }
- if (!context) {
- context = "default";
- }
- if (argv[6]) {
- timeout = atoi(argv[6]);
- }
- if (switch_ivr_originate(NULL, &caller_session, &cause, aleg, timeout, NULL, cid_name, cid_num, NULL, NULL, SOF_NONE, NULL, NULL) != SWITCH_STATUS_SUCCESS
- || !caller_session) {
- stream->write_function(stream, "-ERR %s\n", switch_channel_cause2str(cause));
- goto done;
- }
- caller_channel = switch_core_session_get_channel(caller_session);
- if (*exten == '&' && *(exten + 1)) {
- switch_caller_extension_t *extension = NULL;
- char *app_name = switch_core_session_strdup(caller_session, (exten + 1));
- char *arg = NULL, *e;
- if ((e = strchr(app_name, ')'))) {
- *e = '\0';
- }
- if ((arg = strchr(app_name, '('))) {
- *arg++ = '\0';
- }
- if ((extension = switch_caller_extension_new(caller_session, app_name, arg)) == 0) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n");
- abort();
- }
- switch_caller_extension_add_application(caller_session, extension, app_name, arg);
- switch_channel_set_caller_extension(caller_channel, extension);
- switch_channel_set_state(caller_channel, CS_EXECUTE);
- } else {
- switch_ivr_session_transfer(caller_session, exten, dp, context);
- }
- stream->write_function(stream, "+OK %s\n", switch_core_session_get_uuid(caller_session));
- switch_core_session_rwunlock(caller_session);
- done:
- switch_safe_free(mycmd);
- return status;
- }
- originate_function
- => switch_ivr_originate
- => switch_core_session_outgoing_channel
- => endpoint_interface->io_routines->outgoing_channel
- => switch_core_session_thread_launch
该函数用于发起具体的呼叫。
switch_ivr_originate函数定义:
- SWITCH_DECLARE(switch_status_t) switch_ivr_originate(
- switch_core_session_t *session,
- switch_core_session_t **bleg,
- switch_call_cause_t *cause,
- const char *bridgeto,
- uint32_t timelimit_sec,
- const switch_state_handler_table_t *table,
- const char *cid_name_override,
- const char *cid_num_override,
- switch_caller_profile_t *caller_profile_override,
- switch_event_t *ovars, switch_originate_flag_t flags,
- switch_call_cause_t *cancel_cause,
- switch_dial_handle_t *dh)
参数解释:
- session : 发起originate的channel,即 caller_channel , aleg
- bleg : originate所在的leg,会在该函数赋值
- cause : 失败原因,会在该函数赋值
- bridgeto : bleg的呼叫字符串,只读
- timelimit_sec :originate超时时间
- table : bleg的状态机回调函数
- cid_name_override : origination_caller_id_name,用于设置主叫名称
- cid_num_override : origination_caller_id_number,用于设置主叫号码
- caller_profile_override :主叫的profile
- ovars : originate导出的通道变量(从aleg)
- flags : originate flag 参数,一般为 SOF_NONE
- cancel_cause :originate取消原因
- dh : dial handle,功能类似呼叫字符串,可以设置多条leg同时originate
如果outgoing_channel执行成功,会发送SWITCH_EVENT_CHANNEL_OUTGOING事件;并且该channel会设置上CF_ORIGINATING标识位。
- if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_OUTGOING) == SWITCH_STATUS_SUCCESS) {
- switch_channel_event_set_data(peer_channel, event);
- switch_event_fire(&event);
- }
使用 switch_core_session_thread_launch 启动线程创建session :
- if (!switch_core_session_running(oglobals.originate_status[i].peer_session)) {
- if (oglobals.originate_status[i].per_channel_delay_start) {
- switch_channel_set_flag(oglobals.originate_status[i].peer_channel, CF_BLOCK_STATE);
- }
- switch_core_session_thread_launch(oglobals.originate_status[i].peer_session);
- }
bridge app入口(mod_dptools.c):