123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308 |
- /*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2013, Digium, Inc.
- *
- * Kinsey Moore <kmoore@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
- /*! \file
- *
- * \brief Stasis Messages and Data Types for Bridge Objects
- *
- * \author Kinsey Moore <kmoore@digium.com>
- */
- /*** MODULEINFO
- <support_level>core</support_level>
- ***/
- #include "asterisk.h"
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
- #include "asterisk/astobj2.h"
- #include "asterisk/stasis.h"
- #include "asterisk/stasis_cache_pattern.h"
- #include "asterisk/channel.h"
- #include "asterisk/stasis_bridges.h"
- #include "asterisk/stasis_channels.h"
- #include "asterisk/bridge.h"
- #include "asterisk/bridge_technology.h"
- /* The container of channel snapshots in a bridge snapshot should always be
- equivalent to a linked list; otherwise things (like CDRs) that depend on some
- consistency in the ordering of channels in a bridge will break. */
- #define SNAPSHOT_CHANNELS_BUCKETS 1
- /*** DOCUMENTATION
- <managerEvent language="en_US" name="BlindTransfer">
- <managerEventInstance class="EVENT_FLAG_CALL">
- <synopsis>Raised when a blind transfer is complete.</synopsis>
- <syntax>
- <parameter name="Result">
- <para>Indicates if the transfer was successful or if it failed.</para>
- <enumlist>
- <enum name="Fail"><para>An internal error occurred.</para></enum>
- <enum name="Invalid"><para>Invalid configuration for transfer (e.g. Not bridged)</para></enum>
- <enum name="Not Permitted"><para>Bridge does not permit transfers</para></enum>
- <enum name="Success"><para>Transfer completed successfully</para></enum>
- </enumlist>
- <note><para>A result of <literal>Success</literal> does not necessarily mean that a target was succesfully
- contacted. It means that a party was succesfully placed into the dialplan at the expected location.</para></note>
- </parameter>
- <channel_snapshot prefix="Transferer"/>
- <channel_snapshot prefix="Transferee"/>
- <bridge_snapshot/>
- <parameter name="IsExternal">
- <para>Indicates if the transfer was performed outside of Asterisk. For instance,
- a channel protocol native transfer is external. A DTMF transfer is internal.</para>
- <enumlist>
- <enum name="Yes" />
- <enum name="No" />
- </enumlist>
- </parameter>
- <parameter name="Context">
- <para>Destination context for the blind transfer.</para>
- </parameter>
- <parameter name="Extension">
- <para>Destination extension for the blind transfer.</para>
- </parameter>
- </syntax>
- <see-also>
- <ref type="manager">BlindTransfer</ref>
- </see-also>
- </managerEventInstance>
- </managerEvent>
- <managerEvent language="en_US" name="AttendedTransfer">
- <managerEventInstance class="EVENT_FLAG_CALL">
- <synopsis>Raised when an attended transfer is complete.</synopsis>
- <syntax>
- <xi:include xpointer="xpointer(docs/managerEvent[@name='BlindTransfer']/managerEventInstance/syntax/parameter[@name='Result'])" />
- <channel_snapshot prefix="OrigTransferer"/>
- <bridge_snapshot prefix="Orig"/>
- <channel_snapshot prefix="SecondTransferer"/>
- <bridge_snapshot prefix="Second"/>
- <parameter name="DestType">
- <para>Indicates the method by which the attended transfer completed.</para>
- <enumlist>
- <enum name="Bridge"><para>The transfer was accomplished by merging two bridges into one.</para></enum>
- <enum name="App"><para>The transfer was accomplished by having a channel or bridge run a dialplan application.</para></enum>
- <enum name="Link"><para>The transfer was accomplished by linking two bridges together using a local channel pair.</para></enum>
- <enum name="Threeway"><para>The transfer was accomplished by placing all parties into a threeway call.</para></enum>
- <enum name="Fail"><para>The transfer failed.</para></enum>
- </enumlist>
- </parameter>
- <parameter name="DestBridgeUniqueid">
- <para>Indicates the surviving bridge when bridges were merged to complete the transfer</para>
- <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Bridge</literal> or <literal>Threeway</literal></para></note>
- </parameter>
- <parameter name="DestApp">
- <para>Indicates the application that is running when the transfer completes</para>
- <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>App</literal></para></note>
- </parameter>
- <channel_snapshot prefix="LocalOne"/>
- <channel_snapshot prefix="LocalTwo"/>
- <parameter name="DestTransfererChannel">
- <para>The name of the surviving transferer channel when a transfer results in a threeway call</para>
- <note><para>This header is only present when <replaceable>DestType</replaceable> is <literal>Threeway</literal></para></note>
- </parameter>
- <channel_snapshot prefix="Transferee" />
- </syntax>
- <description>
- <para>The headers in this event attempt to describe all the major details of the attended transfer. The two transferer channels
- and the two bridges are determined based on their chronological establishment. So consider that Alice calls Bob, and then Alice
- transfers the call to Voicemail. The transferer and bridge headers would be arranged as follows:</para>
- <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
- <para> <replaceable>OrigBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
- <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
- <para> <replaceable>SecondBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
- <para>Now consider if the order were reversed; instead of having Alice call Bob and transfer him to Voicemail, Alice instead
- calls her Voicemail and transfers that to Bob. The transferer and bridge headers would be arranged as follows:</para>
- <para> <replaceable>OrigTransfererChannel</replaceable>: Alice's channel that called Voicemail.</para>
- <para> <replaceable>OrigBridgeUniqueid</replaceable>: Not present, since a call to Voicemail has no bridge.</para>
- <para> <replaceable>SecondTransfererChannel</replaceable>: Alice's channel in the bridge with Bob.</para>
- <para> <replaceable>SecondBridgeUniqueid</replaceable>: The bridge between Alice and Bob.</para>
- </description>
- <see-also>
- <ref type="manager">AtxFer</ref>
- </see-also>
- </managerEventInstance>
- </managerEvent>
- ***/
- static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize);
- static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *message);
- static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize);
- static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *message);
- static struct ast_json *ast_channel_entered_bridge_to_json(
- struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize);
- static struct ast_json *ast_channel_left_bridge_to_json(
- struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize);
- static struct ast_json *ast_bridge_merge_message_to_json(
- struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize);
- static struct stasis_cp_all *bridge_cache_all;
- /*!
- * @{ \brief Define bridge message types.
- */
- STASIS_MESSAGE_TYPE_DEFN(ast_bridge_snapshot_type);
- STASIS_MESSAGE_TYPE_DEFN(ast_bridge_merge_message_type,
- .to_json = ast_bridge_merge_message_to_json);
- STASIS_MESSAGE_TYPE_DEFN(ast_channel_entered_bridge_type,
- .to_json = ast_channel_entered_bridge_to_json);
- STASIS_MESSAGE_TYPE_DEFN(ast_channel_left_bridge_type,
- .to_json = ast_channel_left_bridge_to_json);
- STASIS_MESSAGE_TYPE_DEFN(ast_blind_transfer_type,
- .to_json = blind_transfer_to_json,
- .to_ami = blind_transfer_to_ami);
- STASIS_MESSAGE_TYPE_DEFN(ast_attended_transfer_type,
- .to_json = attended_transfer_to_json,
- .to_ami = attended_transfer_to_ami);
- /*! @} */
- struct stasis_cache *ast_bridge_cache(void)
- {
- return stasis_cp_all_cache(bridge_cache_all);
- }
- struct stasis_topic *ast_bridge_topic_all(void)
- {
- return stasis_cp_all_topic(bridge_cache_all);
- }
- struct stasis_topic *ast_bridge_topic_all_cached(void)
- {
- return stasis_cp_all_topic_cached(bridge_cache_all);
- }
- int bridge_topics_init(struct ast_bridge *bridge)
- {
- if (ast_strlen_zero(bridge->uniqueid)) {
- ast_log(LOG_ERROR, "Bridge id initialization required\n");
- return -1;
- }
- bridge->topics = stasis_cp_single_create(bridge_cache_all,
- bridge->uniqueid);
- if (!bridge->topics) {
- return -1;
- }
- return 0;
- }
- struct stasis_topic *ast_bridge_topic(struct ast_bridge *bridge)
- {
- if (!bridge) {
- return ast_bridge_topic_all();
- }
- return stasis_cp_single_topic(bridge->topics);
- }
- struct stasis_topic *ast_bridge_topic_cached(struct ast_bridge *bridge)
- {
- if (!bridge) {
- return ast_bridge_topic_all_cached();
- }
- return stasis_cp_single_topic_cached(bridge->topics);
- }
- /*! \brief Destructor for bridge snapshots */
- static void bridge_snapshot_dtor(void *obj)
- {
- struct ast_bridge_snapshot *snapshot = obj;
- ast_string_field_free_memory(snapshot);
- ao2_cleanup(snapshot->channels);
- snapshot->channels = NULL;
- }
- struct ast_bridge_snapshot *ast_bridge_snapshot_create(struct ast_bridge *bridge)
- {
- struct ast_bridge_snapshot *snapshot;
- struct ast_bridge_channel *bridge_channel;
- snapshot = ao2_alloc_options(sizeof(*snapshot), bridge_snapshot_dtor,
- AO2_ALLOC_OPT_LOCK_NOLOCK);
- if (!snapshot) {
- return NULL;
- }
- if (ast_string_field_init(snapshot, 128)
- || ast_string_field_init_extended(snapshot, video_source_id)) {
- ao2_ref(snapshot, -1);
- return NULL;
- }
- snapshot->channels = ast_str_container_alloc(SNAPSHOT_CHANNELS_BUCKETS);
- if (!snapshot->channels) {
- ao2_ref(snapshot, -1);
- return NULL;
- }
- AST_LIST_TRAVERSE(&bridge->channels, bridge_channel, entry) {
- if (ast_str_container_add(snapshot->channels,
- ast_channel_uniqueid(bridge_channel->chan))) {
- ao2_ref(snapshot, -1);
- return NULL;
- }
- }
- ast_string_field_set(snapshot, uniqueid, bridge->uniqueid);
- ast_string_field_set(snapshot, technology, bridge->technology->name);
- ast_string_field_set(snapshot, subclass, bridge->v_table->name);
- ast_string_field_set(snapshot, creator, bridge->creator);
- ast_string_field_set(snapshot, name, bridge->name);
- snapshot->feature_flags = bridge->feature_flags;
- snapshot->capabilities = bridge->technology->capabilities;
- snapshot->num_channels = bridge->num_channels;
- snapshot->num_active = bridge->num_active;
- snapshot->video_mode = bridge->softmix.video_mode.mode;
- if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_SINGLE_SRC
- && bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc) {
- ast_string_field_set(snapshot, video_source_id,
- ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.single_src_data.chan_vsrc));
- } else if (snapshot->video_mode == AST_BRIDGE_VIDEO_MODE_TALKER_SRC
- && bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc) {
- ast_string_field_set(snapshot, video_source_id,
- ast_channel_uniqueid(bridge->softmix.video_mode.mode_data.talker_src_data.chan_vsrc));
- }
- return snapshot;
- }
- void ast_bridge_publish_state(struct ast_bridge *bridge)
- {
- struct ast_bridge_snapshot *snapshot;
- struct stasis_message *msg;
- if (!ast_bridge_snapshot_type()) {
- return;
- }
- ast_assert(bridge != NULL);
- snapshot = ast_bridge_snapshot_create(bridge);
- if (!snapshot) {
- return;
- }
- msg = stasis_message_create(ast_bridge_snapshot_type(), snapshot);
- ao2_ref(snapshot, -1);
- if (!msg) {
- return;
- }
- stasis_publish(ast_bridge_topic(bridge), msg);
- ao2_ref(msg, -1);
- }
- static void bridge_publish_state_from_blob(struct ast_bridge *bridge,
- struct ast_bridge_blob *obj)
- {
- struct stasis_message *msg;
- ast_assert(obj != NULL);
- msg = stasis_message_create(ast_bridge_snapshot_type(), obj->bridge);
- if (!msg) {
- return;
- }
- stasis_publish(ast_bridge_topic(bridge), msg);
- ao2_ref(msg, -1);
- }
- /*! \brief Destructor for bridge merge messages */
- static void bridge_merge_message_dtor(void *obj)
- {
- struct ast_bridge_merge_message *msg = obj;
- ao2_cleanup(msg->to);
- msg->to = NULL;
- ao2_cleanup(msg->from);
- msg->from = NULL;
- }
- /*! \brief Bridge merge message creation helper */
- static struct ast_bridge_merge_message *bridge_merge_message_create(struct ast_bridge *to, struct ast_bridge *from)
- {
- struct ast_bridge_merge_message *msg;
- msg = ao2_alloc(sizeof(*msg), bridge_merge_message_dtor);
- if (!msg) {
- return NULL;
- }
- msg->to = ast_bridge_snapshot_create(to);
- msg->from = ast_bridge_snapshot_create(from);
- if (!msg->to || !msg->from) {
- ao2_ref(msg, -1);
- return NULL;
- }
- return msg;
- }
- static struct ast_json *ast_bridge_merge_message_to_json(
- struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_bridge_merge_message *merge = stasis_message_data(msg);
- struct ast_json *json_bridge_to = ast_bridge_snapshot_to_json(merge->to, sanitize);
- struct ast_json *json_bridge_from = ast_bridge_snapshot_to_json(merge->from, sanitize);
- if (!json_bridge_to || !json_bridge_from) {
- ast_json_unref(json_bridge_to);
- ast_json_unref(json_bridge_from);
- return NULL;
- }
- return ast_json_pack("{s: s, s: o, s: o, s: o}",
- "type", "BridgeMerged",
- "timestamp", ast_json_timeval(*stasis_message_timestamp(msg), NULL),
- "bridge", json_bridge_to,
- "bridge_from", json_bridge_from);
- }
- void ast_bridge_publish_merge(struct ast_bridge *to, struct ast_bridge *from)
- {
- struct ast_bridge_merge_message *merge_msg;
- struct stasis_message *msg;
- if (!ast_bridge_merge_message_type()) {
- return;
- }
- ast_assert(to != NULL);
- ast_assert(from != NULL);
- merge_msg = bridge_merge_message_create(to, from);
- if (!merge_msg) {
- return;
- }
- msg = stasis_message_create(ast_bridge_merge_message_type(), merge_msg);
- ao2_ref(merge_msg, -1);
- if (!msg) {
- return;
- }
- stasis_publish(ast_bridge_topic_all(), msg);
- ao2_ref(msg, -1);
- }
- static void bridge_blob_dtor(void *obj)
- {
- struct ast_bridge_blob *event = obj;
- ao2_cleanup(event->bridge);
- event->bridge = NULL;
- ao2_cleanup(event->channel);
- event->channel = NULL;
- ast_json_unref(event->blob);
- event->blob = NULL;
- }
- struct stasis_message *ast_bridge_blob_create(
- struct stasis_message_type *message_type,
- struct ast_bridge *bridge,
- struct ast_channel *chan,
- struct ast_json *blob)
- {
- struct ast_bridge_blob *obj;
- struct stasis_message *msg;
- if (!message_type) {
- return NULL;
- }
- obj = ao2_alloc(sizeof(*obj), bridge_blob_dtor);
- if (!obj) {
- return NULL;
- }
- if (bridge) {
- obj->bridge = ast_bridge_snapshot_create(bridge);
- if (obj->bridge == NULL) {
- ao2_ref(obj, -1);
- return NULL;
- }
- }
- if (chan) {
- obj->channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
- if (obj->channel == NULL) {
- ao2_ref(obj, -1);
- return NULL;
- }
- }
- if (blob) {
- obj->blob = ast_json_ref(blob);
- }
- msg = stasis_message_create(message_type, obj);
- ao2_ref(obj, -1);
- return msg;
- }
- void ast_bridge_publish_enter(struct ast_bridge *bridge, struct ast_channel *chan,
- struct ast_channel *swap)
- {
- struct stasis_message *msg;
- struct ast_json *blob = NULL;
- if (swap) {
- blob = ast_json_pack("{s: s}", "swap", ast_channel_uniqueid(swap));
- if (!blob) {
- return;
- }
- }
- msg = ast_bridge_blob_create(ast_channel_entered_bridge_type(), bridge, chan, blob);
- ast_json_unref(blob);
- if (!msg) {
- return;
- }
- /* enter blob first, then state */
- stasis_publish(ast_bridge_topic(bridge), msg);
- bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
- ao2_ref(msg, -1);
- }
- void ast_bridge_publish_leave(struct ast_bridge *bridge, struct ast_channel *chan)
- {
- struct stasis_message *msg;
- msg = ast_bridge_blob_create(ast_channel_left_bridge_type(), bridge, chan, NULL);
- if (!msg) {
- return;
- }
- /* state first, then leave blob (opposite of enter, preserves nesting of events) */
- bridge_publish_state_from_blob(bridge, stasis_message_data(msg));
- stasis_publish(ast_bridge_topic(bridge), msg);
- ao2_ref(msg, -1);
- }
- static struct ast_json *simple_bridge_channel_event(
- const char *type,
- struct ast_bridge_snapshot *bridge_snapshot,
- struct ast_channel_snapshot *channel_snapshot,
- const struct timeval *tv,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_json *json_bridge = ast_bridge_snapshot_to_json(bridge_snapshot, sanitize);
- struct ast_json *json_channel = ast_channel_snapshot_to_json(channel_snapshot, sanitize);
- if (!json_bridge || !json_channel) {
- ast_json_unref(json_bridge);
- ast_json_unref(json_channel);
- return NULL;
- }
- return ast_json_pack("{s: s, s: o, s: o, s: o}",
- "type", type,
- "timestamp", ast_json_timeval(*tv, NULL),
- "bridge", json_bridge,
- "channel", json_channel);
- }
- struct ast_json *ast_channel_entered_bridge_to_json(
- struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_bridge_blob *obj = stasis_message_data(msg);
- return simple_bridge_channel_event("ChannelEnteredBridge", obj->bridge,
- obj->channel, stasis_message_timestamp(msg), sanitize);
- }
- struct ast_json *ast_channel_left_bridge_to_json(
- struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_bridge_blob *obj = stasis_message_data(msg);
- return simple_bridge_channel_event("ChannelLeftBridge", obj->bridge,
- obj->channel, stasis_message_timestamp(msg), sanitize);
- }
- static struct ast_json *container_to_json_array(struct ao2_container *items,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_json *json_items = ast_json_array_create();
- char *item;
- struct ao2_iterator it;
- if (!json_items) {
- return NULL;
- }
- for (it = ao2_iterator_init(items, 0);
- (item = ao2_iterator_next(&it)); ao2_cleanup(item)) {
- if (sanitize && sanitize->channel_id && sanitize->channel_id(item)) {
- continue;
- }
- if (ast_json_array_append(json_items, ast_json_string_create(item))) {
- ao2_cleanup(item);
- ao2_iterator_destroy(&it);
- ast_json_unref(json_items);
- return NULL;
- }
- }
- ao2_iterator_destroy(&it);
- return json_items;
- }
- static const char *capability2str(uint32_t capabilities)
- {
- if (capabilities & AST_BRIDGE_CAPABILITY_HOLDING) {
- return "holding";
- } else {
- return "mixing";
- }
- }
- struct ast_json *ast_bridge_snapshot_to_json(
- const struct ast_bridge_snapshot *snapshot,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_json *json_bridge;
- struct ast_json *json_channels;
- if (snapshot == NULL) {
- return NULL;
- }
- json_channels = container_to_json_array(snapshot->channels, sanitize);
- if (!json_channels) {
- return NULL;
- }
- json_bridge = ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: s, s: o, s: s}",
- "id", snapshot->uniqueid,
- "technology", snapshot->technology,
- "bridge_type", capability2str(snapshot->capabilities),
- "bridge_class", snapshot->subclass,
- "creator", snapshot->creator,
- "name", snapshot->name,
- "channels", json_channels,
- "video_mode", ast_bridge_video_mode_to_string(snapshot->video_mode));
- if (!json_bridge) {
- return NULL;
- }
- if (snapshot->video_mode != AST_BRIDGE_VIDEO_MODE_NONE
- && !ast_strlen_zero(snapshot->video_source_id)) {
- ast_json_object_set(json_bridge, "video_source_id",
- ast_json_string_create(snapshot->video_source_id));
- }
- return json_bridge;
- }
- /*!
- * \internal
- * \brief Allocate the fields of an \ref ast_bridge_channel_snapshot_pair.
- *
- * \param pair A bridge and channel to get snapshots of
- * \param[out] snapshot_pair An allocated snapshot pair.
- * \retval 0 Success
- * \retval non-zero Failure
- */
- static int bridge_channel_snapshot_pair_init(struct ast_channel *channel, struct ast_bridge *bridge,
- struct ast_bridge_channel_snapshot_pair *snapshot_pair)
- {
- if (bridge) {
- ast_bridge_lock(bridge);
- snapshot_pair->bridge_snapshot = ast_bridge_snapshot_create(bridge);
- ast_bridge_unlock(bridge);
- if (!snapshot_pair->bridge_snapshot) {
- return -1;
- }
- }
- snapshot_pair->channel_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(channel));
- if (!snapshot_pair->channel_snapshot) {
- return -1;
- }
- return 0;
- }
- /*!
- * \internal
- * \brief Free the fields of an \ref ast_bridge_channel_snapshot_pair.
- *
- * \param pair The snapshot pair whose fields are to be cleaned up
- */
- static void bridge_channel_snapshot_pair_cleanup(struct ast_bridge_channel_snapshot_pair *pair)
- {
- ao2_cleanup(pair->bridge_snapshot);
- ao2_cleanup(pair->channel_snapshot);
- }
- static const char *result_strs[] = {
- [AST_BRIDGE_TRANSFER_FAIL] = "Fail",
- [AST_BRIDGE_TRANSFER_INVALID] = "Invalid",
- [AST_BRIDGE_TRANSFER_NOT_PERMITTED] = "Not Permitted",
- [AST_BRIDGE_TRANSFER_SUCCESS] = "Success",
- };
- static struct ast_json *blind_transfer_to_json(struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
- struct ast_json *json_transferer;
- struct ast_json *json_transferee = NULL;
- struct ast_json *out;
- struct ast_json *json_replace = NULL;
- const struct timeval *tv = stasis_message_timestamp(msg);
- json_transferer = ast_channel_snapshot_to_json(transfer_msg->transferer, sanitize);
- if (!json_transferer) {
- return NULL;
- }
- if (transfer_msg->transferee) {
- json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
- if (!json_transferee) {
- ast_json_unref(json_transferer);
- return NULL;
- }
- }
- if (transfer_msg->replace_channel) {
- json_replace = ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize);
- if (!json_replace) {
- ast_json_unref(json_transferee);
- ast_json_unref(json_transferer);
- return NULL;
- }
- }
- out = ast_json_pack("{s: s, s: o, s: o, s: s, s: s, s: s, s: o}",
- "type", "BridgeBlindTransfer",
- "timestamp", ast_json_timeval(*tv, NULL),
- "channel", json_transferer,
- "exten", transfer_msg->exten,
- "context", transfer_msg->context,
- "result", result_strs[transfer_msg->result],
- "is_external", ast_json_boolean(transfer_msg->is_external));
- if (!out) {
- ast_json_unref(json_transferee);
- ast_json_unref(json_replace);
- return NULL;
- }
- if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
- ast_json_unref(out);
- ast_json_unref(json_replace);
- return NULL;
- }
- if (json_replace && ast_json_object_set(out, "replace_channel", json_replace)) {
- ast_json_unref(out);
- return NULL;
- }
- if (transfer_msg->bridge) {
- struct ast_json *json_bridge = ast_bridge_snapshot_to_json(
- transfer_msg->bridge, sanitize);
- if (!json_bridge || ast_json_object_set(out, "bridge", json_bridge)) {
- ast_json_unref(out);
- return NULL;
- }
- }
- return out;
- }
- static struct ast_manager_event_blob *blind_transfer_to_ami(struct stasis_message *msg)
- {
- RAII_VAR(struct ast_str *, transferer_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, bridge_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
- struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
- if (!transfer_msg) {
- return NULL;
- }
- transferer_state = ast_manager_build_channel_state_string_prefix(
- transfer_msg->transferer, "Transferer");
- if (!transferer_state) {
- return NULL;
- }
- if (transfer_msg->bridge) {
- bridge_state = ast_manager_build_bridge_state_string(transfer_msg->bridge);
- if (!bridge_state) {
- return NULL;
- }
- }
- if (transfer_msg->transferee) {
- transferee_state = ast_manager_build_channel_state_string_prefix(
- transfer_msg->transferee, "Transferee");
- if (!transferee_state) {
- return NULL;
- }
- }
- return ast_manager_event_blob_create(EVENT_FLAG_CALL, "BlindTransfer",
- "Result: %s\r\n"
- "%s"
- "%s"
- "%s"
- "IsExternal: %s\r\n"
- "Context: %s\r\n"
- "Extension: %s\r\n",
- result_strs[transfer_msg->result],
- ast_str_buffer(transferer_state),
- transferee_state ? ast_str_buffer(transferee_state) : "",
- bridge_state ? ast_str_buffer(bridge_state) : "",
- transfer_msg->is_external ? "Yes" : "No",
- transfer_msg->context,
- transfer_msg->exten);
- }
- static void blind_transfer_dtor(void *obj)
- {
- struct ast_blind_transfer_message *msg = obj;
- ao2_cleanup(msg->transferer);
- ao2_cleanup(msg->bridge);
- ao2_cleanup(msg->transferee);
- ao2_cleanup(msg->replace_channel);
- }
- struct ast_blind_transfer_message *ast_blind_transfer_message_create(int is_external,
- struct ast_channel *transferer, const char *exten, const char *context)
- {
- struct ast_blind_transfer_message *msg;
- msg = ao2_alloc(sizeof(*msg), blind_transfer_dtor);
- if (!msg) {
- return NULL;
- }
- msg->transferer = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferer));
- if (!msg->transferer) {
- ao2_cleanup(msg);
- return NULL;
- }
- msg->is_external = is_external;
- ast_copy_string(msg->context, context, sizeof(msg->context));
- ast_copy_string(msg->exten, exten, sizeof(msg->exten));
- return msg;
- }
- void ast_bridge_publish_blind_transfer(struct ast_blind_transfer_message *transfer_message)
- {
- struct stasis_message *stasis;
- stasis = stasis_message_create(ast_blind_transfer_type(), transfer_message);
- if (!stasis) {
- return;
- }
- stasis_publish(ast_bridge_topic_all(), stasis);
- ao2_cleanup(stasis);
- }
- static struct ast_json *attended_transfer_to_json(struct stasis_message *msg,
- const struct stasis_message_sanitizer *sanitize)
- {
- struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
- RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
- struct ast_json *json_transferer1, *json_transferer2, *json_bridge, *json_channel;
- struct ast_json *json_transferee = NULL, *json_target = NULL;
- const struct timeval *tv = stasis_message_timestamp(msg);
- int res = 0;
- json_transferer1 = ast_channel_snapshot_to_json(transfer_msg->to_transferee.channel_snapshot, sanitize);
- if (!json_transferer1) {
- return NULL;
- }
- json_transferer2 = ast_channel_snapshot_to_json(transfer_msg->to_transfer_target.channel_snapshot, sanitize);
- if (!json_transferer2) {
- ast_json_unref(json_transferer1);
- return NULL;
- }
- if (transfer_msg->transferee) {
- json_transferee = ast_channel_snapshot_to_json(transfer_msg->transferee, sanitize);
- if (!json_transferee) {
- ast_json_unref(json_transferer2);
- ast_json_unref(json_transferer1);
- return NULL;
- }
- }
- if (transfer_msg->target) {
- json_target = ast_channel_snapshot_to_json(transfer_msg->target, sanitize);
- if (!json_target) {
- ast_json_unref(json_transferee);
- ast_json_unref(json_transferer2);
- ast_json_unref(json_transferer1);
- return NULL;
- }
- }
- out = ast_json_pack("{s: s, s: o, s: o, s: o, s: s, s: o}",
- "type", "BridgeAttendedTransfer",
- "timestamp", ast_json_timeval(*tv, NULL),
- "transferer_first_leg", json_transferer1,
- "transferer_second_leg", json_transferer2,
- "result", result_strs[transfer_msg->result],
- "is_external", ast_json_boolean(transfer_msg->is_external));
- if (!out) {
- ast_json_unref(json_target);
- ast_json_unref(json_transferee);
- return NULL;
- }
- if (json_transferee && ast_json_object_set(out, "transferee", json_transferee)) {
- ast_json_unref(json_target);
- return NULL;
- }
- if (json_target && ast_json_object_set(out, "transfer_target", json_target)) {
- return NULL;
- }
- if (transfer_msg->to_transferee.bridge_snapshot) {
- json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transferee.bridge_snapshot, sanitize);
- if (!json_bridge) {
- return NULL;
- }
- res |= ast_json_object_set(out, "transferer_first_leg_bridge", json_bridge);
- }
- if (transfer_msg->to_transfer_target.bridge_snapshot) {
- json_bridge = ast_bridge_snapshot_to_json(transfer_msg->to_transfer_target.bridge_snapshot, sanitize);
- if (!json_bridge) {
- return NULL;
- }
- res |= ast_json_object_set(out, "transferer_second_leg_bridge", json_bridge);
- }
- switch (transfer_msg->dest_type) {
- case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
- res |= ast_json_object_set(out, "destination_type", ast_json_string_create("bridge"));
- res |= ast_json_object_set(out, "destination_bridge", ast_json_string_create(transfer_msg->dest.bridge));
- break;
- case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
- res |= ast_json_object_set(out, "replace_channel", ast_channel_snapshot_to_json(transfer_msg->replace_channel, sanitize));
- /* fallthrough */
- case AST_ATTENDED_TRANSFER_DEST_APP:
- res |= ast_json_object_set(out, "destination_type", ast_json_string_create("application"));
- res |= ast_json_object_set(out, "destination_application", ast_json_string_create(transfer_msg->dest.app));
- break;
- case AST_ATTENDED_TRANSFER_DEST_LINK:
- res |= ast_json_object_set(out, "destination_type", ast_json_string_create("link"));
- json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[0], sanitize);
- if (!json_channel) {
- return NULL;
- }
- res |= ast_json_object_set(out, "destination_link_first_leg", json_channel);
- json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.links[1], sanitize);
- if (!json_channel) {
- return NULL;
- }
- res |= ast_json_object_set(out, "destination_link_second_leg", json_channel);
- break;
- case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
- res |= ast_json_object_set(out, "destination_type", ast_json_string_create("threeway"));
- json_channel = ast_channel_snapshot_to_json(transfer_msg->dest.threeway.channel_snapshot, sanitize);
- if (!json_channel) {
- return NULL;
- }
- res |= ast_json_object_set(out, "destination_threeway_channel", json_channel);
- json_bridge = ast_bridge_snapshot_to_json(transfer_msg->dest.threeway.bridge_snapshot, sanitize);
- if (!json_bridge) {
- return NULL;
- }
- res |= ast_json_object_set(out, "destination_threeway_bridge", json_bridge);
- break;
- case AST_ATTENDED_TRANSFER_DEST_FAIL:
- res |= ast_json_object_set(out, "destination_type", ast_json_string_create("fail"));
- break;
- }
- if (res) {
- return NULL;
- }
- return ast_json_ref(out);
- }
- static struct ast_manager_event_blob *attended_transfer_to_ami(struct stasis_message *msg)
- {
- RAII_VAR(struct ast_str *, variable_data, ast_str_create(64), ast_free_ptr);
- RAII_VAR(struct ast_str *, transferer1_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, bridge1_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, transferer2_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, bridge2_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, local1_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, local2_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, transferee_state, NULL, ast_free_ptr);
- RAII_VAR(struct ast_str *, target_state, NULL, ast_free_ptr);
- struct ast_attended_transfer_message *transfer_msg = stasis_message_data(msg);
- if (!variable_data) {
- return NULL;
- }
- transferer1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transferee.channel_snapshot, "OrigTransferer");
- transferer2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->to_transfer_target.channel_snapshot, "SecondTransferer");
- if (!transferer1_state || !transferer2_state) {
- return NULL;
- }
- if (transfer_msg->transferee) {
- transferee_state = ast_manager_build_channel_state_string_prefix(transfer_msg->transferee, "Transferee");
- if (!transferee_state) {
- return NULL;
- }
- }
- if (transfer_msg->target) {
- target_state = ast_manager_build_channel_state_string_prefix(transfer_msg->target, "TransferTarget");
- if (!target_state) {
- return NULL;
- }
- }
- if (transfer_msg->to_transferee.bridge_snapshot) {
- bridge1_state = ast_manager_build_bridge_state_string_prefix(
- transfer_msg->to_transferee.bridge_snapshot, "Orig");
- if (!bridge1_state) {
- return NULL;
- }
- }
- if (transfer_msg->to_transfer_target.bridge_snapshot) {
- bridge2_state = ast_manager_build_bridge_state_string_prefix(
- transfer_msg->to_transfer_target.bridge_snapshot, "Second");
- if (!bridge2_state) {
- return NULL;
- }
- }
- switch (transfer_msg->dest_type) {
- case AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE:
- ast_str_append(&variable_data, 0, "DestType: Bridge\r\n");
- ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.bridge);
- break;
- case AST_ATTENDED_TRANSFER_DEST_APP:
- case AST_ATTENDED_TRANSFER_DEST_LOCAL_APP:
- ast_str_append(&variable_data, 0, "DestType: App\r\n");
- ast_str_append(&variable_data, 0, "DestApp: %s\r\n", transfer_msg->dest.app);
- break;
- case AST_ATTENDED_TRANSFER_DEST_LINK:
- local1_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[0], "LocalOne");
- local2_state = ast_manager_build_channel_state_string_prefix(transfer_msg->dest.links[1], "LocalTwo");
- if (!local1_state || !local2_state) {
- return NULL;
- }
- ast_str_append(&variable_data, 0, "DestType: Link\r\n");
- ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local1_state));
- ast_str_append(&variable_data, 0, "%s", ast_str_buffer(local2_state));
- break;
- case AST_ATTENDED_TRANSFER_DEST_THREEWAY:
- ast_str_append(&variable_data, 0, "DestType: Threeway\r\n");
- ast_str_append(&variable_data, 0, "DestBridgeUniqueid: %s\r\n", transfer_msg->dest.threeway.bridge_snapshot->uniqueid);
- ast_str_append(&variable_data, 0, "DestTransfererChannel: %s\r\n", transfer_msg->dest.threeway.channel_snapshot->name);
- break;
- case AST_ATTENDED_TRANSFER_DEST_FAIL:
- ast_str_append(&variable_data, 0, "DestType: Fail\r\n");
- break;
- }
- return ast_manager_event_blob_create(EVENT_FLAG_CALL, "AttendedTransfer",
- "Result: %s\r\n"
- "%s"
- "%s"
- "%s"
- "%s"
- "%s"
- "%s"
- "IsExternal: %s\r\n"
- "%s",
- result_strs[transfer_msg->result],
- ast_str_buffer(transferer1_state),
- bridge1_state ? ast_str_buffer(bridge1_state) : "",
- ast_str_buffer(transferer2_state),
- bridge2_state ? ast_str_buffer(bridge2_state) : "",
- transferee_state ? ast_str_buffer(transferee_state) : "",
- target_state ? ast_str_buffer(target_state) : "",
- transfer_msg->is_external ? "Yes" : "No",
- ast_str_buffer(variable_data));
- }
- static void attended_transfer_dtor(void *obj)
- {
- struct ast_attended_transfer_message *msg = obj;
- int i;
- bridge_channel_snapshot_pair_cleanup(&msg->to_transferee);
- bridge_channel_snapshot_pair_cleanup(&msg->to_transfer_target);
- ao2_cleanup(msg->replace_channel);
- ao2_cleanup(msg->transferee);
- ao2_cleanup(msg->target);
- if (msg->dest_type != AST_ATTENDED_TRANSFER_DEST_LINK) {
- return;
- }
- for (i = 0; i < ARRAY_LEN(msg->dest.links); ++i) {
- ao2_cleanup(msg->dest.links[i]);
- }
- }
- struct ast_attended_transfer_message *ast_attended_transfer_message_create(int is_external,
- struct ast_channel *to_transferee, struct ast_bridge *transferee_bridge,
- struct ast_channel *to_transfer_target, struct ast_bridge *target_bridge,
- struct ast_channel *transferee, struct ast_channel *transfer_target)
- {
- struct ast_attended_transfer_message *transfer_msg;
- transfer_msg = ao2_alloc(sizeof(*transfer_msg), attended_transfer_dtor);
- if (!transfer_msg) {
- return NULL;
- }
- if (bridge_channel_snapshot_pair_init(to_transferee, transferee_bridge, &transfer_msg->to_transferee) ||
- bridge_channel_snapshot_pair_init(to_transfer_target, target_bridge, &transfer_msg->to_transfer_target)) {
- ao2_cleanup(transfer_msg);
- return NULL;
- }
- if (transferee) {
- transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
- if (!transfer_msg->transferee) {
- ao2_cleanup(transfer_msg);
- return NULL;
- }
- } else if (transferee_bridge) {
- transferee = ast_bridge_peer(transferee_bridge, to_transferee);
- if (transferee) {
- transfer_msg->transferee = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transferee));
- ao2_cleanup(transferee);
- if (!transfer_msg->transferee) {
- ao2_cleanup(transfer_msg);
- return NULL;
- }
- }
- }
- if (transfer_target) {
- transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
- if (!transfer_msg->target) {
- ao2_cleanup(transfer_msg);
- return NULL;
- }
- } else if (target_bridge) {
- transfer_target = ast_bridge_peer(target_bridge, to_transfer_target);
- if (transfer_target) {
- transfer_msg->target = ast_channel_snapshot_get_latest(ast_channel_uniqueid(transfer_target));
- ao2_cleanup(transfer_target);
- if (!transfer_msg->target) {
- ao2_cleanup(transfer_msg);
- return NULL;
- }
- }
- }
- return transfer_msg;
- }
- int ast_attended_transfer_message_add_merge(struct ast_attended_transfer_message *transfer_msg,
- struct ast_bridge *final_bridge)
- {
- transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE;
- ast_copy_string(transfer_msg->dest.bridge, final_bridge->uniqueid,
- sizeof(transfer_msg->dest.bridge));
- return 0;
- }
- int ast_attended_transfer_message_add_threeway(struct ast_attended_transfer_message *transfer_msg,
- struct ast_channel *survivor_channel, struct ast_bridge *survivor_bridge)
- {
- transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_THREEWAY;
- if (!strcmp(ast_channel_uniqueid(survivor_channel), transfer_msg->to_transferee.channel_snapshot->uniqueid)) {
- transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transferee.channel_snapshot;
- } else {
- transfer_msg->dest.threeway.channel_snapshot = transfer_msg->to_transfer_target.channel_snapshot;
- }
- if (!strcmp(survivor_bridge->uniqueid, transfer_msg->to_transferee.bridge_snapshot->uniqueid)) {
- transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transferee.bridge_snapshot;
- } else {
- transfer_msg->dest.threeway.bridge_snapshot = transfer_msg->to_transfer_target.bridge_snapshot;
- }
- return 0;
- }
- int ast_attended_transfer_message_add_app(struct ast_attended_transfer_message *transfer_msg,
- const char *app, struct ast_channel *replace_channel)
- {
- transfer_msg->dest_type = replace_channel ? AST_ATTENDED_TRANSFER_DEST_LOCAL_APP : AST_ATTENDED_TRANSFER_DEST_APP;
- if (replace_channel) {
- transfer_msg->replace_channel = ast_channel_snapshot_get_latest(ast_channel_uniqueid(replace_channel));
- if (!transfer_msg->replace_channel) {
- return -1;
- }
- }
- ast_copy_string(transfer_msg->dest.app, app, sizeof(transfer_msg->dest.app));
- return 0;
- }
- int ast_attended_transfer_message_add_link(struct ast_attended_transfer_message *transfer_msg,
- struct ast_channel *locals[2])
- {
- int i;
- transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
- for (i = 0; i < 2; ++i) {
- transfer_msg->dest.links[i] = ast_channel_snapshot_get_latest(ast_channel_uniqueid(locals[i]));
- if (!transfer_msg->dest.links[i]) {
- return -1;
- }
- }
- return 0;
- }
- void ast_bridge_publish_attended_transfer(struct ast_attended_transfer_message *transfer_msg)
- {
- struct stasis_message *msg;
- msg = stasis_message_create(ast_attended_transfer_type(), transfer_msg);
- if (!msg) {
- return;
- }
- stasis_publish(ast_bridge_topic_all(), msg);
- ao2_ref(msg, -1);
- }
- struct ast_bridge_snapshot *ast_bridge_snapshot_get_latest(const char *uniqueid)
- {
- struct stasis_message *message;
- struct ast_bridge_snapshot *snapshot;
- ast_assert(!ast_strlen_zero(uniqueid));
- message = stasis_cache_get(ast_bridge_cache(),
- ast_bridge_snapshot_type(),
- uniqueid);
- if (!message) {
- return NULL;
- }
- snapshot = ao2_bump(stasis_message_data(message));
- ao2_ref(message, -1);
- return snapshot;
- }
- /*! \brief snapshot ID getter for caching topic */
- static const char *bridge_snapshot_get_id(struct stasis_message *msg)
- {
- struct ast_bridge_snapshot *snapshot;
- if (stasis_message_type(msg) != ast_bridge_snapshot_type()) {
- return NULL;
- }
- snapshot = stasis_message_data(msg);
- return snapshot->uniqueid;
- }
- static void stasis_bridging_cleanup(void)
- {
- STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_snapshot_type);
- STASIS_MESSAGE_TYPE_CLEANUP(ast_bridge_merge_message_type);
- STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_entered_bridge_type);
- STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_left_bridge_type);
- STASIS_MESSAGE_TYPE_CLEANUP(ast_blind_transfer_type);
- STASIS_MESSAGE_TYPE_CLEANUP(ast_attended_transfer_type);
- ao2_cleanup(bridge_cache_all);
- bridge_cache_all = NULL;
- }
- int ast_stasis_bridging_init(void)
- {
- int res = 0;
- ast_register_cleanup(stasis_bridging_cleanup);
- bridge_cache_all = stasis_cp_all_create("ast_bridge_topic_all",
- bridge_snapshot_get_id);
- if (!bridge_cache_all) {
- return -1;
- }
- res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_snapshot_type);
- res |= STASIS_MESSAGE_TYPE_INIT(ast_bridge_merge_message_type);
- res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_entered_bridge_type);
- res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_left_bridge_type);
- res |= STASIS_MESSAGE_TYPE_INIT(ast_blind_transfer_type);
- res |= STASIS_MESSAGE_TYPE_INIT(ast_attended_transfer_type);
- return res;
- }
|