Add transfer support to CEL
This adds CEL support for blind and attended transfers and call pickup. During the course of adding this functionality I noticed that CONF_ENTER, CONF_EXIT, and BRIDGE_TO_CONF events are particularly useless without a bridge identifier, so I added that as well. This adds tests for blind transfers, several types of attended transfers, and call pickup. The extra field in CEL records now consists of a JSON blob whose fields are defined on a per-event basis. Review: https://reviewboard.asterisk.org/r/2658/ (closes issue ASTERISK-21565) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@394858 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
4e15046cf6
commit
684c83b29b
17
CHANGES
17
CHANGES
|
@ -320,6 +320,23 @@ CDR (Call Detail Records)
|
||||||
included in the resulting CDR. If both parties have the same variable, only
|
included in the resulting CDR. If both parties have the same variable, only
|
||||||
the Party A value is provided.
|
the Party A value is provided.
|
||||||
|
|
||||||
|
CEL (Channel Event Logging)
|
||||||
|
------------------
|
||||||
|
* The 'extra' field of all CEL events that use it now consists of a JSON blob
|
||||||
|
with key/value pairs which are defined in the Asterisk 12 CEL documentation.
|
||||||
|
|
||||||
|
* AST_CEL_BLINDTRANSFER events now report the transferee bridge unique
|
||||||
|
identifier, extension, and context in a JSON blob as the extra string
|
||||||
|
instead of the transferee channel name as the peer.
|
||||||
|
|
||||||
|
* AST_CEL_ATTENDEDTRANSFER events now report the peer as NULL and additional
|
||||||
|
information in the 'extra' string as a JSON blob. For transfers that occur
|
||||||
|
between two bridged channels, the 'extra' JSON blob contains the primary
|
||||||
|
bridge unique identifier, the secondary channel name, and the secondary
|
||||||
|
bridge unique identifier. For transfers that occur between a bridged channel
|
||||||
|
and a channel running an app, the 'extra' JSON blob contains the primary
|
||||||
|
bridge unique identifier, the secondary channel name, and the app name.
|
||||||
|
|
||||||
Features
|
Features
|
||||||
-------------------
|
-------------------
|
||||||
* The BRIDGE_FEATURES channel variable would previously only set features for
|
* The BRIDGE_FEATURES channel variable would previously only set features for
|
||||||
|
|
|
@ -75,9 +75,9 @@ static int celgenuserevent_exec(struct ast_channel *chan, const char *data)
|
||||||
parse = ast_strdupa(data);
|
parse = ast_strdupa(data);
|
||||||
AST_STANDARD_APP_ARGS(args, parse);
|
AST_STANDARD_APP_ARGS(args, parse);
|
||||||
|
|
||||||
blob = ast_json_pack("{s: s, s: s}",
|
blob = ast_json_pack("{s: s, s: {s: s}}",
|
||||||
"event", args.event,
|
"event", args.event,
|
||||||
"extra", args.extra);
|
"extra", "extra", args.extra);
|
||||||
if (!blob) {
|
if (!blob) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/stringfields.h"
|
#include "asterisk/stringfields.h"
|
||||||
#include "asterisk/global_datastores.h"
|
#include "asterisk/global_datastores.h"
|
||||||
#include "asterisk/dsp.h"
|
#include "asterisk/dsp.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/aoc.h"
|
#include "asterisk/aoc.h"
|
||||||
#include "asterisk/ccss.h"
|
#include "asterisk/ccss.h"
|
||||||
#include "asterisk/indications.h"
|
#include "asterisk/indications.h"
|
||||||
|
|
|
@ -46,7 +46,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/features.h"
|
#include "asterisk/features.h"
|
||||||
#include "asterisk/manager.h"
|
#include "asterisk/manager.h"
|
||||||
#include "asterisk/callerid.h"
|
#include "asterisk/callerid.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
|
|
||||||
#define PICKUPMARK "PICKUPMARK"
|
#define PICKUPMARK "PICKUPMARK"
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/taskprocessor.h"
|
#include "asterisk/taskprocessor.h"
|
||||||
#include "asterisk/aoc.h"
|
#include "asterisk/aoc.h"
|
||||||
#include "asterisk/callerid.h"
|
#include "asterisk/callerid.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/data.h"
|
#include "asterisk/data.h"
|
||||||
#include "asterisk/term.h"
|
#include "asterisk/term.h"
|
||||||
#include "asterisk/dial.h"
|
#include "asterisk/dial.h"
|
||||||
|
|
|
@ -107,7 +107,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/callerid.h"
|
#include "asterisk/callerid.h"
|
||||||
#include "asterisk/adsi.h"
|
#include "asterisk/adsi.h"
|
||||||
#include "asterisk/cli.h"
|
#include "asterisk/cli.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/features.h"
|
#include "asterisk/features.h"
|
||||||
#include "asterisk/musiconhold.h"
|
#include "asterisk/musiconhold.h"
|
||||||
#include "asterisk/say.h"
|
#include "asterisk/say.h"
|
||||||
|
|
|
@ -276,7 +276,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/translate.h"
|
#include "asterisk/translate.h"
|
||||||
#include "asterisk/ast_version.h"
|
#include "asterisk/ast_version.h"
|
||||||
#include "asterisk/event.h"
|
#include "asterisk/event.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/data.h"
|
#include "asterisk/data.h"
|
||||||
#include "asterisk/aoc.h"
|
#include "asterisk/aoc.h"
|
||||||
#include "asterisk/message.h"
|
#include "asterisk/message.h"
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
#include "asterisk/manager.h"
|
#include "asterisk/manager.h"
|
||||||
#include "asterisk/astdb.h"
|
#include "asterisk/astdb.h"
|
||||||
#include "asterisk/features.h"
|
#include "asterisk/features.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/causes.h"
|
#include "asterisk/causes.h"
|
||||||
#include "asterisk/features_config.h"
|
#include "asterisk/features_config.h"
|
||||||
#include "asterisk/bridging.h"
|
#include "asterisk/bridging.h"
|
||||||
|
|
|
@ -67,8 +67,6 @@ enum ast_cel_event_type {
|
||||||
AST_CEL_BLINDTRANSFER = 13,
|
AST_CEL_BLINDTRANSFER = 13,
|
||||||
/*! \brief a transfer occurs */
|
/*! \brief a transfer occurs */
|
||||||
AST_CEL_ATTENDEDTRANSFER = 14,
|
AST_CEL_ATTENDEDTRANSFER = 14,
|
||||||
/*! \brief a transfer occurs */
|
|
||||||
AST_CEL_TRANSFER = 15,
|
|
||||||
/*! \brief a 3-way conference, usually part of a transfer */
|
/*! \brief a 3-way conference, usually part of a transfer */
|
||||||
AST_CEL_HOOKFLASH = 16,
|
AST_CEL_HOOKFLASH = 16,
|
||||||
/*! \brief a 3-way conference, usually part of a transfer */
|
/*! \brief a 3-way conference, usually part of a transfer */
|
||||||
|
@ -167,31 +165,6 @@ enum ast_cel_event_type ast_cel_str_to_event_type(const char *name);
|
||||||
*/
|
*/
|
||||||
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event);
|
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event);
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Report a channel event
|
|
||||||
*
|
|
||||||
* \param chan This argument is required. This is the primary channel associated with
|
|
||||||
* this channel event.
|
|
||||||
* \param event_type This is the type of call event being reported.
|
|
||||||
* \param userdefevname This is an optional custom name for the call event.
|
|
||||||
* \param extra This is an optional opaque field that will go into the "CEL_EXTRA"
|
|
||||||
* information element of the call event.
|
|
||||||
* \param peer2 All CEL events contain a "peer name" information element. The first
|
|
||||||
* place the code will look to get a peer name is from the bridged channel to
|
|
||||||
* chan. If chan has no bridged channel and peer2 is specified, then the name
|
|
||||||
* of peer2 will go into the "peer name" field. If neither are available, the
|
|
||||||
* peer name field will be blank.
|
|
||||||
*
|
|
||||||
* \since 1.8
|
|
||||||
*
|
|
||||||
* \pre chan and peer2 are both unlocked
|
|
||||||
*
|
|
||||||
* \retval 0 success
|
|
||||||
* \retval non-zero failure
|
|
||||||
*/
|
|
||||||
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
|
|
||||||
const char *userdefevname, const char *extra, struct ast_channel *peer2);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Helper struct for getting the fields out of a CEL event
|
* \brief Helper struct for getting the fields out of a CEL event
|
||||||
*/
|
*/
|
||||||
|
@ -312,8 +285,8 @@ struct ast_channel_snapshot;
|
||||||
* with this channel event.
|
* with this channel event.
|
||||||
* \param event_type The type of call event being reported.
|
* \param event_type The type of call event being reported.
|
||||||
* \param userdefevname Custom name for the call event. (optional)
|
* \param userdefevname Custom name for the call event. (optional)
|
||||||
* \param extra An opaque field that will go into the "CEL_EXTRA" information
|
* \param extra An event-specific opaque JSON blob to be rendered and placed
|
||||||
* element of the call event. (optional)
|
* in the "CEL_EXTRA" information element of the call event. (optional)
|
||||||
* \param peer_name The peer name to be placed into the event. (optional)
|
* \param peer_name The peer name to be placed into the event. (optional)
|
||||||
*
|
*
|
||||||
* \since 12
|
* \since 12
|
||||||
|
@ -323,7 +296,7 @@ struct ast_channel_snapshot;
|
||||||
*/
|
*/
|
||||||
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
|
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
|
||||||
enum ast_cel_event_type event_type, const char *userdefevname,
|
enum ast_cel_event_type event_type, const char *userdefevname,
|
||||||
const char *extra, const char *peer_name);
|
struct ast_json *extra, const char *peer_name);
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
|
|
335
main/cel.c
335
main/cel.c
|
@ -61,6 +61,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/stasis_bridging.h"
|
#include "asterisk/stasis_bridging.h"
|
||||||
#include "asterisk/bridging.h"
|
#include "asterisk/bridging.h"
|
||||||
#include "asterisk/parking.h"
|
#include "asterisk/parking.h"
|
||||||
|
#include "asterisk/features.h"
|
||||||
|
|
||||||
/*** DOCUMENTATION
|
/*** DOCUMENTATION
|
||||||
<configInfo name="cel" language="en_US">
|
<configInfo name="cel" language="en_US">
|
||||||
|
@ -101,7 +102,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
<enum name="CONF_END"/>
|
<enum name="CONF_END"/>
|
||||||
<enum name="PARK_START"/>
|
<enum name="PARK_START"/>
|
||||||
<enum name="PARK_END"/>
|
<enum name="PARK_END"/>
|
||||||
<enum name="TRANSFER"/>
|
|
||||||
<enum name="USER_DEFINED"/>
|
<enum name="USER_DEFINED"/>
|
||||||
<enum name="CONF_ENTER"/>
|
<enum name="CONF_ENTER"/>
|
||||||
<enum name="CONF_EXIT"/>
|
<enum name="CONF_EXIT"/>
|
||||||
|
@ -308,7 +308,6 @@ static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
|
||||||
[AST_CEL_CONF_END] = "CONF_END",
|
[AST_CEL_CONF_END] = "CONF_END",
|
||||||
[AST_CEL_PARK_START] = "PARK_START",
|
[AST_CEL_PARK_START] = "PARK_START",
|
||||||
[AST_CEL_PARK_END] = "PARK_END",
|
[AST_CEL_PARK_END] = "PARK_END",
|
||||||
[AST_CEL_TRANSFER] = "TRANSFER",
|
|
||||||
[AST_CEL_USER_DEFINED] = "USER_DEFINED",
|
[AST_CEL_USER_DEFINED] = "USER_DEFINED",
|
||||||
[AST_CEL_CONF_ENTER] = "CONF_ENTER",
|
[AST_CEL_CONF_ENTER] = "CONF_ENTER",
|
||||||
[AST_CEL_CONF_EXIT] = "CONF_EXIT",
|
[AST_CEL_CONF_EXIT] = "CONF_EXIT",
|
||||||
|
@ -634,9 +633,13 @@ static int cel_track_app(const char *const_app)
|
||||||
static int cel_linkedid_ref(const char *linkedid);
|
static int cel_linkedid_ref(const char *linkedid);
|
||||||
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
|
struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
|
||||||
enum ast_cel_event_type event_type, const char *userdefevname,
|
enum ast_cel_event_type event_type, const char *userdefevname,
|
||||||
const char *extra, const char *peer_name)
|
struct ast_json *extra, const char *peer_name)
|
||||||
{
|
{
|
||||||
struct timeval eventtime = ast_tvnow();
|
struct timeval eventtime = ast_tvnow();
|
||||||
|
RAII_VAR(char *, extra_txt, NULL, ast_free);
|
||||||
|
if (extra) {
|
||||||
|
extra_txt = ast_json_dump_string(extra);
|
||||||
|
}
|
||||||
return ast_event_new(AST_EVENT_CEL,
|
return ast_event_new(AST_EVENT_CEL,
|
||||||
AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
|
AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
|
||||||
AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
|
AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
|
||||||
|
@ -658,14 +661,14 @@ struct ast_event *ast_cel_create_event(struct ast_channel_snapshot *snapshot,
|
||||||
AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->uniqueid,
|
AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, snapshot->uniqueid,
|
||||||
AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
|
AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, snapshot->linkedid,
|
||||||
AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield,
|
AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, snapshot->userfield,
|
||||||
AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra, ""),
|
AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, S_OR(extra_txt, ""),
|
||||||
AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer_name, ""),
|
AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, S_OR(peer_name, ""),
|
||||||
AST_EVENT_IE_END);
|
AST_EVENT_IE_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int report_event_snapshot(struct ast_channel_snapshot *snapshot,
|
static int cel_report_event(struct ast_channel_snapshot *snapshot,
|
||||||
enum ast_cel_event_type event_type, const char *userdefevname,
|
enum ast_cel_event_type event_type, const char *userdefevname,
|
||||||
const char *extra, const char *peer2_name)
|
struct ast_json *extra, const char *peer2_name)
|
||||||
{
|
{
|
||||||
struct ast_event *ev;
|
struct ast_event *ev;
|
||||||
char *linkedid = ast_strdupa(snapshot->linkedid);
|
char *linkedid = ast_strdupa(snapshot->linkedid);
|
||||||
|
@ -735,7 +738,7 @@ static void check_retire_linkedid(struct ast_channel_snapshot *snapshot)
|
||||||
* before unreffing the channel we have a refcount of 3, we're done. Unlink and report. */
|
* before unreffing the channel we have a refcount of 3, we're done. Unlink and report. */
|
||||||
if (ao2_ref(lid, -1) == 3) {
|
if (ao2_ref(lid, -1) == 3) {
|
||||||
ast_str_container_remove(linkedids, lid);
|
ast_str_container_remove(linkedids, lid);
|
||||||
report_event_snapshot(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
|
cel_report_event(snapshot, AST_CEL_LINKEDID_END, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
ao2_ref(lid, -1);
|
ao2_ref(lid, -1);
|
||||||
}
|
}
|
||||||
|
@ -895,109 +898,6 @@ static int cel_linkedid_ref(const char *linkedid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
|
|
||||||
const char *userdefevname, const char *extra, struct ast_channel *peer2)
|
|
||||||
{
|
|
||||||
struct timeval eventtime;
|
|
||||||
struct ast_event *ev;
|
|
||||||
const char *peername = "";
|
|
||||||
struct ast_channel *peer;
|
|
||||||
char *linkedid = ast_strdupa(ast_channel_linkedid(chan));
|
|
||||||
|
|
||||||
if (!ast_cel_check_enabled()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Record the linkedid of new channels if we are tracking LINKEDID_END even if we aren't
|
|
||||||
* reporting on CHANNEL_START so we can track when to send LINKEDID_END */
|
|
||||||
if (ast_cel_track_event(AST_CEL_LINKEDID_END) && event_type == AST_CEL_CHANNEL_START && linkedid) {
|
|
||||||
if (cel_linkedid_ref(linkedid)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ast_cel_track_event(event_type)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END)
|
|
||||||
&& !cel_track_app(ast_channel_appl(chan))) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_channel_lock(chan);
|
|
||||||
peer = ast_bridged_channel(chan);
|
|
||||||
if (peer) {
|
|
||||||
ast_channel_ref(peer);
|
|
||||||
}
|
|
||||||
ast_channel_unlock(chan);
|
|
||||||
|
|
||||||
if (peer) {
|
|
||||||
ast_channel_lock(peer);
|
|
||||||
peername = ast_strdupa(ast_channel_name(peer));
|
|
||||||
ast_channel_unlock(peer);
|
|
||||||
} else if (peer2) {
|
|
||||||
ast_channel_lock(peer2);
|
|
||||||
peername = ast_strdupa(ast_channel_name(peer2));
|
|
||||||
ast_channel_unlock(peer2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userdefevname) {
|
|
||||||
userdefevname = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!extra) {
|
|
||||||
extra = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
eventtime = ast_tvnow();
|
|
||||||
|
|
||||||
ast_channel_lock(chan);
|
|
||||||
|
|
||||||
ev = ast_event_new(AST_EVENT_CEL,
|
|
||||||
AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
|
|
||||||
AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
|
|
||||||
AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
|
|
||||||
AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
|
|
||||||
AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
|
|
||||||
S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
|
|
||||||
AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
|
|
||||||
S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
|
|
||||||
AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
|
|
||||||
S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
|
|
||||||
AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
|
|
||||||
S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
|
|
||||||
AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
|
|
||||||
S_OR(ast_channel_dialed(chan)->number.str, ""),
|
|
||||||
AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
|
|
||||||
AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
|
|
||||||
AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
|
|
||||||
AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
|
|
||||||
AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
|
|
||||||
AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
|
|
||||||
AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
|
|
||||||
AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
|
|
||||||
AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
|
|
||||||
AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
|
|
||||||
AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
|
|
||||||
AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
|
|
||||||
AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
|
|
||||||
AST_EVENT_IE_END);
|
|
||||||
|
|
||||||
ast_channel_unlock(chan);
|
|
||||||
|
|
||||||
if (peer) {
|
|
||||||
peer = ast_channel_unref(peer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ev && ast_event_queue(ev)) {
|
|
||||||
ast_event_destroy(ev);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
|
int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *r)
|
||||||
{
|
{
|
||||||
if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
|
if (r->version != AST_CEL_EVENT_RECORD_VERSION) {
|
||||||
|
@ -1074,13 +974,13 @@ static void cel_channel_state_change(
|
||||||
int is_hungup, was_hungup;
|
int is_hungup, was_hungup;
|
||||||
|
|
||||||
if (!new_snapshot) {
|
if (!new_snapshot) {
|
||||||
report_event_snapshot(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
|
cel_report_event(old_snapshot, AST_CEL_CHANNEL_END, NULL, NULL, NULL);
|
||||||
check_retire_linkedid(old_snapshot);
|
check_retire_linkedid(old_snapshot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!old_snapshot) {
|
if (!old_snapshot) {
|
||||||
report_event_snapshot(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
|
cel_report_event(new_snapshot, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1088,22 +988,22 @@ static void cel_channel_state_change(
|
||||||
is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
|
is_hungup = ast_test_flag(&new_snapshot->flags, AST_FLAG_DEAD) ? 1 : 0;
|
||||||
|
|
||||||
if (!was_hungup && is_hungup) {
|
if (!was_hungup && is_hungup) {
|
||||||
RAII_VAR(struct ast_str *, extra_str, ast_str_create(128), ast_free);
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
RAII_VAR(struct ast_multi_channel_blob *, blob, get_dialstatus_blob(new_snapshot->uniqueid), ao2_cleanup);
|
RAII_VAR(struct ast_multi_channel_blob *, blob, get_dialstatus_blob(new_snapshot->uniqueid), ao2_cleanup);
|
||||||
const char *dialstatus = "";
|
const char *dialstatus = "";
|
||||||
if (blob && !ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
|
if (blob && !ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
|
||||||
dialstatus = get_blob_variable(blob, "dialstatus");
|
dialstatus = get_blob_variable(blob, "dialstatus");
|
||||||
}
|
}
|
||||||
ast_str_set(&extra_str, 0, "%d,%s,%s",
|
extra = ast_json_pack("{s: i, s: s, s: s}",
|
||||||
new_snapshot->hangupcause,
|
"hangupcause", new_snapshot->hangupcause,
|
||||||
new_snapshot->hangupsource,
|
"hangupsource", new_snapshot->hangupsource,
|
||||||
dialstatus);
|
"dialstatus", dialstatus);
|
||||||
report_event_snapshot(new_snapshot, AST_CEL_HANGUP, NULL, ast_str_buffer(extra_str), NULL);
|
cel_report_event(new_snapshot, AST_CEL_HANGUP, NULL, extra, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
|
if (old_snapshot->state != new_snapshot->state && new_snapshot->state == AST_STATE_UP) {
|
||||||
report_event_snapshot(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
|
cel_report_event(new_snapshot, AST_CEL_ANSWER, NULL, NULL, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1136,12 +1036,12 @@ static void cel_channel_app_change(
|
||||||
|
|
||||||
/* old snapshot has an application, end it */
|
/* old snapshot has an application, end it */
|
||||||
if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
|
if (old_snapshot && !ast_strlen_zero(old_snapshot->appl)) {
|
||||||
report_event_snapshot(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
|
cel_report_event(old_snapshot, AST_CEL_APP_END, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* new snapshot has an application, start it */
|
/* new snapshot has an application, start it */
|
||||||
if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {
|
if (new_snapshot && !ast_strlen_zero(new_snapshot->appl)) {
|
||||||
report_event_snapshot(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
|
cel_report_event(new_snapshot, AST_CEL_APP_START, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1260,7 +1160,11 @@ static void cel_bridge_enter_cb(
|
||||||
|
|
||||||
if (snapshot->capabilities & (AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE)) {
|
if (snapshot->capabilities & (AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE)) {
|
||||||
if (assoc && assoc->track_as_conf) {
|
if (assoc && assoc->track_as_conf) {
|
||||||
report_event_snapshot(chan_snapshot, AST_CEL_CONF_ENTER, NULL, NULL, NULL);
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
|
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(chan_snapshot, AST_CEL_CONF_ENTER, NULL, extra, NULL);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1286,7 +1190,7 @@ static void cel_bridge_enter_cb(
|
||||||
}
|
}
|
||||||
|
|
||||||
add_bridge_primary(latest_primary, snapshot->uniqueid, chan_snapshot->name);
|
add_bridge_primary(latest_primary, snapshot->uniqueid, chan_snapshot->name);
|
||||||
report_event_snapshot(latest_primary, AST_CEL_BRIDGE_START, NULL, NULL, chan_snapshot->name);
|
cel_report_event(latest_primary, AST_CEL_BRIDGE_START, NULL, NULL, chan_snapshot->name);
|
||||||
} else if (ao2_container_count(snapshot->channels) > 2) {
|
} else if (ao2_container_count(snapshot->channels) > 2) {
|
||||||
if (!assoc) {
|
if (!assoc) {
|
||||||
ast_log(LOG_ERROR, "No association found for bridge %s\n", snapshot->uniqueid);
|
ast_log(LOG_ERROR, "No association found for bridge %s\n", snapshot->uniqueid);
|
||||||
|
@ -1295,18 +1199,31 @@ static void cel_bridge_enter_cb(
|
||||||
|
|
||||||
/* this bridge will no longer be treated like a bridge, so mark the bridge_assoc as such */
|
/* this bridge will no longer be treated like a bridge, so mark the bridge_assoc as such */
|
||||||
if (!assoc->track_as_conf) {
|
if (!assoc->track_as_conf) {
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
assoc->track_as_conf = 1;
|
assoc->track_as_conf = 1;
|
||||||
report_event_snapshot(assoc->primary_snapshot, AST_CEL_BRIDGE_TO_CONF, NULL,
|
|
||||||
chan_snapshot->name, assoc->secondary_name);
|
extra = ast_json_pack("{s: s, s: s}",
|
||||||
|
"channel_name", chan_snapshot->name,
|
||||||
|
"bridge_id", snapshot->uniqueid);
|
||||||
|
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(assoc->primary_snapshot, AST_CEL_BRIDGE_TO_CONF, NULL,
|
||||||
|
extra, assoc->secondary_name);
|
||||||
|
}
|
||||||
|
|
||||||
ast_string_field_set(assoc, secondary_name, "");
|
ast_string_field_set(assoc, secondary_name, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
|
} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
if (!assoc) {
|
if (!assoc) {
|
||||||
add_bridge_primary(chan_snapshot, snapshot->uniqueid, "");
|
add_bridge_primary(chan_snapshot, snapshot->uniqueid, "");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
report_event_snapshot(chan_snapshot, AST_CEL_CONF_ENTER, NULL, NULL, NULL);
|
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(chan_snapshot, AST_CEL_CONF_ENTER, NULL, extra, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1333,17 +1250,25 @@ static void cel_bridge_leave_cb(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assoc->track_as_conf) {
|
if (assoc->track_as_conf) {
|
||||||
report_event_snapshot(chan_snapshot, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
|
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(chan_snapshot, AST_CEL_CONF_EXIT, NULL, extra, NULL);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ao2_container_count(snapshot->channels) == 1) {
|
if (ao2_container_count(snapshot->channels) == 1) {
|
||||||
report_event_snapshot(assoc->primary_snapshot, AST_CEL_BRIDGE_END, NULL, NULL, assoc->secondary_name);
|
cel_report_event(assoc->primary_snapshot, AST_CEL_BRIDGE_END, NULL, NULL, assoc->secondary_name);
|
||||||
remove_bridge_primary(assoc->primary_snapshot->uniqueid);
|
remove_bridge_primary(assoc->primary_snapshot->uniqueid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
|
} else if (snapshot->capabilities & AST_BRIDGE_CAPABILITY_MULTIMIX) {
|
||||||
report_event_snapshot(chan_snapshot, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
|
extra = ast_json_pack("{s: s}", "bridge_id", snapshot->uniqueid);
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(chan_snapshot, AST_CEL_CONF_EXIT, NULL, extra, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1353,26 +1278,36 @@ static void cel_parking_cb(
|
||||||
struct stasis_message *message)
|
struct stasis_message *message)
|
||||||
{
|
{
|
||||||
struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
|
struct ast_parked_call_payload *parked_payload = stasis_message_data(message);
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
|
const char *reason = NULL;
|
||||||
|
|
||||||
switch (parked_payload->event_type) {
|
switch (parked_payload->event_type) {
|
||||||
case PARKED_CALL:
|
case PARKED_CALL:
|
||||||
report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_START, NULL,
|
extra = ast_json_pack("{s: s, s: s}",
|
||||||
parked_payload->parkinglot,
|
"parker_dial_string", parked_payload->parker_dial_string,
|
||||||
parked_payload->parker_dial_string);
|
"parking_lot", parked_payload->parkinglot);
|
||||||
break;
|
if (extra) {
|
||||||
|
cel_report_event(parked_payload->parkee, AST_CEL_PARK_START, NULL, extra, NULL);
|
||||||
|
}
|
||||||
|
return;
|
||||||
case PARKED_CALL_TIMEOUT:
|
case PARKED_CALL_TIMEOUT:
|
||||||
report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL);
|
reason = "ParkedCallTimeOut";
|
||||||
break;
|
break;
|
||||||
case PARKED_CALL_GIVEUP:
|
case PARKED_CALL_GIVEUP:
|
||||||
report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallGiveUp", NULL);
|
reason = "ParkedCallGiveUp";
|
||||||
break;
|
break;
|
||||||
case PARKED_CALL_UNPARKED:
|
case PARKED_CALL_UNPARKED:
|
||||||
report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallUnparked", NULL);
|
reason = "ParkedCallUnparked";
|
||||||
break;
|
break;
|
||||||
case PARKED_CALL_FAILED:
|
case PARKED_CALL_FAILED:
|
||||||
report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallFailed", NULL);
|
reason = "ParkedCallFailed";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extra = ast_json_pack("{s: s}", "reason", reason);
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(parked_payload->parkee, AST_CEL_PARK_END, NULL, extra, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void save_dialstatus(struct ast_multi_channel_blob *blob)
|
static void save_dialstatus(struct ast_multi_channel_blob *blob)
|
||||||
|
@ -1396,11 +1331,15 @@ static void cel_dial_cb(void *data, struct stasis_subscription *sub,
|
||||||
|
|
||||||
if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
|
if (!ast_strlen_zero(get_blob_variable(blob, "forward"))) {
|
||||||
struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller");
|
struct ast_channel_snapshot *caller = ast_multi_channel_blob_get_channel(blob, "caller");
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
if (!caller) {
|
if (!caller) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
report_event_snapshot(caller, AST_CEL_FORWARD, NULL, get_blob_variable(blob, "forward"), NULL);
|
extra = ast_json_pack("{s: s}", "forward", get_blob_variable(blob, "forward"));
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(caller, AST_CEL_FORWARD, NULL, extra, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
|
if (ast_strlen_zero(get_blob_variable(blob, "dialstatus"))) {
|
||||||
|
@ -1423,8 +1362,8 @@ static void cel_generic_cb(
|
||||||
case AST_CEL_USER_DEFINED:
|
case AST_CEL_USER_DEFINED:
|
||||||
{
|
{
|
||||||
const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
|
const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
|
||||||
const char *extra = ast_json_string_get(ast_json_object_get(event_details, "extra"));
|
struct ast_json *extra = ast_json_object_get(event_details, "extra");
|
||||||
report_event_snapshot(obj->snapshot, event_type, event, extra, NULL);
|
cel_report_event(obj->snapshot, event_type, event, extra, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1433,6 +1372,107 @@ static void cel_generic_cb(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cel_blind_transfer_cb(
|
||||||
|
void *data, struct stasis_subscription *sub,
|
||||||
|
struct stasis_topic *topic,
|
||||||
|
struct stasis_message *message)
|
||||||
|
{
|
||||||
|
struct ast_bridge_blob *obj = stasis_message_data(message);
|
||||||
|
struct ast_channel_snapshot *chan_snapshot = obj->channel;
|
||||||
|
struct ast_bridge_snapshot *bridge_snapshot = obj->bridge;
|
||||||
|
struct ast_json *blob = obj->blob;
|
||||||
|
struct ast_json *json_exten = ast_json_object_get(blob, "exten");
|
||||||
|
struct ast_json *json_context = ast_json_object_get(blob, "context");
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
|
const char *exten, *context;
|
||||||
|
|
||||||
|
if (!json_exten || !json_context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
exten = ast_json_string_get(json_exten);
|
||||||
|
context = ast_json_string_get(json_context);
|
||||||
|
if (!exten || !context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extra = ast_json_pack("{s: s, s: s, s: s}",
|
||||||
|
"extension", exten,
|
||||||
|
"context", context,
|
||||||
|
"bridge_id", bridge_snapshot->uniqueid);
|
||||||
|
|
||||||
|
if (extra) {
|
||||||
|
cel_report_event(chan_snapshot, AST_CEL_BLINDTRANSFER, NULL, extra, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cel_attended_transfer_cb(
|
||||||
|
void *data, struct stasis_subscription *sub,
|
||||||
|
struct stasis_topic *topic,
|
||||||
|
struct stasis_message *message)
|
||||||
|
{
|
||||||
|
struct ast_attended_transfer_message *xfer = stasis_message_data(message);
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref);
|
||||||
|
struct ast_bridge_snapshot *bridge1, *bridge2;
|
||||||
|
struct ast_channel_snapshot *channel1, *channel2;
|
||||||
|
|
||||||
|
/* Make sure bridge1 is always non-NULL */
|
||||||
|
if (!xfer->to_transferee.bridge_snapshot) {
|
||||||
|
bridge1 = xfer->to_transfer_target.bridge_snapshot;
|
||||||
|
bridge2 = xfer->to_transferee.bridge_snapshot;
|
||||||
|
channel1 = xfer->to_transfer_target.channel_snapshot;
|
||||||
|
channel2 = xfer->to_transferee.channel_snapshot;
|
||||||
|
} else {
|
||||||
|
bridge1 = xfer->to_transferee.bridge_snapshot;
|
||||||
|
bridge2 = xfer->to_transfer_target.bridge_snapshot;
|
||||||
|
channel1 = xfer->to_transferee.channel_snapshot;
|
||||||
|
channel2 = xfer->to_transfer_target.channel_snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (xfer->dest_type) {
|
||||||
|
case AST_ATTENDED_TRANSFER_DEST_FAIL:
|
||||||
|
return;
|
||||||
|
/* handle these two the same */
|
||||||
|
case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
|
||||||
|
case AST_ATTENDED_TRANSFER_DEST_LINK:
|
||||||
|
extra = ast_json_pack("{s: s, s: s, s: s}",
|
||||||
|
"bridge1_id", bridge1->uniqueid,
|
||||||
|
"channel2_name", channel2->name,
|
||||||
|
"bridge2_id", bridge2->uniqueid);
|
||||||
|
|
||||||
|
if (!extra) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AST_ATTENDED_TRANSFER_DEST_APP:
|
||||||
|
extra = ast_json_pack("{s: s, s: s, s: s}",
|
||||||
|
"bridge1_id", bridge1->uniqueid,
|
||||||
|
"channel2_name", channel2->name,
|
||||||
|
"app", xfer->dest.app);
|
||||||
|
|
||||||
|
if (!extra) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cel_report_event(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cel_pickup_cb(
|
||||||
|
void *data, struct stasis_subscription *sub,
|
||||||
|
struct stasis_topic *topic,
|
||||||
|
struct stasis_message *message)
|
||||||
|
{
|
||||||
|
struct ast_multi_channel_blob *obj = stasis_message_data(message);
|
||||||
|
struct ast_channel_snapshot *channel = ast_multi_channel_blob_get_channel(obj, "channel");
|
||||||
|
struct ast_channel_snapshot *target = ast_multi_channel_blob_get_channel(obj, "target");
|
||||||
|
|
||||||
|
if (!channel || !target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, channel->name);
|
||||||
|
}
|
||||||
|
|
||||||
static void ast_cel_engine_term(void)
|
static void ast_cel_engine_term(void)
|
||||||
{
|
{
|
||||||
aco_info_destroy(&cel_cfg_info);
|
aco_info_destroy(&cel_cfg_info);
|
||||||
|
@ -1554,6 +1594,21 @@ int ast_cel_engine_init(void)
|
||||||
cel_generic_cb,
|
cel_generic_cb,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
ret |= stasis_message_router_add(cel_state_router,
|
||||||
|
ast_blind_transfer_type(),
|
||||||
|
cel_blind_transfer_cb,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ret |= stasis_message_router_add(cel_state_router,
|
||||||
|
ast_attended_transfer_type(),
|
||||||
|
cel_attended_transfer_cb,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ret |= stasis_message_router_add(cel_state_router,
|
||||||
|
ast_call_pickup_type(),
|
||||||
|
cel_pickup_cb,
|
||||||
|
NULL);
|
||||||
|
|
||||||
/* If somehow we failed to add any routes, just shut down the whole
|
/* If somehow we failed to add any routes, just shut down the whole
|
||||||
* thing and fail it.
|
* thing and fail it.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -50,7 +50,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/cli.h"
|
#include "asterisk/cli.h"
|
||||||
#include "asterisk/translate.h"
|
#include "asterisk/translate.h"
|
||||||
#include "asterisk/manager.h"
|
#include "asterisk/manager.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/chanvars.h"
|
#include "asterisk/chanvars.h"
|
||||||
#include "asterisk/linkedlists.h"
|
#include "asterisk/linkedlists.h"
|
||||||
#include "asterisk/indications.h"
|
#include "asterisk/indications.h"
|
||||||
|
|
|
@ -70,7 +70,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/audiohook.h"
|
#include "asterisk/audiohook.h"
|
||||||
#include "asterisk/global_datastores.h"
|
#include "asterisk/global_datastores.h"
|
||||||
#include "asterisk/astobj2.h"
|
#include "asterisk/astobj2.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/test.h"
|
#include "asterisk/test.h"
|
||||||
#include "asterisk/bridging.h"
|
#include "asterisk/bridging.h"
|
||||||
#include "asterisk/bridging_basic.h"
|
#include "asterisk/bridging_basic.h"
|
||||||
|
@ -2553,8 +2552,6 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initiate the channel transfer of party A to party C (or recalled party B). */
|
/* Initiate the channel transfer of party A to party C (or recalled party B). */
|
||||||
ast_cel_report_event(transferee, AST_CEL_ATTENDEDTRANSFER, NULL, NULL, newchan);
|
|
||||||
|
|
||||||
xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee));
|
xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee));
|
||||||
if (!xferchan) {
|
if (!xferchan) {
|
||||||
ast_autoservice_chan_hangup_peer(transferee, newchan);
|
ast_autoservice_chan_hangup_peer(transferee, newchan);
|
||||||
|
@ -4739,8 +4736,6 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
|
||||||
ast_channel_unlock(chan);
|
ast_channel_unlock(chan);
|
||||||
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
|
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
|
||||||
|
|
||||||
ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
|
|
||||||
|
|
||||||
if (ast_answer(chan)) {
|
if (ast_answer(chan)) {
|
||||||
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
|
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
|
||||||
goto pickup_failed;
|
goto pickup_failed;
|
||||||
|
|
|
@ -50,7 +50,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/file.h"
|
#include "asterisk/file.h"
|
||||||
#include "asterisk/callerid.h"
|
#include "asterisk/callerid.h"
|
||||||
#include "asterisk/cdr.h"
|
#include "asterisk/cdr.h"
|
||||||
#include "asterisk/cel.h"
|
|
||||||
#include "asterisk/config.h"
|
#include "asterisk/config.h"
|
||||||
#include "asterisk/term.h"
|
#include "asterisk/term.h"
|
||||||
#include "asterisk/time.h"
|
#include "asterisk/time.h"
|
||||||
|
|
733
tests/test_cel.c
733
tests/test_cel.c
|
@ -47,6 +47,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#include "asterisk/bridging_basic.h"
|
#include "asterisk/bridging_basic.h"
|
||||||
#include "asterisk/stasis_channels.h"
|
#include "asterisk/stasis_channels.h"
|
||||||
#include "asterisk/stasis_bridging.h"
|
#include "asterisk/stasis_bridging.h"
|
||||||
|
#include "asterisk/json.h"
|
||||||
|
#include "asterisk/features.h"
|
||||||
|
|
||||||
#define TEST_CATEGORY "/main/cel/"
|
#define TEST_CATEGORY "/main/cel/"
|
||||||
|
|
||||||
|
@ -78,6 +80,73 @@ static void do_sleep(void)
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define APPEND_EVENT_SNAPSHOT(snapshot, ev_type, userevent, extra, peer) do { \
|
||||||
|
if (append_expected_event_snapshot(snapshot, ev_type, userevent, extra, peer)) { \
|
||||||
|
return AST_TEST_FAIL; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define APPEND_DUMMY_EVENT() do { \
|
||||||
|
if (append_dummy_event()) { \
|
||||||
|
return AST_TEST_FAIL; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CONF_EXIT(channel, bridge) do { \
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_depart(channel)); \
|
||||||
|
CONF_EXIT_EVENT(channel, bridge); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CONF_EXIT_EVENT(channel, bridge) do { \
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
|
||||||
|
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
|
||||||
|
ast_test_validate(test, extra != NULL); \
|
||||||
|
APPEND_EVENT(channel, AST_CEL_CONF_EXIT, NULL, extra, NULL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CONF_EXIT_SNAPSHOT(channel, bridge) do { \
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
|
||||||
|
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
|
||||||
|
ast_test_validate(test, extra != NULL); \
|
||||||
|
APPEND_EVENT_SNAPSHOT(channel, AST_CEL_CONF_EXIT, NULL, extra, NULL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CONF_ENTER_EVENT(channel, bridge) do { \
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
|
||||||
|
extra = ast_json_pack("{s: s}", "bridge_id", bridge->uniqueid); \
|
||||||
|
ast_test_validate(test, extra != NULL); \
|
||||||
|
APPEND_EVENT(channel, AST_CEL_CONF_ENTER, NULL, extra, NULL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BRIDGE_TO_CONF(first, second, third, bridge) do { \
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
|
||||||
|
extra = ast_json_pack("{s: s, s: s}", \
|
||||||
|
"channel_name", ast_channel_name(third), \
|
||||||
|
"bridge_id", bridge->uniqueid); \
|
||||||
|
ast_test_validate(test, extra != NULL); \
|
||||||
|
APPEND_EVENT(first, AST_CEL_BRIDGE_TO_CONF, NULL, extra, ast_channel_name(second)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define BLINDTRANSFER_EVENT(channel, bridge, extension, context) do { \
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
|
||||||
|
extra = ast_json_pack("{s: s, s: s, s: s}", \
|
||||||
|
"extension", extension, \
|
||||||
|
"context", context, \
|
||||||
|
"bridge_id", bridge->uniqueid); \
|
||||||
|
ast_test_validate(test, extra != NULL); \
|
||||||
|
APPEND_EVENT(channel, AST_CEL_BLINDTRANSFER, NULL, extra, NULL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ATTENDEDTRANSFER_BRIDGE(channel1, bridge1, channel2, bridge2) do { \
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
|
||||||
|
extra = ast_json_pack("{s: s, s: s, s: s}", \
|
||||||
|
"bridge1_id", bridge1->uniqueid, \
|
||||||
|
"channel2_name", ast_channel_name(channel2), \
|
||||||
|
"bridge2_id", bridge2->uniqueid); \
|
||||||
|
ast_test_validate(test, extra != NULL); \
|
||||||
|
APPEND_EVENT(channel1, AST_CEL_ATTENDEDTRANSFER, NULL, extra, NULL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*! \brief Alice's Caller ID */
|
/*! \brief Alice's Caller ID */
|
||||||
#define ALICE_CALLERID { .id.name.str = "Alice", .id.name.valid = 1, .id.number.str = "100", .id.number.valid = 1, }
|
#define ALICE_CALLERID { .id.name.str = "Alice", .id.name.valid = 1, .id.number.str = "100", .id.number.valid = 1, }
|
||||||
|
|
||||||
|
@ -90,31 +159,45 @@ static void do_sleep(void)
|
||||||
/*! \brief David's Caller ID */
|
/*! \brief David's Caller ID */
|
||||||
#define DAVID_CALLERID { .id.name.str = "David", .id.name.valid = 1, .id.number.str = "400", .id.number.valid = 1, }
|
#define DAVID_CALLERID { .id.name.str = "David", .id.name.valid = 1, .id.number.str = "400", .id.number.valid = 1, }
|
||||||
|
|
||||||
|
/*! \brief Eve's Caller ID */
|
||||||
|
#define EVE_CALLERID { .id.name.str = "Eve", .id.name.valid = 1, .id.number.str = "500", .id.number.valid = 1, }
|
||||||
|
|
||||||
|
/*! \brief Fred's Caller ID */
|
||||||
|
#define FRED_CALLERID { .id.name.str = "Fred", .id.name.valid = 1, .id.number.str = "600", .id.number.valid = 1, }
|
||||||
|
|
||||||
/*! \brief Create a \ref test_cel_chan_tech for Alice. */
|
/*! \brief Create a \ref test_cel_chan_tech for Alice. */
|
||||||
#define CREATE_ALICE_CHANNEL(channel_var, caller_id) do { \
|
#define CREATE_ALICE_CHANNEL(channel_var, caller_id) do { \
|
||||||
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
|
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
|
||||||
/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
|
|
||||||
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*! \brief Create a \ref test_cel_chan_tech for Bob. */
|
/*! \brief Create a \ref test_cel_chan_tech for Bob. */
|
||||||
#define CREATE_BOB_CHANNEL(channel_var, caller_id) do { \
|
#define CREATE_BOB_CHANNEL(channel_var, caller_id) do { \
|
||||||
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
|
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
|
||||||
/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
|
|
||||||
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*! \brief Create a \ref test_cel_chan_tech for Charlie. */
|
/*! \brief Create a \ref test_cel_chan_tech for Charlie. */
|
||||||
#define CREATE_CHARLIE_CHANNEL(channel_var, caller_id) do { \
|
#define CREATE_CHARLIE_CHANNEL(channel_var, caller_id) do { \
|
||||||
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
|
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
|
||||||
/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
|
|
||||||
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*! \brief Create a \ref test_cel_chan_tech for Charlie. */
|
/*! \brief Create a \ref test_cel_chan_tech for David. */
|
||||||
#define CREATE_DAVID_CHANNEL(channel_var, caller_id) do { \
|
#define CREATE_DAVID_CHANNEL(channel_var, caller_id) do { \
|
||||||
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David"); \
|
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David"); \
|
||||||
/*ast_channel_set_caller((channel_var), (caller_id), NULL);*/ \
|
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*! \brief Create a \ref test_cel_chan_tech for Eve. */
|
||||||
|
#define CREATE_EVE_CHANNEL(channel_var, caller_id) do { \
|
||||||
|
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "500", "500", "default", NULL, 0, CHANNEL_TECH_NAME "/Eve"); \
|
||||||
|
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*! \brief Create a \ref test_cel_chan_tech for Eve. */
|
||||||
|
#define CREATE_FRED_CHANNEL(channel_var, caller_id) do { \
|
||||||
|
(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "600", "600", "default", NULL, 0, CHANNEL_TECH_NAME "/Fred"); \
|
||||||
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL, NULL); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
@ -139,24 +222,41 @@ static void do_sleep(void)
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*! \brief Hang up a test channel safely */
|
/*! \brief Hang up a test channel safely */
|
||||||
#define HANGUP_CHANNEL(channel, cause, hangup_extra) \
|
#define HANGUP_CHANNEL(channel, cause, dialstatus) do { \
|
||||||
do { \
|
ast_channel_hangupcause_set((channel), (cause)); \
|
||||||
ast_channel_hangupcause_set((channel), (cause)); \
|
ao2_ref(channel, +1); \
|
||||||
ao2_ref(channel, +1); \
|
ast_hangup((channel)); \
|
||||||
ast_hangup(channel); \
|
HANGUP_EVENT(channel, cause, dialstatus); \
|
||||||
APPEND_EVENT(channel, AST_CEL_HANGUP, NULL, hangup_extra, NULL); \
|
APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL, NULL); \
|
||||||
APPEND_EVENT(channel, AST_CEL_CHANNEL_END, NULL, NULL, NULL); \
|
ao2_cleanup(stasis_cache_get_extended(ast_channel_topic_all_cached(), \
|
||||||
ao2_cleanup(stasis_cache_get_extended(ast_channel_topic_all_cached(), \
|
ast_channel_snapshot_type(), ast_channel_uniqueid(channel), 1)); \
|
||||||
ast_channel_snapshot_type(), ast_channel_uniqueid(channel), 1)); \
|
ao2_cleanup(channel); \
|
||||||
ao2_cleanup(channel); \
|
channel = NULL; \
|
||||||
channel = NULL; \
|
} while (0)
|
||||||
|
|
||||||
|
#define HANGUP_EVENT(channel, cause, dialstatus) do { \
|
||||||
|
RAII_VAR(struct ast_json *, extra, NULL, ast_json_unref); \
|
||||||
|
extra = ast_json_pack("{s: i, s: s, s: s}", \
|
||||||
|
"hangupcause", cause, \
|
||||||
|
"hangupsource", "", \
|
||||||
|
"dialstatus", dialstatus); \
|
||||||
|
ast_test_validate(test, extra != NULL); \
|
||||||
|
APPEND_EVENT(channel, AST_CEL_HANGUP, NULL, extra, NULL); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int append_expected_event(
|
static int append_expected_event(
|
||||||
struct ast_channel *chan,
|
struct ast_channel *chan,
|
||||||
enum ast_cel_event_type type,
|
enum ast_cel_event_type type,
|
||||||
const char *userdefevname,
|
const char *userdefevname,
|
||||||
const char *extra, const char *peer);
|
struct ast_json *extra, const char *peer);
|
||||||
|
|
||||||
|
static int append_expected_event_snapshot(
|
||||||
|
struct ast_channel_snapshot *snapshot,
|
||||||
|
enum ast_cel_event_type type,
|
||||||
|
const char *userdefevname,
|
||||||
|
struct ast_json *extra, const char *peer);
|
||||||
|
|
||||||
|
static int append_dummy_event(void);
|
||||||
|
|
||||||
static void safe_channel_release(struct ast_channel *chan)
|
static void safe_channel_release(struct ast_channel *chan)
|
||||||
{
|
{
|
||||||
|
@ -185,7 +285,7 @@ AST_TEST_DEFINE(test_cel_channel_creation)
|
||||||
|
|
||||||
CREATE_ALICE_CHANNEL(chan, (&caller));
|
CREATE_ALICE_CHANNEL(chan, (&caller));
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -213,7 +313,7 @@ AST_TEST_DEFINE(test_cel_unanswered_inbound_call)
|
||||||
|
|
||||||
EMULATE_APP_DATA(chan, 1, "Wait", "1");
|
EMULATE_APP_DATA(chan, 1, "Wait", "1");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +346,7 @@ AST_TEST_DEFINE(test_cel_unanswered_outbound_call)
|
||||||
ast_channel_context_set(chan, "default");
|
ast_channel_context_set(chan, "default");
|
||||||
ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
|
ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
|
||||||
EMULATE_APP_DATA(chan, 0, "AppDial", "(Outgoing Line)");
|
EMULATE_APP_DATA(chan, 0, "AppDial", "(Outgoing Line)");
|
||||||
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +373,7 @@ AST_TEST_DEFINE(test_cel_single_party)
|
||||||
ANSWER_CHANNEL(chan);
|
ANSWER_CHANNEL(chan);
|
||||||
EMULATE_APP_DATA(chan, 2, "VoiceMailMain", "1");
|
EMULATE_APP_DATA(chan, 2, "VoiceMailMain", "1");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -312,7 +412,7 @@ AST_TEST_DEFINE(test_cel_single_bridge)
|
||||||
|
|
||||||
ast_bridge_depart(chan);
|
ast_bridge_depart(chan);
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -353,7 +453,7 @@ AST_TEST_DEFINE(test_cel_single_bridge_continue)
|
||||||
EMULATE_APP_DATA(chan, 3, "Wait", "");
|
EMULATE_APP_DATA(chan, 3, "Wait", "");
|
||||||
|
|
||||||
/* And then it hangs up */
|
/* And then it hangs up */
|
||||||
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -403,8 +503,8 @@ AST_TEST_DEFINE(test_cel_single_twoparty_bridge_a)
|
||||||
ast_bridge_depart(chan_bob);
|
ast_bridge_depart(chan_bob);
|
||||||
APPEND_EVENT(chan_alice, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_bob));
|
APPEND_EVENT(chan_alice, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_bob));
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
|
||||||
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -455,8 +555,8 @@ AST_TEST_DEFINE(test_cel_single_twoparty_bridge_b)
|
||||||
ast_bridge_depart(chan_bob);
|
ast_bridge_depart(chan_bob);
|
||||||
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_alice));
|
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_alice));
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
|
||||||
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -510,18 +610,15 @@ AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
|
||||||
EMULATE_APP_DATA(chan_charlie, 2, "Bridge", "");
|
EMULATE_APP_DATA(chan_charlie, 2, "Bridge", "");
|
||||||
ast_bridge_impart(bridge, chan_charlie, NULL, NULL, 0);
|
ast_bridge_impart(bridge, chan_charlie, NULL, NULL, 0);
|
||||||
do_sleep();
|
do_sleep();
|
||||||
APPEND_EVENT(chan_alice, AST_CEL_BRIDGE_TO_CONF, NULL, ast_channel_name(chan_charlie), ast_channel_name(chan_bob));
|
BRIDGE_TO_CONF(chan_alice, chan_bob, chan_charlie, bridge);
|
||||||
|
|
||||||
ast_bridge_depart(chan_alice);
|
CONF_EXIT(chan_alice, bridge);
|
||||||
APPEND_EVENT(chan_alice, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
CONF_EXIT(chan_bob, bridge);
|
||||||
ast_bridge_depart(chan_bob);
|
CONF_EXIT(chan_charlie, bridge);
|
||||||
APPEND_EVENT(chan_bob, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
|
||||||
ast_bridge_depart(chan_charlie);
|
|
||||||
APPEND_EVENT(chan_charlie, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
|
||||||
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -574,8 +671,8 @@ AST_TEST_DEFINE(test_cel_dial_unanswered)
|
||||||
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
||||||
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "NOANSWER");
|
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "NOANSWER");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ANSWER, "19,,NOANSWER");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ANSWER, "NOANSWER");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ANSWER, "19,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ANSWER, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -609,8 +706,8 @@ AST_TEST_DEFINE(test_cel_dial_busy)
|
||||||
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
||||||
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "BUSY");
|
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "BUSY");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_BUSY, "17,,BUSY");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_BUSY, "BUSY");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_BUSY, "17,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_BUSY, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -643,8 +740,8 @@ AST_TEST_DEFINE(test_cel_dial_congestion)
|
||||||
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
||||||
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CONGESTION");
|
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CONGESTION");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_CONGESTION, "34,,CONGESTION");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_CONGESTION, "CONGESTION");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_CONGESTION, "34,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_CONGESTION, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -677,8 +774,8 @@ AST_TEST_DEFINE(test_cel_dial_unavailable)
|
||||||
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
||||||
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CHANUNAVAIL");
|
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CHANUNAVAIL");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ROUTE_DESTINATION, "3,,CHANUNAVAIL");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NO_ROUTE_DESTINATION, "CHANUNAVAIL");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ROUTE_DESTINATION, "3,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NO_ROUTE_DESTINATION, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -712,8 +809,8 @@ AST_TEST_DEFINE(test_cel_dial_caller_cancel)
|
||||||
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
||||||
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CANCEL");
|
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "CANCEL");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "16,,CANCEL");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "CANCEL");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -755,18 +852,18 @@ AST_TEST_DEFINE(test_cel_dial_parallel_failed)
|
||||||
|
|
||||||
/* Charlie is busy */
|
/* Charlie is busy */
|
||||||
ast_channel_publish_dial(chan_caller, chan_charlie, NULL, "BUSY");
|
ast_channel_publish_dial(chan_caller, chan_charlie, NULL, "BUSY");
|
||||||
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_BUSY, "17,,");
|
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_BUSY, "");
|
||||||
|
|
||||||
/* David is congested */
|
/* David is congested */
|
||||||
ast_channel_publish_dial(chan_caller, chan_david, NULL, "CONGESTION");
|
ast_channel_publish_dial(chan_caller, chan_david, NULL, "CONGESTION");
|
||||||
HANGUP_CHANNEL(chan_david, AST_CAUSE_CONGESTION, "34,,");
|
HANGUP_CHANNEL(chan_david, AST_CAUSE_CONGESTION, "");
|
||||||
|
|
||||||
/* Bob is canceled */
|
/* Bob is canceled */
|
||||||
ast_channel_publish_dial(chan_caller, chan_bob, NULL, "CANCEL");
|
ast_channel_publish_dial(chan_caller, chan_bob, NULL, "CANCEL");
|
||||||
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
/* Alice hangs up */
|
/* Alice hangs up */
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "16,,BUSY");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "BUSY");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -809,8 +906,8 @@ AST_TEST_DEFINE(test_cel_dial_answer_no_bridge)
|
||||||
EMULATE_APP_DATA(chan_caller, 2, "Wait", "1");
|
EMULATE_APP_DATA(chan_caller, 2, "Wait", "1");
|
||||||
EMULATE_APP_DATA(chan_callee, 1, "Wait", "1");
|
EMULATE_APP_DATA(chan_callee, 1, "Wait", "1");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "16,,ANSWER");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -860,8 +957,8 @@ AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_a)
|
||||||
ast_bridge_depart(chan_callee);
|
ast_bridge_depart(chan_callee);
|
||||||
APPEND_EVENT(chan_caller, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_callee));
|
APPEND_EVENT(chan_caller, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_callee));
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "16,,ANSWER");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -910,8 +1007,8 @@ AST_TEST_DEFINE(test_cel_dial_answer_twoparty_bridge_b)
|
||||||
ast_bridge_depart(chan_callee);
|
ast_bridge_depart(chan_callee);
|
||||||
APPEND_EVENT(chan_callee, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_caller));
|
APPEND_EVENT(chan_callee, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_caller));
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "16,,ANSWER");
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
|
||||||
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "16,,");
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -970,28 +1067,431 @@ AST_TEST_DEFINE(test_cel_dial_answer_multiparty)
|
||||||
|
|
||||||
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0));
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0));
|
||||||
do_sleep();
|
do_sleep();
|
||||||
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_TO_CONF, NULL, ast_channel_name(chan_bob), ast_channel_name(chan_david));
|
BRIDGE_TO_CONF(chan_charlie, chan_david, chan_bob, bridge);
|
||||||
|
|
||||||
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0));
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0));
|
||||||
do_sleep();
|
do_sleep();
|
||||||
APPEND_EVENT(chan_alice, AST_CEL_CONF_ENTER, NULL, NULL, NULL);
|
CONF_ENTER_EVENT(chan_alice, bridge);
|
||||||
|
|
||||||
ast_test_validate(test, 0 == ast_bridge_depart(chan_alice));
|
CONF_EXIT(chan_alice, bridge);
|
||||||
APPEND_EVENT(chan_alice, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
CONF_EXIT(chan_bob, bridge);
|
||||||
|
CONF_EXIT(chan_charlie, bridge);
|
||||||
|
CONF_EXIT(chan_david, bridge);
|
||||||
|
|
||||||
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "ANSWER");
|
||||||
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "ANSWER");
|
||||||
|
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
|
return AST_TEST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_TEST_DEFINE(test_cel_blind_transfer)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
|
||||||
|
struct ast_party_caller alice_caller = ALICE_CALLERID;
|
||||||
|
struct ast_party_caller bob_caller = BOB_CALLERID;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case TEST_INIT:
|
||||||
|
info->name = __func__;
|
||||||
|
info->category = TEST_CATEGORY;
|
||||||
|
info->summary = "Test blind transfers to an extension";
|
||||||
|
info->description =
|
||||||
|
"This test creates two channels, bridges them, and then"
|
||||||
|
" blind transfers the bridge to an extension.\n";
|
||||||
|
return AST_TEST_NOT_RUN;
|
||||||
|
case TEST_EXECUTE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bridge = ast_bridge_basic_new();
|
||||||
|
ast_test_validate(test, bridge != NULL);
|
||||||
|
|
||||||
|
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
|
||||||
|
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
|
||||||
|
|
||||||
|
ANSWER_NO_APP(chan_alice);
|
||||||
|
ANSWER_NO_APP(chan_bob);
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_bob, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge, chan_alice, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
|
||||||
|
|
||||||
|
BLINDTRANSFER_EVENT(chan_alice, bridge, "transfer_extension", "transfer_context");
|
||||||
|
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_alice));
|
||||||
|
|
||||||
|
ast_bridge_transfer_blind(1, chan_alice, "transfer_extension", "transfer_context", NULL, NULL);
|
||||||
|
|
||||||
ast_test_validate(test, 0 == ast_bridge_depart(chan_bob));
|
ast_test_validate(test, 0 == ast_bridge_depart(chan_bob));
|
||||||
APPEND_EVENT(chan_bob, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
ast_test_validate(test, 0 == ast_bridge_depart(chan_charlie));
|
|
||||||
APPEND_EVENT(chan_charlie, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
ast_test_validate(test, 0 == ast_bridge_depart(chan_david));
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
|
||||||
APPEND_EVENT(chan_david, AST_CEL_CONF_EXIT, NULL, NULL, NULL);
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "16,,ANSWER");
|
return AST_TEST_PASS;
|
||||||
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "16,,");
|
}
|
||||||
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "16,,ANSWER");
|
|
||||||
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "16,,");
|
AST_TEST_DEFINE(test_cel_attended_transfer_bridges_swap)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_fred, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_bridge *, bridge1, NULL, ao2_cleanup);
|
||||||
|
RAII_VAR(struct ast_bridge *, bridge2, NULL, ao2_cleanup);
|
||||||
|
struct ast_party_caller alice_caller = ALICE_CALLERID;
|
||||||
|
struct ast_party_caller bob_caller = BOB_CALLERID;
|
||||||
|
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
|
||||||
|
struct ast_party_caller fred_caller = ALICE_CALLERID;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case TEST_INIT:
|
||||||
|
info->name = __func__;
|
||||||
|
info->category = TEST_CATEGORY;
|
||||||
|
info->summary = "Test attended transfers between two pairs of bridged parties";
|
||||||
|
info->description =
|
||||||
|
"This test creates four channels, places each pair in"
|
||||||
|
" a bridge, and then attended transfers the bridges"
|
||||||
|
" together.\n";
|
||||||
|
return AST_TEST_NOT_RUN;
|
||||||
|
case TEST_EXECUTE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Create first set of bridged parties */
|
||||||
|
bridge1 = ast_bridge_basic_new();
|
||||||
|
ast_test_validate(test, bridge1 != NULL);
|
||||||
|
|
||||||
|
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
|
||||||
|
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
|
||||||
|
ANSWER_NO_APP(chan_alice);
|
||||||
|
ANSWER_NO_APP(chan_bob);
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_bob, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_alice, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
|
||||||
|
|
||||||
|
/* Create second set of bridged parties */
|
||||||
|
bridge2 = ast_bridge_basic_new();
|
||||||
|
ast_test_validate(test, bridge2 != NULL);
|
||||||
|
|
||||||
|
CREATE_FRED_CHANNEL(chan_fred, &fred_caller);
|
||||||
|
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
|
||||||
|
ANSWER_NO_APP(chan_fred);
|
||||||
|
ANSWER_NO_APP(chan_charlie);
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_charlie, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_fred, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_fred));
|
||||||
|
|
||||||
|
/* Perform attended transfer */
|
||||||
|
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_END, NULL, NULL, ast_channel_name(chan_alice));
|
||||||
|
|
||||||
|
ast_bridge_transfer_attended(chan_alice, chan_fred);
|
||||||
|
do_sleep();
|
||||||
|
BRIDGE_TO_CONF(chan_charlie, chan_fred, chan_bob, bridge2);
|
||||||
|
CONF_EXIT_EVENT(chan_fred, bridge2);
|
||||||
|
|
||||||
|
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_fred, bridge2);
|
||||||
|
|
||||||
|
CONF_EXIT(chan_bob, bridge2);
|
||||||
|
CONF_EXIT(chan_charlie, bridge2);
|
||||||
|
|
||||||
|
do_sleep();
|
||||||
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_fred, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
|
return AST_TEST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_TEST_DEFINE(test_cel_attended_transfer_bridges_merge)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_eve, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_fred, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_bridge *, bridge1, NULL, ao2_cleanup);
|
||||||
|
RAII_VAR(struct ast_bridge *, bridge2, NULL, ao2_cleanup);
|
||||||
|
RAII_VAR(struct ast_channel_snapshot *, eve_tmp_snapshot, NULL, ao2_cleanup);
|
||||||
|
struct ast_party_caller alice_caller = ALICE_CALLERID;
|
||||||
|
struct ast_party_caller bob_caller = BOB_CALLERID;
|
||||||
|
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
|
||||||
|
struct ast_party_caller david_caller = DAVID_CALLERID;
|
||||||
|
struct ast_party_caller eve_caller = EVE_CALLERID;
|
||||||
|
struct ast_party_caller fred_caller = EVE_CALLERID;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case TEST_INIT:
|
||||||
|
info->name = __func__;
|
||||||
|
info->category = TEST_CATEGORY;
|
||||||
|
info->summary = "Test attended transfers between two pairs of"
|
||||||
|
" bridged parties that results in a bridge merge";
|
||||||
|
info->description =
|
||||||
|
"This test creates six channels, places each triplet"
|
||||||
|
" in a bridge, and then attended transfers the bridges"
|
||||||
|
" together causing a bridge merge.\n";
|
||||||
|
return AST_TEST_NOT_RUN;
|
||||||
|
case TEST_EXECUTE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Create first set of bridged parties */
|
||||||
|
bridge1 = ast_bridge_basic_new();
|
||||||
|
ast_test_validate(test, bridge1 != NULL);
|
||||||
|
|
||||||
|
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
|
||||||
|
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
|
||||||
|
CREATE_DAVID_CHANNEL(chan_david, &david_caller);
|
||||||
|
ANSWER_NO_APP(chan_alice);
|
||||||
|
ANSWER_NO_APP(chan_bob);
|
||||||
|
ANSWER_NO_APP(chan_david);
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_bob, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_alice, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_david, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
BRIDGE_TO_CONF(chan_bob, chan_alice, chan_david, bridge1);
|
||||||
|
|
||||||
|
/* Create second set of bridged parties */
|
||||||
|
bridge2 = ast_bridge_basic_new();
|
||||||
|
ast_test_validate(test, bridge2 != NULL);
|
||||||
|
|
||||||
|
CREATE_FRED_CHANNEL(chan_fred, &fred_caller);
|
||||||
|
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
|
||||||
|
CREATE_EVE_CHANNEL(chan_eve, &eve_caller);
|
||||||
|
ANSWER_NO_APP(chan_fred);
|
||||||
|
ANSWER_NO_APP(chan_charlie);
|
||||||
|
ANSWER_NO_APP(chan_eve);
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_charlie, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_fred, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_fred));
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_eve, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
BRIDGE_TO_CONF(chan_charlie, chan_fred, chan_eve, bridge2);
|
||||||
|
|
||||||
|
/* Perform attended transfer */
|
||||||
|
CONF_EXIT_EVENT(chan_charlie, bridge2);
|
||||||
|
eve_tmp_snapshot = ast_channel_snapshot_create(chan_eve);
|
||||||
|
ast_bridge_transfer_attended(chan_alice, chan_fred);
|
||||||
|
do_sleep();
|
||||||
|
CONF_ENTER_EVENT(chan_charlie, bridge1);
|
||||||
|
|
||||||
|
/* Fred goes away */
|
||||||
|
CONF_EXIT_EVENT(chan_fred, bridge2);
|
||||||
|
CONF_EXIT_SNAPSHOT(eve_tmp_snapshot, bridge2);
|
||||||
|
CONF_ENTER_EVENT(chan_eve, bridge1);
|
||||||
|
|
||||||
|
/* Alice goes away */
|
||||||
|
CONF_EXIT_EVENT(chan_alice, bridge1);
|
||||||
|
|
||||||
|
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_fred, bridge2);
|
||||||
|
|
||||||
|
CONF_EXIT(chan_bob, bridge1);
|
||||||
|
CONF_EXIT(chan_charlie, bridge1);
|
||||||
|
CONF_EXIT(chan_david, bridge1);
|
||||||
|
CONF_EXIT(chan_eve, bridge1);
|
||||||
|
|
||||||
|
do_sleep();
|
||||||
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_fred, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_eve, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
|
return AST_TEST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_TEST_DEFINE(test_cel_attended_transfer_bridges_link)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_david, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_eve, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_fred, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_bridge *, bridge1, NULL, ao2_cleanup);
|
||||||
|
RAII_VAR(struct ast_bridge *, bridge2, NULL, ao2_cleanup);
|
||||||
|
RAII_VAR(struct ast_channel_snapshot *, eve_tmp_snapshot, NULL, ao2_cleanup);
|
||||||
|
struct ast_party_caller alice_caller = ALICE_CALLERID;
|
||||||
|
struct ast_party_caller bob_caller = BOB_CALLERID;
|
||||||
|
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
|
||||||
|
struct ast_party_caller david_caller = DAVID_CALLERID;
|
||||||
|
struct ast_party_caller eve_caller = EVE_CALLERID;
|
||||||
|
struct ast_party_caller fred_caller = EVE_CALLERID;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case TEST_INIT:
|
||||||
|
info->name = __func__;
|
||||||
|
info->category = TEST_CATEGORY;
|
||||||
|
info->summary = "Test attended transfers between two pairs of"
|
||||||
|
" bridged parties that results in a bridge merge";
|
||||||
|
info->description =
|
||||||
|
"This test creates six channels, places each triplet"
|
||||||
|
" in a bridge, and then attended transfers the bridges"
|
||||||
|
" together causing a bridge merge.\n";
|
||||||
|
return AST_TEST_NOT_RUN;
|
||||||
|
case TEST_EXECUTE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Create first set of bridged parties */
|
||||||
|
bridge1 = ast_bridge_base_new(AST_BRIDGE_CAPABILITY_1TO1MIX | AST_BRIDGE_CAPABILITY_NATIVE | AST_BRIDGE_CAPABILITY_MULTIMIX,
|
||||||
|
AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
|
||||||
|
| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_TRANSFER_PROHIBITED | AST_BRIDGE_FLAG_SMART);
|
||||||
|
ast_test_validate(test, bridge1 != NULL);
|
||||||
|
|
||||||
|
CREATE_ALICE_CHANNEL(chan_alice, &alice_caller);
|
||||||
|
CREATE_BOB_CHANNEL(chan_bob, &bob_caller);
|
||||||
|
CREATE_DAVID_CHANNEL(chan_david, &david_caller);
|
||||||
|
ANSWER_NO_APP(chan_alice);
|
||||||
|
ANSWER_NO_APP(chan_bob);
|
||||||
|
ANSWER_NO_APP(chan_david);
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_bob, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_alice, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
APPEND_EVENT(chan_bob, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_alice));
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge1, chan_david, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
BRIDGE_TO_CONF(chan_bob, chan_alice, chan_david, bridge1);
|
||||||
|
|
||||||
|
/* Create second set of bridged parties */
|
||||||
|
bridge2 = ast_bridge_basic_new();
|
||||||
|
ast_test_validate(test, bridge2 != NULL);
|
||||||
|
|
||||||
|
CREATE_FRED_CHANNEL(chan_fred, &fred_caller);
|
||||||
|
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
|
||||||
|
CREATE_EVE_CHANNEL(chan_eve, &eve_caller);
|
||||||
|
ANSWER_NO_APP(chan_fred);
|
||||||
|
ANSWER_NO_APP(chan_charlie);
|
||||||
|
ANSWER_NO_APP(chan_eve);
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_charlie, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_fred, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
APPEND_EVENT(chan_charlie, AST_CEL_BRIDGE_START, NULL, NULL, ast_channel_name(chan_fred));
|
||||||
|
|
||||||
|
ast_test_validate(test, 0 == ast_bridge_impart(bridge2, chan_eve, NULL, NULL, 0));
|
||||||
|
do_sleep();
|
||||||
|
BRIDGE_TO_CONF(chan_charlie, chan_fred, chan_eve, bridge2);
|
||||||
|
|
||||||
|
/* Perform attended transfer */
|
||||||
|
ast_bridge_transfer_attended(chan_alice, chan_fred);
|
||||||
|
do_sleep();
|
||||||
|
|
||||||
|
/* Append dummy event for the link channel ;1 start */
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
|
||||||
|
/* Append dummy event for the link channel ;2 start */
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
|
||||||
|
/* Append dummy event for the link channel ;2 answer */
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
|
||||||
|
ATTENDEDTRANSFER_BRIDGE(chan_alice, bridge1, chan_fred, bridge2);
|
||||||
|
|
||||||
|
/* Append dummy event for the link channel ;1 enter */
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
|
||||||
|
/* Append dummy events for the link channel ;2 enter and Alice's exit,
|
||||||
|
* must both be dummies since they're racing */
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
|
||||||
|
/* Append dummy events for the link channel ;1 answer and Fred's exit,
|
||||||
|
* must both be dummies since they're racing */
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
APPEND_DUMMY_EVENT();
|
||||||
|
|
||||||
|
CONF_EXIT(chan_bob, bridge1);
|
||||||
|
CONF_EXIT(chan_charlie, bridge2);
|
||||||
|
CONF_EXIT(chan_david, bridge1);
|
||||||
|
CONF_EXIT(chan_eve, bridge2);
|
||||||
|
|
||||||
|
do_sleep();
|
||||||
|
HANGUP_CHANNEL(chan_alice, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_bob, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_fred, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_david, AST_CAUSE_NORMAL, "");
|
||||||
|
HANGUP_CHANNEL(chan_eve, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
|
return AST_TEST_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_TEST_DEFINE(test_cel_dial_pickup)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_channel *, chan_caller, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_callee, NULL, safe_channel_release);
|
||||||
|
RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
|
||||||
|
struct ast_party_caller caller = ALICE_CALLERID;
|
||||||
|
struct ast_party_caller charlie_caller = CHARLIE_CALLERID;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case TEST_INIT:
|
||||||
|
info->name = __func__;
|
||||||
|
info->category = TEST_CATEGORY;
|
||||||
|
info->summary = "Test call pickup";
|
||||||
|
info->description =
|
||||||
|
"Test CEL records for a call that is\n"
|
||||||
|
"inbound to Asterisk, executes some dialplan, and\n"
|
||||||
|
"is picked up.\n";
|
||||||
|
return AST_TEST_NOT_RUN;
|
||||||
|
case TEST_EXECUTE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CREATE_ALICE_CHANNEL(chan_caller, &caller);
|
||||||
|
|
||||||
|
EMULATE_DIAL(chan_caller, CHANNEL_TECH_NAME "/Bob");
|
||||||
|
|
||||||
|
START_DIALED(chan_caller, chan_callee);
|
||||||
|
|
||||||
|
ast_channel_state_set(chan_caller, AST_STATE_RINGING);
|
||||||
|
|
||||||
|
CREATE_CHARLIE_CHANNEL(chan_charlie, &charlie_caller);
|
||||||
|
|
||||||
|
{
|
||||||
|
SCOPED_CHANNELLOCK(lock, chan_callee);
|
||||||
|
APPEND_EVENT(chan_callee, AST_CEL_PICKUP, NULL, NULL, ast_channel_name(chan_charlie));
|
||||||
|
ast_test_validate(test, 0 == ast_do_pickup(chan_charlie, chan_callee));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hang up the masqueraded zombie */
|
||||||
|
HANGUP_CHANNEL(chan_charlie, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
|
ast_channel_publish_dial(chan_caller, chan_callee, NULL, "ANSWER");
|
||||||
|
|
||||||
|
HANGUP_CHANNEL(chan_caller, AST_CAUSE_NORMAL, "ANSWER");
|
||||||
|
HANGUP_CHANNEL(chan_callee, AST_CAUSE_NORMAL, "");
|
||||||
|
|
||||||
return AST_TEST_PASS;
|
return AST_TEST_PASS;
|
||||||
}
|
}
|
||||||
|
@ -1022,25 +1522,9 @@ static struct ast_event *ao2_dup_event(const struct ast_event *event)
|
||||||
return event_dup;
|
return event_dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_expected_event(
|
static int append_event(struct ast_event *ev)
|
||||||
struct ast_channel *chan,
|
|
||||||
enum ast_cel_event_type type,
|
|
||||||
const char *userdefevname,
|
|
||||||
const char *extra, const char *peer)
|
|
||||||
{
|
{
|
||||||
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
|
||||||
RAII_VAR(struct ast_event *, ev, NULL, ast_free);
|
|
||||||
RAII_VAR(struct ast_event *, ao2_ev, NULL, ao2_cleanup);
|
RAII_VAR(struct ast_event *, ao2_ev, NULL, ao2_cleanup);
|
||||||
snapshot = ast_channel_snapshot_create(chan);
|
|
||||||
if (!snapshot) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ev = ast_cel_create_event(snapshot, type, userdefevname, extra, peer);
|
|
||||||
if (!ev) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ao2_ev = ao2_dup_event(ev);
|
ao2_ev = ao2_dup_event(ev);
|
||||||
if (!ao2_ev) {
|
if (!ao2_ev) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1050,6 +1534,49 @@ static int append_expected_event(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int append_dummy_event(void)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_event *, ev, NULL, ast_free);
|
||||||
|
RAII_VAR(struct ast_event *, ao2_ev, NULL, ao2_cleanup);
|
||||||
|
|
||||||
|
ev = ast_event_new(AST_EVENT_CUSTOM, AST_EVENT_IE_END);
|
||||||
|
if (!ev) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return append_event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int append_expected_event_snapshot(
|
||||||
|
struct ast_channel_snapshot *snapshot,
|
||||||
|
enum ast_cel_event_type type,
|
||||||
|
const char *userdefevname,
|
||||||
|
struct ast_json *extra, const char *peer)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_event *, ev, NULL, ast_free);
|
||||||
|
ev = ast_cel_create_event(snapshot, type, userdefevname, extra, peer);
|
||||||
|
if (!ev) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return append_event(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int append_expected_event(
|
||||||
|
struct ast_channel *chan,
|
||||||
|
enum ast_cel_event_type type,
|
||||||
|
const char *userdefevname,
|
||||||
|
struct ast_json *extra, const char *peer)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
||||||
|
snapshot = ast_channel_snapshot_create(chan);
|
||||||
|
if (!snapshot) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return append_expected_event_snapshot(snapshot, type, userdefevname, extra, peer);
|
||||||
|
}
|
||||||
|
|
||||||
ast_mutex_t sync_lock;
|
ast_mutex_t sync_lock;
|
||||||
ast_cond_t sync_out;
|
ast_cond_t sync_out;
|
||||||
|
|
||||||
|
@ -1149,19 +1676,24 @@ static int match_ie_val(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int events_are_equal(struct ast_event *event1, struct ast_event *event2)
|
static int events_are_equal(struct ast_event *received, struct ast_event *expected)
|
||||||
{
|
{
|
||||||
struct ast_event_iterator iterator;
|
struct ast_event_iterator iterator;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
for (res = ast_event_iterator_init(&iterator, event1); !res; res = ast_event_iterator_next(&iterator)) {
|
if (ast_event_get_type(expected) == AST_EVENT_CUSTOM) {
|
||||||
|
/* this event is flagged as a wildcard match */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (res = ast_event_iterator_init(&iterator, received); !res; res = ast_event_iterator_next(&iterator)) {
|
||||||
/* XXX ignore sec/usec for now */
|
/* XXX ignore sec/usec for now */
|
||||||
/* ignore EID */
|
/* ignore EID */
|
||||||
int ie_type = ast_event_iterator_get_ie_type(&iterator);
|
int ie_type = ast_event_iterator_get_ie_type(&iterator);
|
||||||
if (ie_type != AST_EVENT_IE_CEL_EVENT_TIME_USEC
|
if (ie_type != AST_EVENT_IE_CEL_EVENT_TIME_USEC
|
||||||
&& ie_type != AST_EVENT_IE_EID
|
&& ie_type != AST_EVENT_IE_EID
|
||||||
&& ie_type != AST_EVENT_IE_CEL_EVENT_TIME
|
&& ie_type != AST_EVENT_IE_CEL_EVENT_TIME
|
||||||
&& !match_ie_val(event1, event2, ie_type)) {
|
&& !match_ie_val(received, expected, ie_type)) {
|
||||||
ast_log(LOG_ERROR, "Failed matching on field %s\n", ast_event_get_ie_type_name(ie_type));
|
ast_log(LOG_ERROR, "Failed matching on field %s\n", ast_event_get_ie_type_name(ie_type));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1244,8 +1776,8 @@ static int check_events(struct ao2_container *local_expected, struct ao2_contain
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (debug) {
|
if (debug) {
|
||||||
ast_log(LOG_ERROR, "Compared events successfully\n");
|
ast_log(LOG_ERROR, "Compared events successfully%s\n", ast_event_get_type(ex_event) == AST_EVENT_CUSTOM ? " (wildcard match)" : "");
|
||||||
dump_event(ex_event);
|
dump_event(rx_event);
|
||||||
}
|
}
|
||||||
ao2_cleanup(rx_event);
|
ao2_cleanup(rx_event);
|
||||||
ao2_cleanup(ex_event);
|
ao2_cleanup(ex_event);
|
||||||
|
@ -1370,6 +1902,13 @@ static int unload_module(void)
|
||||||
AST_TEST_UNREGISTER(test_cel_dial_answer_twoparty_bridge_b);
|
AST_TEST_UNREGISTER(test_cel_dial_answer_twoparty_bridge_b);
|
||||||
AST_TEST_UNREGISTER(test_cel_dial_answer_multiparty);
|
AST_TEST_UNREGISTER(test_cel_dial_answer_multiparty);
|
||||||
|
|
||||||
|
AST_TEST_UNREGISTER(test_cel_blind_transfer);
|
||||||
|
AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_swap);
|
||||||
|
AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_merge);
|
||||||
|
AST_TEST_UNREGISTER(test_cel_attended_transfer_bridges_link);
|
||||||
|
|
||||||
|
AST_TEST_UNREGISTER(test_cel_dial_pickup);
|
||||||
|
|
||||||
ast_channel_unregister(&test_cel_chan_tech);
|
ast_channel_unregister(&test_cel_chan_tech);
|
||||||
|
|
||||||
ao2_cleanup(cel_test_config);
|
ao2_cleanup(cel_test_config);
|
||||||
|
@ -1405,6 +1944,9 @@ static int load_module(void)
|
||||||
cel_test_config->events |= 1<<AST_CEL_BRIDGE_TO_CONF;
|
cel_test_config->events |= 1<<AST_CEL_BRIDGE_TO_CONF;
|
||||||
cel_test_config->events |= 1<<AST_CEL_CONF_ENTER;
|
cel_test_config->events |= 1<<AST_CEL_CONF_ENTER;
|
||||||
cel_test_config->events |= 1<<AST_CEL_CONF_EXIT;
|
cel_test_config->events |= 1<<AST_CEL_CONF_EXIT;
|
||||||
|
cel_test_config->events |= 1<<AST_CEL_BLINDTRANSFER;
|
||||||
|
cel_test_config->events |= 1<<AST_CEL_ATTENDEDTRANSFER;
|
||||||
|
cel_test_config->events |= 1<<AST_CEL_PICKUP;
|
||||||
|
|
||||||
ast_channel_register(&test_cel_chan_tech);
|
ast_channel_register(&test_cel_chan_tech);
|
||||||
|
|
||||||
|
@ -1430,6 +1972,13 @@ static int load_module(void)
|
||||||
AST_TEST_REGISTER(test_cel_dial_answer_twoparty_bridge_b);
|
AST_TEST_REGISTER(test_cel_dial_answer_twoparty_bridge_b);
|
||||||
AST_TEST_REGISTER(test_cel_dial_answer_multiparty);
|
AST_TEST_REGISTER(test_cel_dial_answer_multiparty);
|
||||||
|
|
||||||
|
AST_TEST_REGISTER(test_cel_blind_transfer);
|
||||||
|
AST_TEST_REGISTER(test_cel_attended_transfer_bridges_swap);
|
||||||
|
AST_TEST_REGISTER(test_cel_attended_transfer_bridges_merge);
|
||||||
|
AST_TEST_REGISTER(test_cel_attended_transfer_bridges_link);
|
||||||
|
|
||||||
|
AST_TEST_REGISTER(test_cel_dial_pickup);
|
||||||
|
|
||||||
/* ast_test_register_* has to happen after AST_TEST_REGISTER */
|
/* ast_test_register_* has to happen after AST_TEST_REGISTER */
|
||||||
/* Verify received vs expected events and clean things up after every test */
|
/* Verify received vs expected events and clean things up after every test */
|
||||||
ast_test_register_init(TEST_CATEGORY, test_cel_init_cb);
|
ast_test_register_init(TEST_CATEGORY, test_cel_init_cb);
|
||||||
|
|
Loading…
Reference in New Issue