stasis_channels.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2013, Digium, Inc.
  5. *
  6. * Matt Jordan <mjordan@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Stasis Messages and Data Types for Channel Objects
  21. *
  22. * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
  23. *
  24. */
  25. /*** MODULEINFO
  26. <support_level>core</support_level>
  27. ***/
  28. #include "asterisk.h"
  29. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  30. #include "asterisk/astobj2.h"
  31. #include "asterisk/json.h"
  32. #include "asterisk/pbx.h"
  33. #include "asterisk/bridge.h"
  34. #include "asterisk/translate.h"
  35. #include "asterisk/stasis.h"
  36. #include "asterisk/stasis_cache_pattern.h"
  37. #include "asterisk/stasis_channels.h"
  38. /*** DOCUMENTATION
  39. <managerEvent language="en_US" name="VarSet">
  40. <managerEventInstance class="EVENT_FLAG_DIALPLAN">
  41. <synopsis>Raised when a variable is set to a particular value.</synopsis>
  42. <syntax>
  43. <channel_snapshot/>
  44. <parameter name="Variable">
  45. <para>The variable being set.</para>
  46. </parameter>
  47. <parameter name="Value">
  48. <para>The new value of the variable.</para>
  49. </parameter>
  50. </syntax>
  51. </managerEventInstance>
  52. </managerEvent>
  53. <managerEvent language="en_US" name="AgentLogin">
  54. <managerEventInstance class="EVENT_FLAG_AGENT">
  55. <synopsis>Raised when an Agent has logged in.</synopsis>
  56. <syntax>
  57. <channel_snapshot/>
  58. <parameter name="Agent">
  59. <para>Agent ID of the agent.</para>
  60. </parameter>
  61. </syntax>
  62. <see-also>
  63. <ref type="application">AgentLogin</ref>
  64. <ref type="managerEvent">AgentLogoff</ref>
  65. </see-also>
  66. </managerEventInstance>
  67. </managerEvent>
  68. <managerEvent language="en_US" name="AgentLogoff">
  69. <managerEventInstance class="EVENT_FLAG_AGENT">
  70. <synopsis>Raised when an Agent has logged off.</synopsis>
  71. <syntax>
  72. <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentLogin']/managerEventInstance/syntax/parameter)" />
  73. <parameter name="Logintime">
  74. <para>The number of seconds the agent was logged in.</para>
  75. </parameter>
  76. </syntax>
  77. <see-also>
  78. <ref type="managerEvent">AgentLogin</ref>
  79. </see-also>
  80. </managerEventInstance>
  81. </managerEvent>
  82. ***/
  83. #define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
  84. static struct stasis_cp_all *channel_cache_all;
  85. static struct stasis_cache *channel_cache_by_name;
  86. static struct stasis_caching_topic *channel_by_name_topic;
  87. struct stasis_cp_all *ast_channel_cache_all(void)
  88. {
  89. return channel_cache_all;
  90. }
  91. struct stasis_cache *ast_channel_cache(void)
  92. {
  93. return stasis_cp_all_cache(channel_cache_all);
  94. }
  95. struct stasis_topic *ast_channel_topic_all(void)
  96. {
  97. return stasis_cp_all_topic(channel_cache_all);
  98. }
  99. struct stasis_topic *ast_channel_topic_all_cached(void)
  100. {
  101. return stasis_cp_all_topic_cached(channel_cache_all);
  102. }
  103. struct stasis_cache *ast_channel_cache_by_name(void)
  104. {
  105. return channel_cache_by_name;
  106. }
  107. static const char *channel_snapshot_get_id(struct stasis_message *message)
  108. {
  109. struct ast_channel_snapshot *snapshot;
  110. if (ast_channel_snapshot_type() != stasis_message_type(message)) {
  111. return NULL;
  112. }
  113. snapshot = stasis_message_data(message);
  114. return snapshot->uniqueid;
  115. }
  116. static const char *channel_snapshot_get_name(struct stasis_message *message)
  117. {
  118. struct ast_channel_snapshot *snapshot;
  119. if (ast_channel_snapshot_type() != stasis_message_type(message)) {
  120. return NULL;
  121. }
  122. snapshot = stasis_message_data(message);
  123. return snapshot->name;
  124. }
  125. /*!
  126. * \internal
  127. * \brief Hash function for \ref ast_channel_snapshot objects
  128. */
  129. static int channel_snapshot_hash_cb(const void *obj, const int flags)
  130. {
  131. const struct ast_channel_snapshot *snapshot = obj;
  132. const char *name = (flags & OBJ_KEY) ? obj : snapshot->name;
  133. return ast_str_case_hash(name);
  134. }
  135. /*!
  136. * \internal
  137. * \brief Comparison function for \ref ast_channel_snapshot objects
  138. */
  139. static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
  140. {
  141. struct ast_channel_snapshot *left = obj;
  142. struct ast_channel_snapshot *right = arg;
  143. const char *match = (flags & OBJ_KEY) ? arg : right->name;
  144. return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
  145. }
  146. static void channel_snapshot_dtor(void *obj)
  147. {
  148. struct ast_channel_snapshot *snapshot = obj;
  149. ast_string_field_free_memory(snapshot);
  150. ao2_cleanup(snapshot->manager_vars);
  151. ao2_cleanup(snapshot->channel_vars);
  152. }
  153. struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
  154. {
  155. RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
  156. RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
  157. char nativeformats[256];
  158. struct ast_str *write_transpath = ast_str_alloca(256);
  159. struct ast_str *read_transpath = ast_str_alloca(256);
  160. struct ast_party_id effective_connected_id;
  161. struct ast_callid *callid;
  162. /* no snapshots for dummy channels */
  163. if (!ast_channel_tech(chan)) {
  164. return NULL;
  165. }
  166. snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor);
  167. if (!snapshot || ast_string_field_init(snapshot, 1024)) {
  168. return NULL;
  169. }
  170. ast_string_field_set(snapshot, name, ast_channel_name(chan));
  171. ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
  172. ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
  173. ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
  174. ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
  175. ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
  176. ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
  177. ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
  178. if (ast_channel_appl(chan)) {
  179. ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
  180. }
  181. if (ast_channel_data(chan)) {
  182. ast_string_field_set(snapshot, data, ast_channel_data(chan));
  183. }
  184. ast_string_field_set(snapshot, context, ast_channel_context(chan));
  185. ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
  186. ast_string_field_set(snapshot, caller_name,
  187. S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
  188. ast_string_field_set(snapshot, caller_number,
  189. S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
  190. ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, ""));
  191. ast_string_field_set(snapshot, caller_subaddr,
  192. S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
  193. ast_string_field_set(snapshot, dialed_subaddr,
  194. S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
  195. ast_string_field_set(snapshot, caller_ani,
  196. S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
  197. ast_string_field_set(snapshot, caller_rdnis,
  198. S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
  199. ast_string_field_set(snapshot, caller_dnid,
  200. S_OR(ast_channel_dialed(chan)->number.str, ""));
  201. ast_string_field_set(snapshot, connected_name,
  202. S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
  203. ast_string_field_set(snapshot, connected_number,
  204. S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
  205. ast_string_field_set(snapshot, language, ast_channel_language(chan));
  206. if ((bridge = ast_channel_get_bridge(chan))) {
  207. ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
  208. }
  209. ast_string_field_set(snapshot, nativeformats, ast_getformatname_multiple(nativeformats, sizeof(nativeformats),
  210. ast_channel_nativeformats(chan)));
  211. ast_string_field_set(snapshot, readformat, ast_getformatname(ast_channel_readformat(chan)));
  212. ast_string_field_set(snapshot, writeformat, ast_getformatname(ast_channel_writeformat(chan)));
  213. ast_string_field_set(snapshot, writetrans, ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath));
  214. ast_string_field_set(snapshot, readtrans, ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath));
  215. effective_connected_id = ast_channel_connected_effective_id(chan);
  216. ast_string_field_set(snapshot, effective_name,
  217. S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, ""));
  218. ast_string_field_set(snapshot, effective_number,
  219. S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, ""));
  220. if ((callid = ast_channel_callid(chan))) {
  221. ast_callid_strnprint(snapshot->callid, sizeof(snapshot->callid), callid);
  222. ast_callid_unref(callid);
  223. }
  224. snapshot->creationtime = ast_channel_creationtime(chan);
  225. snapshot->hanguptime = *(ast_channel_whentohangup(chan));
  226. snapshot->state = ast_channel_state(chan);
  227. snapshot->priority = ast_channel_priority(chan);
  228. snapshot->amaflags = ast_channel_amaflags(chan);
  229. snapshot->hangupcause = ast_channel_hangupcause(chan);
  230. ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
  231. snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
  232. snapshot->callgroup = ast_channel_callgroup(chan);
  233. snapshot->pickupgroup = ast_channel_pickupgroup(chan);
  234. ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
  235. snapshot->manager_vars = ast_channel_get_manager_vars(chan);
  236. snapshot->channel_vars = ast_channel_get_vars(chan);
  237. snapshot->tech_properties = ast_channel_tech(chan)->properties;
  238. ao2_ref(snapshot, +1);
  239. return snapshot;
  240. }
  241. static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
  242. {
  243. if (chan) {
  244. stasis_publish(ast_channel_topic(chan), message);
  245. } else {
  246. stasis_publish(ast_channel_topic_all(), message);
  247. }
  248. }
  249. static void channel_blob_dtor(void *obj)
  250. {
  251. struct ast_channel_blob *event = obj;
  252. ao2_cleanup(event->snapshot);
  253. ast_json_unref(event->blob);
  254. }
  255. /*! \brief Dummy callback for receiving events */
  256. static void dummy_event_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
  257. {
  258. }
  259. void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer,
  260. struct ast_channel *forwarded, const char *dialstring, const char *dialstatus,
  261. const char *forward)
  262. {
  263. RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
  264. RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
  265. RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
  266. RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
  267. RAII_VAR(struct ast_channel_snapshot *, peer_snapshot, NULL, ao2_cleanup);
  268. RAII_VAR(struct ast_channel_snapshot *, forwarded_snapshot, NULL, ao2_cleanup);
  269. ast_assert(peer != NULL);
  270. blob = ast_json_pack("{s: s, s: s, s: s}",
  271. "dialstatus", S_OR(dialstatus, ""),
  272. "forward", S_OR(forward, ""),
  273. "dialstring", S_OR(dialstring, ""));
  274. if (!blob) {
  275. return;
  276. }
  277. payload = ast_multi_channel_blob_create(blob);
  278. if (!payload) {
  279. return;
  280. }
  281. if (caller) {
  282. ast_channel_lock(caller);
  283. caller_snapshot = ast_channel_snapshot_create(caller);
  284. ast_channel_unlock(caller);
  285. if (!caller_snapshot) {
  286. return;
  287. }
  288. ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
  289. }
  290. ast_channel_lock(peer);
  291. peer_snapshot = ast_channel_snapshot_create(peer);
  292. ast_channel_unlock(peer);
  293. if (!peer_snapshot) {
  294. return;
  295. }
  296. ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
  297. if (forwarded) {
  298. forwarded_snapshot = ast_channel_snapshot_create(forwarded);
  299. if (!forwarded_snapshot) {
  300. return;
  301. }
  302. ast_multi_channel_blob_add_channel(payload, "forwarded", forwarded_snapshot);
  303. }
  304. msg = stasis_message_create(ast_channel_dial_type(), payload);
  305. if (!msg) {
  306. return;
  307. }
  308. if (forwarded) {
  309. struct stasis_subscription *subscription = stasis_subscribe(ast_channel_topic(peer), dummy_event_cb, NULL);
  310. stasis_publish(ast_channel_topic(peer), msg);
  311. stasis_unsubscribe_and_join(subscription);
  312. } else {
  313. publish_message_for_channel_topics(msg, caller);
  314. }
  315. }
  316. void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer,
  317. const char *dialstring, const char *dialstatus)
  318. {
  319. ast_channel_publish_dial_forward(caller, peer, NULL, dialstring, dialstatus, NULL);
  320. }
  321. static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
  322. struct stasis_message_type *type,
  323. struct ast_json *blob)
  324. {
  325. RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
  326. RAII_VAR(struct ast_channel_blob *, obj, NULL, ao2_cleanup);
  327. if (blob == NULL) {
  328. blob = ast_json_null();
  329. }
  330. obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
  331. if (!obj) {
  332. return NULL;
  333. }
  334. if (snapshot) {
  335. obj->snapshot = snapshot;
  336. ao2_ref(obj->snapshot, +1);
  337. }
  338. obj->blob = ast_json_ref(blob);
  339. msg = stasis_message_create(type, obj);
  340. if (!msg) {
  341. return NULL;
  342. }
  343. ao2_ref(msg, +1);
  344. return msg;
  345. }
  346. struct stasis_message *ast_channel_blob_create_from_cache(const char *channel_id,
  347. struct stasis_message_type *type,
  348. struct ast_json *blob)
  349. {
  350. RAII_VAR(struct ast_channel_snapshot *, snapshot,
  351. ast_channel_snapshot_get_latest(channel_id),
  352. ao2_cleanup);
  353. return create_channel_blob_message(snapshot, type, blob);
  354. }
  355. struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
  356. struct stasis_message_type *type, struct ast_json *blob)
  357. {
  358. RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
  359. if (chan) {
  360. snapshot = ast_channel_snapshot_create(chan);
  361. }
  362. return create_channel_blob_message(snapshot, type, blob);
  363. }
  364. /*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
  365. struct channel_role_snapshot {
  366. struct ast_channel_snapshot *snapshot; /*!< A channel snapshot */
  367. char role[0]; /*!< The role assigned to the channel */
  368. };
  369. /*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
  370. struct ast_multi_channel_blob {
  371. struct ao2_container *channel_snapshots; /*!< A container holding the snapshots */
  372. struct ast_json *blob; /*< A blob of JSON data */
  373. };
  374. /*!
  375. * \internal
  376. * \brief Standard comparison function for \ref channel_role_snapshot objects
  377. */
  378. static int channel_role_single_cmp_cb(void *obj, void *arg, int flags)
  379. {
  380. struct channel_role_snapshot *left = obj;
  381. struct channel_role_snapshot *right = arg;
  382. const char *match = (flags & OBJ_KEY) ? arg : right->role;
  383. return strcasecmp(left->role, match) ? 0 : (CMP_MATCH | CMP_STOP);
  384. }
  385. /*!
  386. * \internal
  387. * \brief Multi comparison function for \ref channel_role_snapshot objects
  388. */
  389. static int channel_role_multi_cmp_cb(void *obj, void *arg, int flags)
  390. {
  391. struct channel_role_snapshot *left = obj;
  392. struct channel_role_snapshot *right = arg;
  393. const char *match = (flags & OBJ_KEY) ? arg : right->role;
  394. return strcasecmp(left->role, match) ? 0 : (CMP_MATCH);
  395. }
  396. /*!
  397. * \internal
  398. * \brief Hash function for \ref channel_role_snapshot objects
  399. */
  400. static int channel_role_hash_cb(const void *obj, const int flags)
  401. {
  402. const struct channel_role_snapshot *snapshot = obj;
  403. const char *name = (flags & OBJ_KEY) ? obj : snapshot->role;
  404. return ast_str_case_hash(name);
  405. }
  406. /*!
  407. * \internal
  408. * \brief Destructor for \ref ast_multi_channel_blob objects
  409. */
  410. static void multi_channel_blob_dtor(void *obj)
  411. {
  412. struct ast_multi_channel_blob *multi_blob = obj;
  413. ao2_cleanup(multi_blob->channel_snapshots);
  414. ast_json_unref(multi_blob->blob);
  415. }
  416. struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *blob)
  417. {
  418. RAII_VAR(struct ast_multi_channel_blob *, obj,
  419. ao2_alloc(sizeof(*obj), multi_channel_blob_dtor),
  420. ao2_cleanup);
  421. ast_assert(blob != NULL);
  422. if (!obj) {
  423. return NULL;
  424. }
  425. obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
  426. channel_role_hash_cb, channel_role_single_cmp_cb);
  427. if (!obj->channel_snapshots) {
  428. return NULL;
  429. }
  430. obj->blob = ast_json_ref(blob);
  431. ao2_ref(obj, +1);
  432. return obj;
  433. }
  434. struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid)
  435. {
  436. RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
  437. struct ast_channel_snapshot *snapshot;
  438. ast_assert(!ast_strlen_zero(uniqueid));
  439. message = stasis_cache_get(ast_channel_cache(),
  440. ast_channel_snapshot_type(),
  441. uniqueid);
  442. if (!message) {
  443. return NULL;
  444. }
  445. snapshot = stasis_message_data(message);
  446. if (!snapshot) {
  447. return NULL;
  448. }
  449. ao2_ref(snapshot, +1);
  450. return snapshot;
  451. }
  452. struct ast_channel_snapshot *ast_channel_snapshot_get_latest_by_name(const char *name)
  453. {
  454. RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
  455. struct ast_channel_snapshot *snapshot;
  456. ast_assert(!ast_strlen_zero(name));
  457. message = stasis_cache_get(ast_channel_cache_by_name(),
  458. ast_channel_snapshot_type(),
  459. name);
  460. if (!message) {
  461. return NULL;
  462. }
  463. snapshot = stasis_message_data(message);
  464. if (!snapshot) {
  465. return NULL;
  466. }
  467. ao2_ref(snapshot, +1);
  468. return snapshot;
  469. }
  470. static void channel_role_snapshot_dtor(void *obj)
  471. {
  472. struct channel_role_snapshot *role_snapshot = obj;
  473. ao2_cleanup(role_snapshot->snapshot);
  474. }
  475. void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
  476. {
  477. RAII_VAR(struct channel_role_snapshot *, role_snapshot, NULL, ao2_cleanup);
  478. int role_len = strlen(role) + 1;
  479. if (!obj || ast_strlen_zero(role) || !snapshot) {
  480. return;
  481. }
  482. role_snapshot = ao2_alloc(sizeof(*role_snapshot) + role_len, channel_role_snapshot_dtor);
  483. if (!role_snapshot) {
  484. return;
  485. }
  486. ast_copy_string(role_snapshot->role, role, role_len);
  487. role_snapshot->snapshot = snapshot;
  488. ao2_ref(role_snapshot->snapshot, +1);
  489. ao2_link(obj->channel_snapshots, role_snapshot);
  490. }
  491. struct ast_channel_snapshot *ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
  492. {
  493. struct channel_role_snapshot *role_snapshot;
  494. if (!obj || ast_strlen_zero(role)) {
  495. return NULL;
  496. }
  497. role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_KEY);
  498. /* Note that this function does not increase the ref count on snapshot */
  499. if (!role_snapshot) {
  500. return NULL;
  501. }
  502. ao2_ref(role_snapshot, -1);
  503. return role_snapshot->snapshot;
  504. }
  505. struct ao2_container *ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
  506. {
  507. RAII_VAR(struct ao2_container *, ret_container,
  508. ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS, channel_snapshot_hash_cb, channel_snapshot_cmp_cb),
  509. ao2_cleanup);
  510. struct ao2_iterator *it_role_snapshots;
  511. struct channel_role_snapshot *role_snapshot;
  512. char *arg;
  513. if (!obj || ast_strlen_zero(role) || !ret_container) {
  514. return NULL;
  515. }
  516. arg = ast_strdupa(role);
  517. it_role_snapshots = ao2_callback(obj->channel_snapshots, OBJ_MULTIPLE | OBJ_KEY, channel_role_multi_cmp_cb, arg);
  518. if (!it_role_snapshots) {
  519. return NULL;
  520. }
  521. while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
  522. ao2_link(ret_container, role_snapshot->snapshot);
  523. ao2_ref(role_snapshot, -1);
  524. }
  525. ao2_iterator_destroy(it_role_snapshots);
  526. ao2_ref(ret_container, +1);
  527. return ret_container;
  528. }
  529. struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
  530. {
  531. if (!obj) {
  532. return NULL;
  533. }
  534. return obj->blob;
  535. }
  536. void ast_channel_stage_snapshot(struct ast_channel *chan)
  537. {
  538. ast_set_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE);
  539. }
  540. void ast_channel_stage_snapshot_done(struct ast_channel *chan)
  541. {
  542. ast_clear_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE);
  543. ast_channel_publish_snapshot(chan);
  544. }
  545. void ast_channel_publish_snapshot(struct ast_channel *chan)
  546. {
  547. RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
  548. RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
  549. if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_SNAPSHOT_STAGE)) {
  550. return;
  551. }
  552. snapshot = ast_channel_snapshot_create(chan);
  553. if (!snapshot) {
  554. return;
  555. }
  556. message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
  557. if (!message) {
  558. return;
  559. }
  560. ast_assert(ast_channel_topic(chan) != NULL);
  561. stasis_publish(ast_channel_topic(chan), message);
  562. }
  563. void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
  564. {
  565. RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
  566. if (!blob) {
  567. blob = ast_json_null();
  568. }
  569. message = ast_channel_blob_create(chan, type, blob);
  570. if (message) {
  571. stasis_publish(ast_channel_topic(chan), message);
  572. }
  573. }
  574. void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
  575. {
  576. RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
  577. ast_assert(name != NULL);
  578. ast_assert(value != NULL);
  579. blob = ast_json_pack("{s: s, s: s}",
  580. "variable", name,
  581. "value", value);
  582. if (!blob) {
  583. ast_log(LOG_ERROR, "Error creating message\n");
  584. return;
  585. }
  586. ast_channel_publish_blob(chan, ast_channel_varset_type(), blob);
  587. }
  588. static struct ast_manager_event_blob *varset_to_ami(struct stasis_message *msg)
  589. {
  590. RAII_VAR(struct ast_str *, channel_event_string, NULL, ast_free);
  591. struct ast_channel_blob *obj = stasis_message_data(msg);
  592. const char *variable =
  593. ast_json_string_get(ast_json_object_get(obj->blob, "variable"));
  594. const char *value =
  595. ast_json_string_get(ast_json_object_get(obj->blob, "value"));
  596. if (obj->snapshot) {
  597. channel_event_string =
  598. ast_manager_build_channel_state_string(obj->snapshot);
  599. } else {
  600. channel_event_string = ast_str_create(35);
  601. ast_str_set(&channel_event_string, 0,
  602. "Channel: none\r\n"
  603. "Uniqueid: none\r\n");
  604. }
  605. if (!channel_event_string) {
  606. return NULL;
  607. }
  608. return ast_manager_event_blob_create(EVENT_FLAG_DIALPLAN, "VarSet",
  609. "%s"
  610. "Variable: %s\r\n"
  611. "Value: %s\r\n",
  612. ast_str_buffer(channel_event_string), variable, value);
  613. }
  614. static struct ast_manager_event_blob *agent_login_to_ami(struct stasis_message *msg)
  615. {
  616. RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
  617. RAII_VAR(struct ast_str *, party_string, ast_str_create(256), ast_free);
  618. struct ast_channel_blob *obj = stasis_message_data(msg);
  619. const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
  620. channel_string = ast_manager_build_channel_state_string(obj->snapshot);
  621. if (!channel_string) {
  622. return NULL;
  623. }
  624. return ast_manager_event_blob_create(EVENT_FLAG_AGENT, "AgentLogin",
  625. "%s"
  626. "Agent: %s\r\n",
  627. ast_str_buffer(channel_string), agent);
  628. }
  629. static struct ast_manager_event_blob *agent_logoff_to_ami(struct stasis_message *msg)
  630. {
  631. RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
  632. RAII_VAR(struct ast_str *, party_string, ast_str_create(256), ast_free);
  633. struct ast_channel_blob *obj = stasis_message_data(msg);
  634. const char *agent = ast_json_string_get(ast_json_object_get(obj->blob, "agent"));
  635. long logintime = ast_json_integer_get(ast_json_object_get(obj->blob, "logintime"));
  636. channel_string = ast_manager_build_channel_state_string(obj->snapshot);
  637. if (!channel_string) {
  638. return NULL;
  639. }
  640. return ast_manager_event_blob_create(EVENT_FLAG_AGENT, "AgentLogoff",
  641. "%s"
  642. "Agent: %s\r\n"
  643. "Logintime: %ld\r\n",
  644. ast_str_buffer(channel_string), agent, logintime);
  645. }
  646. void ast_publish_channel_state(struct ast_channel *chan)
  647. {
  648. RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
  649. RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
  650. ast_assert(chan != NULL);
  651. if (!chan) {
  652. return;
  653. }
  654. snapshot = ast_channel_snapshot_create(chan);
  655. if (!snapshot) {
  656. return;
  657. }
  658. message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
  659. if (!message) {
  660. return;
  661. }
  662. ast_assert(ast_channel_topic(chan) != NULL);
  663. stasis_publish(ast_channel_topic(chan), message);
  664. }
  665. struct ast_json *ast_channel_snapshot_to_json(
  666. const struct ast_channel_snapshot *snapshot,
  667. const struct stasis_message_sanitizer *sanitize)
  668. {
  669. RAII_VAR(struct ast_json *, json_chan, NULL, ast_json_unref);
  670. if (snapshot == NULL
  671. || (sanitize && sanitize->channel_snapshot
  672. && sanitize->channel_snapshot(snapshot))) {
  673. return NULL;
  674. }
  675. json_chan = ast_json_pack(
  676. /* Broken up into groups of three for readability */
  677. "{ s: s, s: s, s: s,"
  678. " s: o, s: o, s: s,"
  679. " s: o, s: o }",
  680. /* First line */
  681. "id", snapshot->uniqueid,
  682. "name", snapshot->name,
  683. "state", ast_state2str(snapshot->state),
  684. /* Second line */
  685. "caller", ast_json_name_number(
  686. snapshot->caller_name, snapshot->caller_number),
  687. "connected", ast_json_name_number(
  688. snapshot->connected_name, snapshot->connected_number),
  689. "accountcode", snapshot->accountcode,
  690. /* Third line */
  691. "dialplan", ast_json_dialplan_cep(
  692. snapshot->context, snapshot->exten, snapshot->priority),
  693. "creationtime", ast_json_timeval(snapshot->creationtime, NULL));
  694. return ast_json_ref(json_chan);
  695. }
  696. int ast_channel_snapshot_cep_equal(
  697. const struct ast_channel_snapshot *old_snapshot,
  698. const struct ast_channel_snapshot *new_snapshot)
  699. {
  700. ast_assert(old_snapshot != NULL);
  701. ast_assert(new_snapshot != NULL);
  702. /* We actually get some snapshots with CEP set, but before the
  703. * application is set. Since empty application is invalid, we treat
  704. * setting the application from nothing as a CEP change.
  705. */
  706. if (ast_strlen_zero(old_snapshot->appl) &&
  707. !ast_strlen_zero(new_snapshot->appl)) {
  708. return 0;
  709. }
  710. return old_snapshot->priority == new_snapshot->priority &&
  711. strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
  712. strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
  713. }
  714. int ast_channel_snapshot_caller_id_equal(
  715. const struct ast_channel_snapshot *old_snapshot,
  716. const struct ast_channel_snapshot *new_snapshot)
  717. {
  718. ast_assert(old_snapshot != NULL);
  719. ast_assert(new_snapshot != NULL);
  720. return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
  721. strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
  722. }
  723. static struct ast_json *channel_blob_to_json(
  724. struct stasis_message *message,
  725. const char *type,
  726. const struct stasis_message_sanitizer *sanitize)
  727. {
  728. RAII_VAR(struct ast_json *, out, NULL, ast_json_unref);
  729. struct ast_channel_blob *channel_blob = stasis_message_data(message);
  730. struct ast_json *blob = channel_blob->blob;
  731. struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
  732. const struct timeval *tv = stasis_message_timestamp(message);
  733. int res = 0;
  734. if (blob == NULL || ast_json_is_null(blob)) {
  735. out = ast_json_object_create();
  736. } else {
  737. /* blobs are immutable, so shallow copies are fine */
  738. out = ast_json_copy(blob);
  739. }
  740. if (!out) {
  741. return NULL;
  742. }
  743. res |= ast_json_object_set(out, "type", ast_json_string_create(type));
  744. res |= ast_json_object_set(out, "timestamp",
  745. ast_json_timeval(*tv, NULL));
  746. /* For global channel messages, the snapshot is optional */
  747. if (snapshot) {
  748. struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
  749. if (!json_channel) {
  750. return NULL;
  751. }
  752. res |= ast_json_object_set(out, "channel", json_channel);
  753. }
  754. if (res != 0) {
  755. return NULL;
  756. }
  757. return ast_json_ref(out);
  758. }
  759. static struct ast_json *dtmf_end_to_json(
  760. struct stasis_message *message,
  761. const struct stasis_message_sanitizer *sanitize)
  762. {
  763. struct ast_channel_blob *channel_blob = stasis_message_data(message);
  764. struct ast_json *blob = channel_blob->blob;
  765. struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
  766. const char *direction =
  767. ast_json_string_get(ast_json_object_get(blob, "direction"));
  768. const struct timeval *tv = stasis_message_timestamp(message);
  769. struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
  770. /* Only present received DTMF end events as JSON */
  771. if (strcasecmp("Received", direction) != 0) {
  772. return NULL;
  773. }
  774. if (!json_channel) {
  775. return NULL;
  776. }
  777. return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
  778. "type", "ChannelDtmfReceived",
  779. "timestamp", ast_json_timeval(*tv, NULL),
  780. "digit", ast_json_object_get(blob, "digit"),
  781. "duration_ms", ast_json_object_get(blob, "duration_ms"),
  782. "channel", json_channel);
  783. }
  784. static struct ast_json *user_event_to_json(
  785. struct stasis_message *message,
  786. const struct stasis_message_sanitizer *sanitize)
  787. {
  788. struct ast_channel_blob *channel_blob = stasis_message_data(message);
  789. struct ast_json *blob = channel_blob->blob;
  790. struct ast_channel_snapshot *snapshot = channel_blob->snapshot;
  791. const struct timeval *tv = stasis_message_timestamp(message);
  792. struct ast_json *json_channel = ast_channel_snapshot_to_json(snapshot, sanitize);
  793. if (!json_channel) {
  794. return NULL;
  795. }
  796. return ast_json_pack("{s: s, s: o, s: O, s: O, s: o}",
  797. "type", "ChannelUserevent",
  798. "timestamp", ast_json_timeval(*tv, NULL),
  799. "eventname", ast_json_object_get(blob, "eventname"),
  800. "userevent", blob,
  801. "channel", json_channel);
  802. }
  803. static struct ast_json *varset_to_json(
  804. struct stasis_message *message,
  805. const struct stasis_message_sanitizer *sanitize)
  806. {
  807. return channel_blob_to_json(message, "ChannelVarset", sanitize);
  808. }
  809. static struct ast_json *hangup_request_to_json(
  810. struct stasis_message *message,
  811. const struct stasis_message_sanitizer *sanitize)
  812. {
  813. return channel_blob_to_json(message, "ChannelHangupRequest", sanitize);
  814. }
  815. static struct ast_json *dial_to_json(
  816. struct stasis_message *message,
  817. const struct stasis_message_sanitizer *sanitize)
  818. {
  819. struct ast_multi_channel_blob *payload = stasis_message_data(message);
  820. struct ast_json *blob = ast_multi_channel_blob_get_json(payload);
  821. struct ast_json *caller_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "caller"), sanitize);
  822. struct ast_json *peer_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "peer"), sanitize);
  823. struct ast_json *forwarded_json = ast_channel_snapshot_to_json(ast_multi_channel_blob_get_channel(payload, "forwarded"), sanitize);
  824. struct ast_json *json;
  825. const struct timeval *tv = stasis_message_timestamp(message);
  826. int res = 0;
  827. json = ast_json_pack("{s: s, s: o, s: O, s: O, s: O}",
  828. "type", "Dial",
  829. "timestamp", ast_json_timeval(*tv, NULL),
  830. "dialstatus", ast_json_object_get(blob, "dialstatus"),
  831. "forward", ast_json_object_get(blob, "forward"),
  832. "dialstring", ast_json_object_get(blob, "dialstring"));
  833. if (!json) {
  834. ast_json_unref(caller_json);
  835. ast_json_unref(peer_json);
  836. ast_json_unref(forwarded_json);
  837. return NULL;
  838. }
  839. if (caller_json) {
  840. res |= ast_json_object_set(json, "caller", caller_json);
  841. }
  842. if (peer_json) {
  843. res |= ast_json_object_set(json, "peer", peer_json);
  844. }
  845. if (forwarded_json) {
  846. res |= ast_json_object_set(json, "forwarded", forwarded_json);
  847. }
  848. if (res) {
  849. ast_json_unref(json);
  850. return NULL;
  851. }
  852. return json;
  853. }
  854. /*!
  855. * @{ \brief Define channel message types.
  856. */
  857. STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type);
  858. STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type,
  859. .to_json = dial_to_json,
  860. );
  861. STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type,
  862. .to_ami = varset_to_ami,
  863. .to_json = varset_to_json,
  864. );
  865. STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type,
  866. .to_json = user_event_to_json,
  867. );
  868. STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type,
  869. .to_json = hangup_request_to_json,
  870. );
  871. STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type);
  872. STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type,
  873. .to_json = dtmf_end_to_json,
  874. );
  875. STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
  876. STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
  877. STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
  878. STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
  879. STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
  880. STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type);
  881. STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type);
  882. STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type);
  883. STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type);
  884. STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type);
  885. STASIS_MESSAGE_TYPE_DEFN(ast_channel_agent_login_type,
  886. .to_ami = agent_login_to_ami,
  887. );
  888. STASIS_MESSAGE_TYPE_DEFN(ast_channel_agent_logoff_type,
  889. .to_ami = agent_logoff_to_ami,
  890. );
  891. /*! @} */
  892. static void stasis_channels_cleanup(void)
  893. {
  894. stasis_caching_unsubscribe_and_join(channel_by_name_topic);
  895. channel_by_name_topic = NULL;
  896. ao2_cleanup(channel_cache_by_name);
  897. channel_cache_by_name = NULL;
  898. ao2_cleanup(channel_cache_all);
  899. channel_cache_all = NULL;
  900. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type);
  901. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type);
  902. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_varset_type);
  903. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_user_event_type);
  904. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type);
  905. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type);
  906. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type);
  907. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hold_type);
  908. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_unhold_type);
  909. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_start_type);
  910. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_stop_type);
  911. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_fax_type);
  912. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_handler_type);
  913. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_start_type);
  914. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_stop_type);
  915. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_start_type);
  916. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_stop_type);
  917. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_agent_login_type);
  918. STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_agent_logoff_type);
  919. }
  920. int ast_stasis_channels_init(void)
  921. {
  922. int res = 0;
  923. ast_register_cleanup(stasis_channels_cleanup);
  924. channel_cache_all = stasis_cp_all_create("ast_channel_topic_all",
  925. channel_snapshot_get_id);
  926. if (!channel_cache_all) {
  927. return -1;
  928. }
  929. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_login_type);
  930. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_agent_logoff_type);
  931. channel_cache_by_name = stasis_cache_create(channel_snapshot_get_name);
  932. if (!channel_cache_by_name) {
  933. return -1;
  934. }
  935. /* This should be initialized before the caching topic */
  936. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);
  937. channel_by_name_topic = stasis_caching_topic_create(
  938. stasis_cp_all_topic(channel_cache_all),
  939. channel_cache_by_name);
  940. if (!channel_by_name_topic) {
  941. return -1;
  942. }
  943. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type);
  944. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type);
  945. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_user_event_type);
  946. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
  947. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type);
  948. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type);
  949. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hold_type);
  950. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_unhold_type);
  951. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_start_type);
  952. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_stop_type);
  953. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_fax_type);
  954. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_handler_type);
  955. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_start_type);
  956. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_stop_type);
  957. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_start_type);
  958. res |= STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_stop_type);
  959. return res;
  960. }