Compare commits

...

8 Commits

Author SHA1 Message Date
Alexey Khabulyak
b0421fc87c app_dial.c: Moved channel lock to prevent deadlock
It's reproducible with pbx_lua, not regular dialplan.

deadlock description:
1. asterisk locks a channel
2. calls function onedigit_goto
3. calls ast_goto_if_exists funciton
4. checks ast_exists_extension -> pbx_extension_helper
5. pbx_extension_helper calls pbx_find_extension
6. Then asterisk starts autoservice in a new thread
7. autoservice run tries to lock the channel again

Because our channel is locked already, autoservice can't lock.
Autoservice can't lock -> autoservice stop is waiting forever.
onedigit_goto waits for autoservice stop.

Resolves: https://github.com/asterisk/asterisk/issues/1335
2025-08-11 14:37:22 +00:00
Mike Bradeen
dce107234a res_pjsip_diversion: resolve race condition between Diversion header processing and redirect
Based on the firing order of the PJSIP call-backs on a redirect, it was possible for
the Diversion header to not be included in the outgoing 181 response to the UAC and
the INVITE to the UAS.

This change moves the Diversion header processing to an earlier PJSIP callback while also
preventing the corresponding update that can cause a duplicate 181 response when processing
the header at that time.

Resolves: #1349
2025-08-11 13:58:11 +00:00
Allan Nathanson
31571a5079 file.c: with "sounds_search_custom_dir = yes", search "custom" directory
With `sounds_search_custom_dir = yes`, we are supposed to search for sounds
in the `AST_DATA_DIR/sounds/custom` directory before searching the normal
directories.  Unfortunately, a recent change
(https://github.com/asterisk/asterisk/pull/1172) had a typo resulting in
the "custom" directory not being searched.  This change restores this
expected behavior.

Resolves: #1353
2025-08-11 13:53:22 +00:00
Sperl Viktor
c1f24b74d7 cel: Add STREAM_BEGIN, STREAM_END and DTMF event types.
Fixes: #1280

UserNote: Enabling the tracking of the
STREAM_BEGIN and the STREAM_END event
types in cel.conf will log media files and
music on hold played to each channel.
The STREAM_BEGIN event's extra field will
contain a JSON with the file details (path,
format and language), or the class name, in
case of music on hold is played. The DTMF
event's extra field will contain a JSON with
the digit and the duration in milliseconds.
2025-08-11 13:52:30 +00:00
Naveen Albert
613d645d04 func_dialplan: Remove deprecated/redundant function.
Remove VALID_EXTEN, which was deprecated/superseded by DIALPLAN_EXISTS
in Asterisk 11 (commit 8017b65bb9),
as DIALPLAN_EXISTS does the same thing and is more flexible.

Resolves: #1347

UpgradeNote: The deprecated VALID_EXTEN function has been removed.
Use DIALPLAN_EXISTS instead.
2025-08-11 12:32:01 +00:00
Naveen Albert
c8f844a900 logger.c: Remove deprecated/redundant configuration option.
Remove the deprecated 'rotatetimestamp' config option, as this
was deprecated by 'rotatestrategy' in 1.6 by commit
f5a14167f3.

Resolves: #1345

UpgradeNote: The deprecated rotatetimestamp option has been removed.
Use rotatestrategy instead.
2025-08-11 12:23:42 +00:00
Naveen Albert
5c3cd44563 cli.c: Remove deprecated and redundant CLI command.
The "no debug channel" command has been deprecated since
1.6 (commit 691363656f),
as it is replaced by "core set debug channel", which also
supports tab-completion on channels. Remove the redundant
command.

Resolves: #1343

UpgradeNote: The deprecated "no debug channel" command has
now been removed; use "core set debug channel" instead.
2025-08-11 12:22:45 +00:00
Naveen Albert
aca74d100c app_queue: Remove redundant/deprecated function.
QUEUE_MEMBER_COUNT has been deprecated since at least 1.6,
for fully duplicating functionality available in the
QUEUE_MEMBER function; remove it now.

Resolves: #1341

UpgradeNote: The deprecated QUEUE_MEMBER_COUNT function
has been removed; use QUEUE_MEMBER(<queue>,logged) instead.
2025-08-11 12:22:28 +00:00
12 changed files with 157 additions and 244 deletions

View File

@@ -1808,7 +1808,10 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) {
const char *context;
ast_channel_lock(in);
context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
if ((context = pbx_builtin_getvar_helper(in, "EXITCONTEXT"))) {
context = ast_strdupa(context);
}
ast_channel_unlock(in);
if (onedigit_goto(in, context, (char) f->subclass.integer, 1)) {
ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
*to_answer = 0;
@@ -1817,14 +1820,12 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
pa->canceled = 1;
publish_dial_end_event(in, out_chans, NULL, pa->status);
ast_frfree(f);
ast_channel_unlock(in);
if (is_cc_recall) {
ast_cc_completed(in, "CC completed, but the caller used DTMF to exit");
}
SCOPE_EXIT_RTN_VALUE(NULL, "%s: Caller pressed %c to end call\n",
ast_channel_name(in), f->subclass.integer);
}
ast_channel_unlock(in);
}
if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&

