summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES7
-rw-r--r--apps/app_originate.c2
-rw-r--r--include/asterisk/channel.h1
-rw-r--r--include/asterisk/pbx.h2
-rw-r--r--main/channel.c8
-rw-r--r--main/manager.c14
-rw-r--r--main/pbx.c20
-rw-r--r--pbx/pbx_spool.c7
-rw-r--r--res/res_clioriginate.c2
9 files changed, 52 insertions, 11 deletions
diff --git a/CHANGES b/CHANGES
index 9dbd911a9..d19cfeb28 100644
--- a/CHANGES
+++ b/CHANGES
@@ -425,6 +425,9 @@ Core
* Asterisk can now use a system-provided NetBSD editline library (libedit) if it
is available.
+ * Call files now support the "early_media" option to connect with an outgoing
+ extension when early media is received.
+
AGI
------------------
* A new channel variable, AGIEXITONHANGUP, has been added which allows
@@ -438,6 +441,10 @@ AGI
AMI (Asterisk Manager Interface)
------------------
+ * The originate action now has an option "EarlyMedia" that enables the
+ call to bridge when we get early media in the call. Previously,
+ early media was disregarded always when originating calls using AMI.
+
* Added setvar= option to manager accounts (much like sip.conf)
* Originate now generates an error response if the extension given is not found
diff --git a/apps/app_originate.c b/apps/app_originate.c
index 4756b68b6..8eb8ba329 100644
--- a/apps/app_originate.c
+++ b/apps/app_originate.c
@@ -178,7 +178,7 @@ static int originate_exec(struct ast_channel *chan, const char *data)
ast_pbx_outgoing_exten(chantech, cap_slin, chandata,
timeout * 1000, args.arg1, exten, priority, &outgoing_status, 0, NULL,
- NULL, NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL, 0);
} else if (!strcasecmp(args.type, "app")) {
ast_debug(1, "Originating call to '%s/%s' and connecting them to %s(%s)\n",
chantech, chandata, args.arg1, S_OR(args.arg2, ""));
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index e8785cfe3..c9d13187c 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -907,6 +907,7 @@ struct outgoing_helper {
const char *context;
const char *exten;
int priority;
+ int connect_on_early_media; /* If set, treat session progress as answer */
const char *cid_num;
const char *cid_name;
const char *account;
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index bea7e5ebf..b1e820983 100644
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -1010,7 +1010,7 @@ int ast_async_goto_by_name(const char *chan, const char *context, const char *ex
/*! Synchronously or asynchronously make an outbound call and send it to a
particular extension */
-int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel);
+int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel, int early_media);
/*! Synchronously or asynchronously make an outbound call and send it to a
particular application with given extension */
diff --git a/main/channel.c b/main/channel.c
index f7e9d631a..d5f1d31c1 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -5620,8 +5620,14 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
ast_channel_hangupcause_hash_set(chan, f->data.ptr, f->datalen);
break;
- /* Ignore these */
case AST_CONTROL_PROGRESS:
+ if (oh && oh->connect_on_early_media) {
+ *outstate = f->subclass.integer;
+ timeout = 0; /* trick to force exit from the while() */
+ break;
+ }
+ /* Fallthrough */
+ /* Ignore these */
case AST_CONTROL_PROCEEDING:
case AST_CONTROL_HOLD:
case AST_CONTROL_UNHOLD:
diff --git a/main/manager.c b/main/manager.c
index 12aa851c7..e1bf19f68 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -465,6 +465,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<parameter name="Account">
<para>Account code.</para>
</parameter>
+ <parameter name="EarlyMedia">
+ <para>Set to <literal>true</literal> to force call bridge on early media..</para>
+ </parameter>
<parameter name="Async">
<para>Set to <literal>true</literal> for fast origination.</para>
</parameter>
@@ -3915,6 +3918,7 @@ action_command_cleanup:
struct fast_originate_helper {
int timeout;
struct ast_format_cap *cap; /*!< Codecs used for a call */
+ int early_media;
AST_DECLARE_STRING_FIELDS (
AST_STRING_FIELD(tech);
/*! data can contain a channel name, extension number, username, password, etc. */
@@ -3966,7 +3970,7 @@ static void *fast_originate(void *data)
in->timeout, in->context, in->exten, in->priority, &reason, 1,
S_OR(in->cid_num, NULL),
S_OR(in->cid_name, NULL),
- in->vars, in->account, &chan);
+ in->vars, in->account, &chan, in->early_media);
}
/* Any vars memory was passed to the ast_pbx_outgoing_xxx() calls. */
in->vars = NULL;
@@ -4245,6 +4249,7 @@ static int action_originate(struct mansession *s, const struct message *m)
const char *async = astman_get_header(m, "Async");
const char *id = astman_get_header(m, "ActionID");
const char *codecs = astman_get_header(m, "Codecs");
+ const char *early_media = astman_get_header(m, "Earlymedia");
struct ast_variable *vars = NULL;
char *tech, *data;
char *l = NULL, *n = NULL;
@@ -4257,6 +4262,7 @@ static int action_originate(struct mansession *s, const struct message *m)
struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
struct ast_format tmp_fmt;
pthread_t th;
+ int bridge_early = 0;
if (!cap) {
astman_send_error(s, m, "Internal Error. Memory allocation failure.");
@@ -4359,6 +4365,9 @@ static int action_originate(struct mansession *s, const struct message *m)
}
}
+ /* For originate async - we can bridge in early media stage */
+ bridge_early = ast_true(early_media);
+
if (ast_true(async)) {
struct fast_originate_helper *fast;
@@ -4384,6 +4393,7 @@ static int action_originate(struct mansession *s, const struct message *m)
fast->cap = cap;
cap = NULL; /* transfered originate helper the capabilities structure. It is now responsible for freeing it. */
fast->timeout = to;
+ fast->early_media = bridge_early;
fast->priority = pi;
if (ast_pthread_create_detached(&th, NULL, fast_originate, fast)) {
destroy_fast_originate_helper(fast);
@@ -4397,7 +4407,7 @@ static int action_originate(struct mansession *s, const struct message *m)
/* Any vars memory was passed to ast_pbx_outgoing_app(). */
} else {
if (exten && context && pi) {
- res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL);
+ res = ast_pbx_outgoing_exten(tech, cap, data, to, context, exten, pi, &reason, 1, l, n, vars, account, NULL, bridge_early);
/* Any vars memory was passed to ast_pbx_outgoing_exten(). */
} else {
astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'");
diff --git a/main/pbx.c b/main/pbx.c
index ef04d6644..3195da3bc 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -9559,6 +9559,7 @@ struct async_stat {
int timeout;
char app[AST_MAX_EXTENSION];
char appdata[1024];
+ int early_media; /* Connect the bridge if early media arrives, don't wait for answer */
};
static void *async_wait(void *data)
@@ -9569,6 +9570,7 @@ static void *async_wait(void *data)
int res;
struct ast_frame *f;
struct ast_app *app;
+ int have_early_media = 0;
if (chan) {
struct ast_callid *callid = ast_channel_callid(chan);
@@ -9593,10 +9595,18 @@ static void *async_wait(void *data)
ast_frfree(f);
break;
}
+ if (as->early_media && f->subclass.integer == AST_CONTROL_PROGRESS) {
+ have_early_media = 1;
+ ast_frfree(f);
+ break;
+ }
}
ast_frfree(f);
}
- if (ast_channel_state(chan) == AST_STATE_UP) {
+ if (ast_channel_state(chan) == AST_STATE_UP || have_early_media) {
+ if (have_early_media) {
+ ast_debug(2, "Activating pbx since we have early media \n");
+ }
if (!ast_strlen_zero(as->app)) {
app = pbx_findapp(as->app);
if (app) {
@@ -9657,7 +9667,7 @@ static int ast_pbx_outgoing_cdr_failed(void)
return 0; /* success */
}
-int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
+int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel, int early_media)
{
struct ast_channel *chan;
struct async_stat *as;
@@ -9666,6 +9676,8 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
int res = -1, cdr_res = -1;
struct outgoing_helper oh;
+ oh.connect_on_early_media = early_media;
+
callid_created = ast_callid_threadstorage_auto(&callid);
if (synchronous) {
@@ -9695,9 +9707,9 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
}
}
- if (ast_channel_state(chan) == AST_STATE_UP) {
+ if (ast_channel_state(chan) == AST_STATE_UP || (early_media && *reason == AST_CONTROL_PROGRESS)) {
res = 0;
- ast_verb(4, "Channel %s was answered.\n", ast_channel_name(chan));
+ ast_verb(4, "Channel %s %s\n", ast_channel_name(chan), ast_channel_state(chan) == AST_STATE_UP ? "was answered" : "got early media");
if (synchronous > 1) {
if (channel)
diff --git a/pbx/pbx_spool.c b/pbx/pbx_spool.c
index 43bac620e..d061f356b 100644
--- a/pbx/pbx_spool.c
+++ b/pbx/pbx_spool.c
@@ -67,6 +67,8 @@ enum {
SPOOL_FLAG_ALWAYS_DELETE = (1 << 0),
/* Don't unlink the call file after processing, move in qdonedir */
SPOOL_FLAG_ARCHIVE = (1 << 1),
+ /* Connect the channel with the outgoing extension once early media is received */
+ SPOOL_FLAG_EARLY_MEDIA = (1 << 2),
};
static char qdir[255];
@@ -253,6 +255,8 @@ static int apply_outgoing(struct outgoing *o, const char *fn, FILE *f)
ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE);
} else if (!strcasecmp(buf, "archive")) {
ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE);
+ } else if (!strcasecmp(buf, "early_media")) {
+ ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_EARLY_MEDIA);
} else {
ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn);
}
@@ -357,7 +361,8 @@ static void *attempt_thread(void *data)
ast_verb(3, "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries);
res = ast_pbx_outgoing_exten(o->tech, o->capabilities, o->dest,
o->waittime * 1000, o->context, o->exten, o->priority, &reason,
- 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL);
+ 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL,
+ ast_test_flag(&o->options, SPOOL_FLAG_EARLY_MEDIA));
o->vars = NULL;
}
if (res) {
diff --git a/res/res_clioriginate.c b/res/res_clioriginate.c
index 7ac5605b9..42030d798 100644
--- a/res/res_clioriginate.c
+++ b/res/res_clioriginate.c
@@ -119,7 +119,7 @@ static char *orig_exten(int fd, const char *chan, const char *data)
return CLI_FAILURE;
}
ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
- ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL);
+ ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0);
cap = ast_format_cap_destroy(cap);
return CLI_SUCCESS;