diff options
-rw-r--r-- | CHANGES | 7 | ||||
-rw-r--r-- | apps/app_originate.c | 2 | ||||
-rw-r--r-- | include/asterisk/channel.h | 1 | ||||
-rw-r--r-- | include/asterisk/pbx.h | 2 | ||||
-rw-r--r-- | main/channel.c | 8 | ||||
-rw-r--r-- | main/manager.c | 14 | ||||
-rw-r--r-- | main/pbx.c | 20 | ||||
-rw-r--r-- | pbx/pbx_spool.c | 7 | ||||
-rw-r--r-- | res/res_clioriginate.c | 2 |
9 files changed, 52 insertions, 11 deletions
@@ -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; |