View File

@@ -310,7 +310,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -366,7 +365,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -409,7 +407,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -459,7 +456,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -506,7 +502,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -543,7 +538,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -624,7 +618,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -692,38 +685,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
<ref type="function">QUEUE_MEMBER_LIST</ref>
<ref type="function">QUEUE_MEMBER_PENALTY</ref>
</see-also>
</function>
<function name="QUEUE_MEMBER_COUNT" language="en_US">
<since>
<version>1.4.0</version>
</since>
<synopsis>
Count number of members answering a queue.
</synopsis>
<syntax>
<parameter name="queuename" required="true" />
</syntax>
<description>
<para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
<warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
</description>
<see-also>
<ref type="application">Queue</ref>
<ref type="application">QueueLog</ref>
<ref type="application">AddQueueMember</ref>
<ref type="application">RemoveQueueMember</ref>
<ref type="application">PauseQueueMember</ref>
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -753,7 +714,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -785,7 +745,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
<ref type="function">QUEUE_MEMBER_LIST</ref>
@@ -814,7 +773,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -844,7 +802,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -876,7 +833,6 @@
<ref type="application">UnpauseQueueMember</ref>
<ref type="function">QUEUE_VARIABLES</ref>
<ref type="function">QUEUE_MEMBER</ref>
<ref type="function">QUEUE_MEMBER_COUNT</ref>
<ref type="function">QUEUE_EXISTS</ref>
<ref type="function">QUEUE_GET_CHANNEL</ref>
<ref type="function">QUEUE_WAITING_COUNT</ref>
@@ -9400,51 +9356,6 @@ static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, c
return 0;
}
/*!
* \brief Get the total number of members in a specific queue (Deprecated)
* \retval number of members
* \retval -1 on error
*/
static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
int count = 0;
struct member *m;
struct call_queue *q;
struct ao2_iterator mem_iter;
static int depflag = 1;
if (depflag) {
depflag = 0;
ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
}
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
return -1;
}
if ((q = find_load_queue_rt_friendly(data))) {
ao2_lock(q);
mem_iter = ao2_iterator_init(q->members, 0);
while ((m = ao2_iterator_next(&mem_iter))) {
/* Count the agents who are logged in and presently answering calls */
if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
count++;
}
ao2_ref(m, -1);
}
ao2_iterator_destroy(&mem_iter);
ao2_unlock(q);
queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
} else {
ast_log(LOG_WARNING, "queue %s was not found\n", data);
}
snprintf(buf, len, "%d", count);
return 0;
}
/*! \brief Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue */
static int queue_function_queuegetchannel(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
@@ -9694,11 +9605,6 @@ static struct ast_custom_function queuemembercount_function = {
.write = queue_function_mem_write,
};
static struct ast_custom_function queuemembercount_dep = {
.name = "QUEUE_MEMBER_COUNT",
.read = queue_function_qac_dep,
};
static struct ast_custom_function queuegetchannel_function = {
.name = "QUEUE_GET_CHANNEL",
.read = queue_function_queuegetchannel,
@@ -11996,7 +11902,6 @@ static int unload_module(void)
ast_custom_function_unregister(&queueexists_function);
ast_custom_function_unregister(&queuevar_function);
ast_custom_function_unregister(&queuemembercount_function);
ast_custom_function_unregister(&queuemembercount_dep);
ast_custom_function_unregister(&queuememberlist_function);
ast_custom_function_unregister(&queuegetchannel_function);
ast_custom_function_unregister(&queuewaitingcount_function);
@@ -12109,7 +12014,6 @@ static int load_module(void)
err |= ast_custom_function_register(&queuevar_function);
err |= ast_custom_function_register(&queueexists_function);
err |= ast_custom_function_register(&queuemembercount_function);
err |= ast_custom_function_register(&queuemembercount_dep);
err |= ast_custom_function_register(&queuememberlist_function);
err |= ast_custom_function_register(&queuegetchannel_function);
err |= ast_custom_function_register(&queuewaitingcount_function);

View File

@@ -59,6 +59,12 @@ apps=dial,park
; USER_DEFINED -- Triggered from the dialplan, and has a name given by the
; user
; LOCAL_OPTIMIZE -- A local channel pair is optimizing away.
; STREAM_BEGIN -- A stream started playing: it can be a standalone sound file
; playing back, or a music-on-hold class started
; STREAM_END -- A playing stream ended
; DTMF -- A DTMF digit was processed: these events are dispatched at the
; end, when the button is released and the duration is present in
; the extra field
;
; Default value: none
; (Track no events)

View File

@@ -52,28 +52,6 @@
<para>This function returns <literal>1</literal> if the target exits. Otherwise, it returns <literal>0</literal>.</para>
</description>
</function>
<function name="VALID_EXTEN" language="en_US">
<since>
<version>11.0.0</version>
</since>
<synopsis>
Determine whether an extension exists or not.
</synopsis>
<syntax>
<parameter name="context">
<para>Defaults to the current context</para>
</parameter>
<parameter name="extension" required="true" />
<parameter name="priority">
<para>Priority defaults to <literal>1</literal>.</para>
</parameter>
</syntax>
<description>
<para>Returns a true value if the indicated <replaceable>context</replaceable>,
<replaceable>extension</replaceable>, and <replaceable>priority</replaceable> exist.</para>
<warning><para>This function has been deprecated in favor of the <literal>DIALPLAN_EXISTS()</literal> function</para></warning>
</description>
</function>
***/
static int isexten_function_read(struct ast_channel *chan, const char *cmd, char *data,
@@ -131,70 +109,20 @@ static int isexten_function_read(struct ast_channel *chan, const char *cmd, char
return 0;
}
static int acf_isexten_exec(struct ast_channel *chan, const char *cmd, char *parse, char *buffer, size_t buflen)
{
int priority_int;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(context);
AST_APP_ARG(extension);
AST_APP_ARG(priority);
);
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
return -1;
}
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.context)) {
args.context = ast_strdupa(ast_channel_context(chan));
}
if (ast_strlen_zero(args.extension)) {
ast_log(LOG_WARNING, "Syntax: VALID_EXTEN([<context>],<extension>[,<priority>]) - missing argument <extension>!\n");
return -1;
}
if (ast_strlen_zero(args.priority)) {
priority_int = 1;
} else {
priority_int = atoi(args.priority);
}
if (ast_exists_extension(chan, args.context, args.extension, priority_int,
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
ast_copy_string(buffer, "1", buflen);
} else {
ast_copy_string(buffer, "0", buflen);
}
return 0;
}
static struct ast_custom_function isexten_function = {
.name = "DIALPLAN_EXISTS",
.read = isexten_function_read,
.read_max = 2,
};
static struct ast_custom_function acf_isexten = {
.name = "VALID_EXTEN",
.read = acf_isexten_exec,
};
static int unload_module(void)
{
int res = ast_custom_function_unregister(&isexten_function);
res |= ast_custom_function_unregister(&acf_isexten);
return res;
return ast_custom_function_unregister(&isexten_function);
}
static int load_module(void)
{
int res = ast_custom_function_register(&isexten_function);
res |= ast_custom_function_register(&acf_isexten);
return res;
return ast_custom_function_register(&isexten_function);
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Dialplan Context/Extension/Priority Checking Functions",

View File

@@ -77,6 +77,12 @@ enum ast_cel_event_type {
AST_CEL_LOCAL_OPTIMIZE = 17,
/*! \brief A local channel optimization has begun */
AST_CEL_LOCAL_OPTIMIZE_BEGIN = 18,
/*! \brief A stream started */
AST_CEL_STREAM_BEGIN = 19,
/*! \brief A stream ended */
AST_CEL_STREAM_END = 20,
/*! \brief A DTMF digit was processed */
AST_CEL_DTMF = 21,
};
/*!

View File

@@ -118,6 +118,9 @@
<enum name="LINKEDID_END"/>
<enum name="LOCAL_OPTIMIZE"/>
<enum name="LOCAL_OPTIMIZE_BEGIN"/>
<enum name="STREAM_BEGIN"/>
<enum name="STREAM_END"/>
<enum name="DTMF"/>
</enumlist>
</description>
</configOption>
@@ -338,6 +341,9 @@ static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
[AST_CEL_LINKEDID_END] = "LINKEDID_END",
[AST_CEL_LOCAL_OPTIMIZE] = "LOCAL_OPTIMIZE",
[AST_CEL_LOCAL_OPTIMIZE_BEGIN] = "LOCAL_OPTIMIZE_BEGIN",
[AST_CEL_STREAM_BEGIN] = "STREAM_BEGIN",
[AST_CEL_STREAM_END] = "STREAM_END",
[AST_CEL_DTMF] = "DTMF",
};
struct cel_backend {
@@ -849,12 +855,8 @@ int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *
r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
r->event_name = ast_cel_get_type_name(r->event_type);
if (r->event_type == AST_CEL_USER_DEFINED) {
r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
} else {
r->user_defined_name = "";
}
r->user_defined_name= S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME), "");
r->caller_id_name = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
r->caller_id_num = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
r->caller_id_ani = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
@@ -1282,6 +1284,8 @@ static void cel_generic_cb(
switch (event_type) {
case AST_CEL_USER_DEFINED:
case AST_CEL_DTMF:
case AST_CEL_STREAM_BEGIN:
{
const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
struct ast_json *extra = ast_json_object_get(event_details, "extra");
@@ -1289,6 +1293,13 @@ static void cel_generic_cb(
event, extra, NULL);
break;
}
case AST_CEL_STREAM_END:
{
const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
cel_report_event(obj->snapshot, event_type, stasis_message_timestamp(message),
event, NULL, NULL);
break;
}
default:
ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
break;

View File

@@ -42,6 +42,7 @@
#include "asterisk/mod_format.h"
#include "asterisk/sched.h"
#include "asterisk/channel.h"
#include "asterisk/cel.h"
#include "asterisk/musiconhold.h"
#include "asterisk/say.h"
#include "asterisk/file.h"
@@ -3338,34 +3339,45 @@ static const char *dtmf_direction_to_string(enum DtmfDirection direction)
static void send_dtmf_begin_event(struct ast_channel *chan,
enum DtmfDirection direction, const char digit)
{
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
RAII_VAR(struct ast_json *, channel_blob, NULL, ast_json_unref);
char digit_str[] = { digit, '\0' };
blob = ast_json_pack("{ s: s, s: s }",
channel_blob = ast_json_pack("{ s: s, s: s }",
"digit", digit_str,
"direction", dtmf_direction_to_string(direction));
if (!blob) {
return;
}
ast_channel_publish_blob(chan, ast_channel_dtmf_begin_type(), blob);
if (channel_blob) {
ast_channel_publish_blob(chan, ast_channel_dtmf_begin_type(), channel_blob);
}
}
static void send_dtmf_end_event(struct ast_channel *chan,
enum DtmfDirection direction, const char digit, long duration_ms)
{
RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
RAII_VAR(struct ast_json *, channel_blob, NULL, ast_json_unref);
RAII_VAR(struct ast_json *, cel_blob, NULL, ast_json_unref);
char digit_str[] = { digit, '\0' };
blob = ast_json_pack("{ s: s, s: s, s: I }",
channel_blob = ast_json_pack("{ s: s, s: s, s: I }",
"digit", digit_str,
"direction", dtmf_direction_to_string(direction),
"duration_ms", (ast_json_int_t)duration_ms);
if (!blob) {
return;
if (channel_blob) {
ast_channel_publish_blob(chan, ast_channel_dtmf_end_type(), channel_blob);
}
ast_channel_publish_blob(chan, ast_channel_dtmf_end_type(), blob);
cel_blob = ast_json_pack("{ s: s, s: { s: s, s: I }}",
"event", dtmf_direction_to_string(direction),
"extra",
"digit", digit_str,
"duration_ms", (ast_json_int_t)duration_ms);
if (cel_blob) {
ast_cel_publish_event(chan, AST_CEL_DTMF, cel_blob);
} else {
ast_log(LOG_WARNING, "Unable to build extradata for DTMF CEL event on channel %s", ast_channel_name(chan));
}
}
static void send_flash_event(struct ast_channel *chan)

View File

@@ -1538,10 +1538,7 @@ static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, str
return NULL;
}
if (cmd == (CLI_HANDLER + 1000)) {
/* called from handle_nodebugchan_deprecated */
args.is_off = 1;
} else if (a->argc == e->args + 2) {
if (a->argc == e->args + 2) {
/* 'core set debug channel {all|chan_id}' */
if (!strcasecmp(a->argv[e->args + 1], "off"))
args.is_off = 1;
@@ -1615,33 +1612,6 @@ static char *handle_debug_category(struct ast_cli_entry *e, int cmd, struct ast_
return CLI_SUCCESS;
}
static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
char *res;
switch (cmd) {
case CLI_INIT:
e->command = "no debug channel";
return NULL;
case CLI_HANDLER:
/* exit out of switch statement */
break;
default:
return NULL;
}
if (a->argc != e->args + 1)
return CLI_SHOWUSAGE;
/* add a 'magic' value to the CLI_HANDLER command so that
* handle_core_set_debug_channel() will act as if 'off'
* had been specified as part of the command
*/
res = handle_core_set_debug_channel(e, CLI_HANDLER + 1000, a);
return res;
}
static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_channel *chan;
@@ -2056,7 +2026,6 @@ static struct ast_cli_entry cli_cli[] = {
};
static struct ast_cli_entry cli_channels_cli[] = {
AST_CLI_DEFINE(handle_nodebugchan_deprecated, "Disable debugging on channel(s)"),
AST_CLI_DEFINE(handle_chanlist, "Display information on channels"),
AST_CLI_DEFINE(handle_showcalls, "Display information on calls"),
AST_CLI_DEFINE(handle_showchan, "Display information on a specific channel"),

View File

@@ -39,6 +39,7 @@
#include "asterisk/mod_format.h"
#include "asterisk/cli.h"
#include "asterisk/channel.h"
#include "asterisk/cel.h"
#include "asterisk/sched.h"
#include "asterisk/translate.h"
#include "asterisk/utils.h"
@@ -221,15 +222,25 @@ int ast_file_fdtemp(const char *path, char **filename, const char *template_name
int ast_stopstream(struct ast_channel *tmp)
{
struct ast_json * cel_event = NULL;
ast_channel_lock(tmp);
/* Stop a running stream if there is one */
if (ast_channel_stream(tmp)) {
ast_closestream(ast_channel_stream(tmp));
ast_channel_stream_set(tmp, NULL);
cel_event = ast_json_pack("{ s: s }", "event", "FILE_STREAM_END");
if (cel_event) {
ast_cel_publish_event(tmp, AST_CEL_STREAM_END, cel_event);
}
if (ast_channel_oldwriteformat(tmp) && ast_set_write_format(tmp, ast_channel_oldwriteformat(tmp)))
ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_format_get_name(ast_channel_oldwriteformat(tmp)));
}
ast_json_unref(cel_event);
/* Stop the video stream too */
if (ast_channel_vstream(tmp) != NULL) {
ast_closestream(ast_channel_vstream(tmp));
@@ -1301,6 +1312,7 @@ int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj
int ast_streamfile(struct ast_channel *chan, const char *filename,
const char *preflang)
{
struct ast_json * cel_event = NULL;
struct ast_filestream *fs = NULL;
struct ast_filestream *vfs = NULL;
off_t pos;
@@ -1315,7 +1327,7 @@ int ast_streamfile(struct ast_channel *chan, const char *filename,
if (ast_opt_sounds_search_custom && !is_absolute_path(filename)) {
memset(custom_filename, 0, sizeof(custom_filename));
snprintf(custom_filename, sizeof(custom_filename), "custom/%s", filename);
fs = openstream_internal(chan, filename, preflang, 0, 1); /* open stream, do not warn for missing files */
fs = openstream_internal(chan, custom_filename, preflang, 0, 1); /* open stream, do not warn for missing files */
if (fs) {
tmp_filename = custom_filename;
ast_debug(3, "Found file %s in custom directory\n", filename);
@@ -1367,6 +1379,20 @@ int ast_streamfile(struct ast_channel *chan, const char *filename,
if (!res && vfs)
res = ast_playstream(vfs);
cel_event = ast_json_pack("{ s: s, s: {s: s, s: s, s: s}}",
"event", "FILE_STREAM_BEGIN",
"extra",
"sound", tmp_filename,
"format", ast_format_get_name(ast_channel_writeformat(chan)),
"language", preflang ? preflang : "default"
);
if (cel_event) {
ast_cel_publish_event(chan, AST_CEL_STREAM_BEGIN, cel_event);
} else {
ast_log(LOG_WARNING, "Unable to build extradata for sound file STREAM_BEGIN event on channel %s", ast_channel_name(chan));
}
ast_json_unref(cel_event);
if (VERBOSITY_ATLEAST(3)) {
ast_channel_lock(chan);
ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), tmp_filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default");

View File

@@ -840,11 +840,6 @@ static int init_logger_chain(const char *altconf)
} else {
fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
}
} else {
if ((s = ast_variable_retrieve(cfg, "general", "rotatetimestamp"))) {
rotatestrategy = ast_true(s) ? TIMESTAMP : SEQUENTIAL;
fprintf(stderr, "rotatetimestamp option has been deprecated. Please use rotatestrategy instead.\n");
}
}
if ((s = ast_variable_retrieve(cfg, "general", "logger_queue_limit"))) {
if (sscanf(s, "%30d", &logger_queue_limit) != 1) {

View File

@@ -54,6 +54,7 @@
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/cel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
@@ -253,10 +254,23 @@ static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
{
struct stasis_message *message;
struct ast_json *json_object;
struct ast_json *cel_event;
ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n",
moh_class_name, ast_channel_name(chan));
cel_event = ast_json_pack("{ s: s, s: {s: s }}",
"event", "MOH_STREAM_BEGIN",
"extra",
"class", moh_class_name
);
if (cel_event) {
ast_cel_publish_event(chan, AST_CEL_STREAM_BEGIN, cel_event);
} else {
ast_log(LOG_WARNING, "Unable to build extradata for music on hold STREAM_BEGIN event on channel %s", ast_channel_name(chan));
}
ast_json_unref(cel_event);
json_object = ast_json_pack("{s: s}", "class", moh_class_name);
if (!json_object) {
return;
@@ -277,9 +291,16 @@ static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
static void moh_post_stop(struct ast_channel *chan)
{
struct stasis_message *message;
struct ast_json *cel_event;
ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
cel_event = ast_json_pack("{ s: s }", "event", "MOH_STREAM_END");
if (cel_event) {
ast_cel_publish_event(chan, AST_CEL_STREAM_END, cel_event);
}
ast_json_unref(cel_event);
message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
ast_channel_moh_stop_type(), NULL);
if (message) {

View File

@@ -39,6 +39,14 @@ static const pj_str_t diversion_name = { "Diversion", 9 };
static const pj_str_t history_info_name = { "History-Info", 12 };
static pj_str_t HISTINFO_SUPPORTED_NAME = { "histinfo", 8 };
/*
* Should we queue a frame with the updated redirecting information.
*/
typedef enum {
PJSIP_DIVERSION_NOSEND_UPDATE = 0,
PJSIP_DIVERSION_SEND_UPDATE = 1,
} pjsip_diversion_send_update;
/*!
* \internal
* \brief Determine if the given string is a SIP token.
@@ -385,7 +393,8 @@ static void set_redirecting_reason(pjsip_fromto_hdr *from_info, pjsip_name_addr
static void set_redirecting(struct ast_sip_session *session,
pjsip_fromto_hdr *from_info,
pjsip_name_addr *to_info)
pjsip_name_addr *to_info,
pjsip_diversion_send_update send_update)
{
struct ast_party_redirecting data;
struct ast_set_party_redirecting update;
@@ -417,8 +426,8 @@ static void set_redirecting(struct ast_sip_session *session,
++data.count;
ast_channel_set_redirecting(session->channel, &data, &update);
/* Only queue an indication if it was due to a response */
if (session->inv_session->role == PJSIP_ROLE_UAC) {
/* Only queue an indication if it was due to a response received pre media*/
if (session->inv_session->role == PJSIP_ROLE_UAC && send_update) {
ast_channel_queue_redirecting_update(session->channel, &data, &update);
}
ast_party_redirecting_free(&data);
@@ -430,7 +439,7 @@ static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_
if (hdr) {
set_redirecting(session, hdr, (pjsip_name_addr*)
PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri);
PJSIP_MSG_TO_HDR(rdata->msg_info.msg)->uri, PJSIP_DIVERSION_SEND_UPDATE);
} else {
pjsip_fromto_hdr *history_info_to;
pjsip_fromto_hdr *history_info_from;
@@ -440,14 +449,14 @@ static int diversion_incoming_request(struct ast_sip_session *session, pjsip_rx_
/* If History-Info is present, then it will also include the original
redirected-from in addition to the redirected-to */
history_info_from = get_history_info_header(rdata, 1);
set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri);
set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri, PJSIP_DIVERSION_SEND_UPDATE);
}
}
return 0;
}
static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata, pjsip_diversion_send_update send_update)
{
static const pj_str_t contact_name = { "Contact", 7 };
static const pj_str_t contact_name_s = { "m", 1 };
@@ -472,7 +481,7 @@ static void diversion_incoming_response(struct ast_sip_session *session, pjsip_r
/* If History-Info is present, then it will also include the original
redirected-from in addition to the redirected-to */
history_info_from = get_history_info_header(rdata, 1);
set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri);
set_redirecting(session, history_info_from, (pjsip_name_addr*)history_info_to->uri, send_update);
return;
}
if (!div_hdr && !session->id.number.valid) {
@@ -484,16 +493,30 @@ static void diversion_incoming_response(struct ast_sip_session *session, pjsip_r
if (status.code == 302) {
/* With 302, Contact indicates the final destination and possibly Diversion indicates the hop before */
contact_hdr = pjsip_msg_find_hdr_by_names(rdata->msg_info.msg, &contact_name, &contact_name_s, NULL);
set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri :
(pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri);
(pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri, send_update);
} else {
/* With 181, Diversion is non-standard, but if present indicates the new final destination, and To indicating the original */
set_redirecting(session, PJSIP_MSG_TO_HDR(rdata->msg_info.msg),
div_hdr ? (pjsip_name_addr*)div_hdr->uri : NULL);
div_hdr ? (pjsip_name_addr*)div_hdr->uri : NULL, send_update);
}
}
static void diversion_incoming_response_media(struct ast_sip_session *session, pjsip_rx_data *rdata)
{
/* Trigger an update if the event is triggered by the PJSIP AST_SIP_SESSION_BEFORE_MEDIA callback */
diversion_incoming_response(session, rdata, PJSIP_DIVERSION_SEND_UPDATE);
return;
}
static void diversion_incoming_response_redirecting(struct ast_sip_session *session, pjsip_rx_data *rdata)
{
/* Don't trigger an update if the event is triggered by the PJSIP AST_SIP_SESSION_REDIRECTING callback
otherwise, we will send a duplicate 181 to the UAC */
diversion_incoming_response(session, rdata, PJSIP_DIVERSION_NOSEND_UPDATE);
return;
}
/*!
* \internal
* \brief Adds diversion header information to an outbound SIP message
@@ -688,20 +711,29 @@ static void diversion_outgoing_response(struct ast_sip_session *session, pjsip_t
/* add to 302 and 181 */
if (PJSIP_IS_STATUS_IN_CLASS(status.code, 300) || (status.code == 181)) {
get_redirecting_add_diversion(session, tdata);
}
get_redirecting_add_diversion(session, tdata);
}
}
static struct ast_sip_session_supplement diversion_supplement = {
static struct ast_sip_session_supplement diversion_supplement_media = {
.method = "INVITE",
/* this supplement needs to be called after caller id
and after the channel has been created */
.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
.incoming_response = diversion_incoming_response_media,
.response_priority = AST_SIP_SESSION_BEFORE_MEDIA,
};
static struct ast_sip_session_supplement diversion_supplement_redirecting = {
.method = "INVITE",
/* this supplement needs to be called after caller id
and after the channel has been created */
.priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
.incoming_request = diversion_incoming_request,
.incoming_response = diversion_incoming_response,
.incoming_response = diversion_incoming_response_redirecting,
.outgoing_request = diversion_outgoing_request,
.outgoing_response = diversion_outgoing_response,
.response_priority = AST_SIP_SESSION_BEFORE_MEDIA,
.response_priority = AST_SIP_SESSION_BEFORE_REDIRECTING,
};
static int load_module(void)
@@ -709,13 +741,15 @@ static int load_module(void)
/* Because we are passing static memory to pjsip, we need to make sure it
* stays valid while we potentially have active sessions */
ast_module_shutdown_ref(ast_module_info->self);
ast_sip_session_register_supplement(&diversion_supplement);
ast_sip_session_register_supplement(&diversion_supplement_media);
ast_sip_session_register_supplement(&diversion_supplement_redirecting);
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
ast_sip_session_unregister_supplement(&diversion_supplement);
ast_sip_session_unregister_supplement(&diversion_supplement_media);
ast_sip_session_unregister_supplement(&diversion_supplement_redirecting);
return 0;
}