[asterisk-commits] file: trunk r429154 - in /trunk: ./ res/ res/ari/ rest-api/api-docs/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Dec 9 09:45:23 CST 2014


Author: file
Date: Tue Dec  9 09:45:19 2014
New Revision: 429154

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=429154
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:
    trunk/   (props changed)
    trunk/CHANGES
    trunk/res/ari/resource_channels.c
    trunk/res/ari/resource_channels.h
    trunk/res/res_ari_channels.c
    trunk/rest-api/api-docs/channels.json

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-13-merged' - no diff available.

Modified: trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/trunk/CHANGES?view=diff&rev=429154&r1=429153&r2=429154
==============================================================================
--- trunk/CHANGES (original)
+++ trunk/CHANGES Tue Dec  9 09:45:19 2014
@@ -74,6 +74,17 @@
  * Added preferchannelclass=no option to prefer the application-passed class
    over the channel-set musicclass. This allows separate hold-music from
    application (e.g. Queue or Dial) specified music.
+
+------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.1.0 to Asterisk 13.2.0 ------------
+------------------------------------------------------------------------------
+
+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: trunk/res/ari/resource_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/resource_channels.c?view=diff&rev=429154&r1=429153&r2=429154
==============================================================================
--- trunk/res/ari/resource_channels.c (original)
+++ trunk/res/ari/resource_channels.c Tue Dec  9 09:45:19 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: trunk/res/ari/resource_channels.h
URL: http://svnview.digium.com/svn/asterisk/trunk/res/ari/resource_channels.h?view=diff&rev=429154&r1=429153&r2=429154
==============================================================================
--- trunk/res/ari/resource_channels.h (original)
+++ trunk/res/ari/resource_channels.h Tue Dec  9 09:45:19 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: trunk/res/res_ari_channels.c
URL: http://svnview.digium.com/svn/asterisk/trunk/res/res_ari_channels.c?view=diff&rev=429154&r1=429153&r2=429154
==============================================================================
--- trunk/res/res_ari_channels.c (original)
+++ trunk/res/res_ari_channels.c Tue Dec  9 09:45:19 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: trunk/rest-api/api-docs/channels.json
URL: http://svnview.digium.com/svn/asterisk/trunk/rest-api/api-docs/channels.json?view=diff&rev=429154&r1=429153&r2=429154
==============================================================================
--- trunk/rest-api/api-docs/channels.json (original)
+++ trunk/rest-api/api-docs/channels.json Tue Dec  9 09:45:19 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,




More information about the asterisk-commits mailing list