Author: bebuild Date: Fri Dec 19 15:52:43 2014 New Revision: 429892 URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=429892 Log: ari: Add support for specifying an originator channel when originating.
If an originator channel is specified when originating a channel the linked ID of it will be applied to the newly originated outgoing channel. This allows an association to be made between the two so it is known that the originator has dialed the originated channel. ASTERISK-24552 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/4243/ ........ Merged revisions 429153 from http://svn.asterisk.org/svn/asterisk/branches/13 Modified: certified/branches/13.1/ (props changed) certified/branches/13.1/CHANGES certified/branches/13.1/res/ari/resource_channels.c certified/branches/13.1/res/ari/resource_channels.h certified/branches/13.1/res/res_ari_channels.c certified/branches/13.1/rest-api/api-docs/channels.json Propchange: certified/branches/13.1/ ------------------------------------------------------------------------------ --- branch-13-merged (original) +++ branch-13-merged Fri Dec 19 15:52:43 2014 @@ -1,1 +1,1 @@ -/branches/13:429175,429196,429206,429407,429409,429433,429477,429497,429540,429571,429739,429761,429829 +/branches/13:429153,429175,429196,429206,429407,429409,429433,429477,429497,429540,429571,429739,429761,429829 Modified: certified/branches/13.1/CHANGES URL: http://svnview.digium.com/svn/asterisk/certified/branches/13.1/CHANGES?view=diff&rev=429892&r1=429891&r2=429892 ============================================================================== --- certified/branches/13.1/CHANGES (original) +++ certified/branches/13.1/CHANGES Fri Dec 19 15:52:43 2014 @@ -7,6 +7,17 @@ === and the other UPGRADE files for older releases. === ============================================================================== +------------------------------------------------------------------------------ +--- Functionality changes from Asterisk 13.1.0 to Asterisk 13.1-cert1 -------- +------------------------------------------------------------------------------ + +ARI +------------------ + * The Originate operation now takes in an originator channel. The linked ID of + this originator channel is applied to the newly originated outgoing channel. + If using CEL this allows an association to be established between the two so + it can be recognized that the originator is dialing the originated channel. + ------------------------------------------------------------------------------ --- Functionality changes from Asterisk 13.0.0 to Asterisk 13.1.0 ------------ ------------------------------------------------------------------------------ Modified: certified/branches/13.1/res/ari/resource_channels.c URL: http://svnview.digium.com/svn/asterisk/certified/branches/13.1/res/ari/resource_channels.c?view=diff&rev=429892&r1=429891&r2=429892 ============================================================================== --- certified/branches/13.1/res/ari/resource_channels.c (original) +++ certified/branches/13.1/res/ari/resource_channels.c Fri Dec 19 15:52:43 2014 @@ -44,6 +44,7 @@ #include "asterisk/causes.h" #include "asterisk/format_cache.h" #include "asterisk/core_local.h" +#include "asterisk/dial.h" #include "resource_channels.h" #include <limits.h> @@ -723,6 +724,69 @@ ast_ari_response_ok(response, ast_json_ref(json)); } +/*! \brief Structure used for origination */ +struct ari_origination { + /*! \brief Dialplan context */ + char context[AST_MAX_CONTEXT]; + /*! \brief Dialplan extension */ + char exten[AST_MAX_EXTENSION]; + /*! \brief Dialplan priority */ + int priority; + /*! \brief Application data to pass to Stasis application */ + char appdata[0]; +}; + +/*! \brief Thread which dials and executes upon answer */ +static void *ari_originate_dial(void *data) +{ + struct ast_dial *dial = data; + struct ari_origination *origination = ast_dial_get_user_data(dial); + enum ast_dial_result res; + + res = ast_dial_run(dial, NULL, 0); + if (res != AST_DIAL_RESULT_ANSWERED) { + goto end; + } + + if (!ast_strlen_zero(origination->appdata)) { + struct ast_app *app = pbx_findapp("Stasis"); + + if (app) { + ast_verb(4, "Launching Stasis(%s) on %s\n", origination->appdata, + ast_channel_name(ast_dial_answered(dial))); + pbx_exec(ast_dial_answered(dial), app, origination->appdata); + } else { + ast_log(LOG_WARNING, "No such application 'Stasis'\n"); + } + } else { + struct ast_channel *answered = ast_dial_answered(dial); + + if (!ast_strlen_zero(origination->context)) { + ast_channel_context_set(answered, origination->context); + } + + if (!ast_strlen_zero(origination->exten)) { + ast_channel_exten_set(answered, origination->exten); + } + + if (origination->priority > 0) { + ast_channel_priority_set(answered, origination->priority); + } + + if (ast_pbx_run(answered)) { + ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(answered)); + } else { + /* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */ + ast_dial_answered_steal(dial); + } + } + +end: + ast_dial_destroy(dial); + ast_free(origination); + return NULL; +} + static void ari_channels_handle_originate_with_id(const char *args_endpoint, const char *args_extension, const char *args_context, @@ -734,23 +798,27 @@ struct ast_variable *variables, const char *args_channel_id, const char *args_other_channel_id, + const char *args_originator, struct ast_ari_response *response) { char *dialtech; char dialdevice[AST_CHANNEL_NAME]; + struct ast_dial *dial; char *caller_id = NULL; char *cid_num = NULL; char *cid_name = NULL; - int timeout = 30000; RAII_VAR(struct ast_format_cap *, cap, ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup); char *stuff; + struct ast_channel *other = NULL; struct ast_channel *chan; RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup); struct ast_assigned_ids assignedids = { .uniqueid = args_channel_id, .uniqueid2 = args_other_channel_id, }; + struct ari_origination *origination; + pthread_t thread; if (!cap) { ast_ari_response_alloc_failed(response); @@ -783,10 +851,64 @@ return; } + if (!ast_strlen_zero(args_app)) { + RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free); + + if (!appdata) { + ast_ari_response_alloc_failed(response); + return; + } + + ast_str_set(&appdata, 0, "%s", args_app); + if (!ast_strlen_zero(args_app_args)) { + ast_str_append(&appdata, 0, ",%s", args_app_args); + } + + origination = ast_calloc(1, sizeof(*origination) + ast_str_size(appdata) + 1); + if (!origination) { + ast_ari_response_alloc_failed(response); + return; + } + + strcpy(origination->appdata, ast_str_buffer(appdata)); + } else if (!ast_strlen_zero(args_extension)) { + origination = ast_calloc(1, sizeof(*origination) + 1); + if (!origination) { + ast_ari_response_alloc_failed(response); + return; + } + + ast_copy_string(origination->context, S_OR(args_context, "default"), sizeof(origination->context)); + ast_copy_string(origination->exten, args_extension, sizeof(origination->exten)); + origination->priority = args_priority ? args_priority : 1; + origination->appdata[0] = '\0'; + } else { + ast_ari_response_error(response, 400, "Bad Request", + "Application or extension must be specified"); + return; + } + + dial = ast_dial_create(); + if (!dial) { + ast_ari_response_alloc_failed(response); + ast_free(origination); + return; + } + ast_dial_set_user_data(dial, origination); + + if (ast_dial_append(dial, dialtech, dialdevice, &assignedids)) { + ast_ari_response_alloc_failed(response); + ast_dial_destroy(dial); + ast_free(origination); + return; + } + if (args_timeout > 0) { - timeout = args_timeout * 1000; + ast_dial_set_global_timeout(dial, args_timeout * 1000); } else if (args_timeout == -1) { - timeout = -1; + ast_dial_set_global_timeout(dial, -1); + } else { + ast_dial_set_global_timeout(dial, 30000); } if (!ast_strlen_zero(args_caller_id)) { @@ -798,37 +920,68 @@ } } - if (!ast_strlen_zero(args_app)) { - const char *app = "Stasis"; - - RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free); - - if (!appdata) { - ast_ari_response_alloc_failed(response); + if (!ast_strlen_zero(args_originator)) { + other = ast_channel_get_by_name(args_originator); + if (!other) { + ast_ari_response_error( + response, 400, "Bad Request", + "Provided originator channel was not found"); + ast_dial_destroy(dial); + ast_free(origination); return; } - - ast_str_set(&appdata, 0, "%s", args_app); - if (!ast_strlen_zero(args_app_args)) { - ast_str_append(&appdata, 0, ",%s", args_app_args); - } - - /* originate a channel, putting it into an application */ - if (ast_pbx_outgoing_app(dialtech, cap, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, variables, NULL, &chan, &assignedids)) { - ast_ari_response_alloc_failed(response); - return; - } - } else if (!ast_strlen_zero(args_extension)) { - /* originate a channel, sending it to an extension */ - if (ast_pbx_outgoing_exten(dialtech, cap, dialdevice, timeout, S_OR(args_context, "default"), args_extension, args_priority ? args_priority : 1, NULL, 0, cid_num, cid_name, variables, NULL, &chan, 0, &assignedids)) { - ast_ari_response_alloc_failed(response); - return; - } - } else { - ast_ari_response_error(response, 400, "Bad Request", - "Application or extension must be specified"); - return; - } + } + + if (ast_dial_prerun(dial, other, cap)) { + ast_ari_response_alloc_failed(response); + ast_dial_destroy(dial); + ast_free(origination); + ast_channel_cleanup(other); + return; + } + + ast_channel_cleanup(other); + + chan = ast_dial_get_channel(dial, 0); + if (!chan) { + ast_ari_response_alloc_failed(response); + ast_dial_destroy(dial); + ast_free(origination); + return; + } + + if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) { + struct ast_party_connected_line connected; + + /* + * It seems strange to set the CallerID on an outgoing call leg + * to whom we are calling, but this function's callers are doing + * various Originate methods. This call leg goes to the local + * user. Once the called party answers, the dialplan needs to + * be able to access the CallerID from the CALLERID function as + * if the called party had placed this call. + */ + ast_set_callerid(chan, cid_num, cid_name, cid_num); + + ast_party_connected_line_set_init(&connected, ast_channel_connected(chan)); + if (!ast_strlen_zero(cid_num)) { + connected.id.number.valid = 1; + connected.id.number.str = (char *) cid_num; + connected.id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + } + if (!ast_strlen_zero(cid_name)) { + connected.id.name.valid = 1; + connected.id.name.str = (char *) cid_name; + connected.id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED; + } + ast_channel_set_connected_line(chan, &connected, NULL); + } + + ast_channel_lock(chan); + if (variables) { + ast_set_variables(chan, variables); + } + ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED); if (!ast_strlen_zero(args_app)) { struct ast_channel *local_peer; @@ -846,8 +999,21 @@ snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan)); ast_channel_unlock(chan); - ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL)); + /* Before starting the async dial bump the ref in case the dial quickly goes away and takes + * the reference with it + */ + ast_channel_ref(chan); + + if (ast_pthread_create_detached(&thread, NULL, ari_originate_dial, dial)) { + ast_ari_response_alloc_failed(response); + ast_dial_destroy(dial); + ast_free(origination); + } else { + ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL)); + } + ast_channel_unref(chan); + return; } void ast_ari_channels_originate_with_id(struct ast_variable *headers, @@ -883,6 +1049,7 @@ variables, args->channel_id, args->other_channel_id, + args->originator, response); } @@ -919,6 +1086,7 @@ variables, args->channel_id, args->other_channel_id, + args->originator, response); } Modified: certified/branches/13.1/res/ari/resource_channels.h URL: http://svnview.digium.com/svn/asterisk/certified/branches/13.1/res/ari/resource_channels.h?view=diff&rev=429892&r1=429891&r2=429892 ============================================================================== --- certified/branches/13.1/res/ari/resource_channels.h (original) +++ certified/branches/13.1/res/ari/resource_channels.h Fri Dec 19 15:52:43 2014 @@ -74,6 +74,8 @@ const char *channel_id; /*! The unique id to assign the second channel when using local channels. */ const char *other_channel_id; + /*! The unique id of the channel which is originating this one. */ + const char *originator; }; /*! * \brief Body parsing function for /channels. @@ -133,6 +135,8 @@ struct ast_json *variables; /*! The unique id to assign the second channel when using local channels. */ const char *other_channel_id; + /*! The unique id of the channel which is originating this one. */ + const char *originator; }; /*! * \brief Body parsing function for /channels/{channelId}. Modified: certified/branches/13.1/res/res_ari_channels.c URL: http://svnview.digium.com/svn/asterisk/certified/branches/13.1/res/res_ari_channels.c?view=diff&rev=429892&r1=429891&r2=429892 ============================================================================== --- certified/branches/13.1/res/res_ari_channels.c (original) +++ certified/branches/13.1/res/res_ari_channels.c Fri Dec 19 15:52:43 2014 @@ -148,6 +148,10 @@ if (field) { args->other_channel_id = ast_json_string_get(field); } + field = ast_json_object_get(body, "originator"); + if (field) { + args->originator = ast_json_string_get(field); + } return 0; } @@ -201,6 +205,9 @@ } else if (strcmp(i->name, "otherChannelId") == 0) { args.other_channel_id = (i->value); + } else + if (strcmp(i->name, "originator") == 0) { + args.originator = (i->value); } else {} } @@ -354,6 +361,10 @@ if (field) { args->other_channel_id = ast_json_string_get(field); } + field = ast_json_object_get(body, "originator"); + if (field) { + args->originator = ast_json_string_get(field); + } return 0; } @@ -404,6 +415,9 @@ } else if (strcmp(i->name, "otherChannelId") == 0) { args.other_channel_id = (i->value); + } else + if (strcmp(i->name, "originator") == 0) { + args.originator = (i->value); } else {} } Modified: certified/branches/13.1/rest-api/api-docs/channels.json URL: http://svnview.digium.com/svn/asterisk/certified/branches/13.1/rest-api/api-docs/channels.json?view=diff&rev=429892&r1=429891&r2=429892 ============================================================================== --- certified/branches/13.1/rest-api/api-docs/channels.json (original) +++ certified/branches/13.1/rest-api/api-docs/channels.json Fri Dec 19 15:52:43 2014 @@ -112,6 +112,14 @@ "required": false, "allowMultiple": false, "dataType": "string" + }, + { + "name": "originator", + "description": "The unique id of the channel which is originating this one.", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" } ], "errorResponses": [ @@ -240,6 +248,14 @@ { "name": "otherChannelId", "description": "The unique id to assign the second channel when using local channels.", + "paramType": "query", + "required": false, + "allowMultiple": false, + "dataType": "string" + }, + { + "name": "originator", + "description": "The unique id of the channel which is originating this one.", "paramType": "query", "required": false, "allowMultiple": false, -- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- svn-commits mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/svn-commits
