c08bbd99fdca746c74f17f5ede4d4b3207601083
[asterisk/asterisk.git] / main / stasis_channels.c
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
19 /*! \file
20  *
21  * \brief Stasis Messages and Data Types for Channel Objects
22  *
23  * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
24  *
25  */
26
27 /*** MODULEINFO
28         <support_level>core</support_level>
29  ***/
30
31 #include "asterisk.h"
32
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
34
35 #include "asterisk/stasis.h"
36 #include "asterisk/astobj2.h"
37 #include "asterisk/stasis_channels.h"
38
39 #define NUM_MULTI_CHANNEL_BLOB_BUCKETS 7
40
41 /*!
42  * @{ \brief Define channel message types.
43  */
44 STASIS_MESSAGE_TYPE_DEFN(ast_channel_snapshot_type);
45 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dial_type);
46 STASIS_MESSAGE_TYPE_DEFN(ast_channel_varset_type);
47 STASIS_MESSAGE_TYPE_DEFN(ast_channel_user_event_type);
48 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_request_type);
49 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_begin_type);
50 STASIS_MESSAGE_TYPE_DEFN(ast_channel_dtmf_end_type);
51 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hold_type);
52 STASIS_MESSAGE_TYPE_DEFN(ast_channel_unhold_type);
53 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_start_type);
54 STASIS_MESSAGE_TYPE_DEFN(ast_channel_chanspy_stop_type);
55 STASIS_MESSAGE_TYPE_DEFN(ast_channel_fax_type);
56 STASIS_MESSAGE_TYPE_DEFN(ast_channel_hangup_handler_type);
57 STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_start_type);
58 STASIS_MESSAGE_TYPE_DEFN(ast_channel_moh_stop_type);
59 STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_start_type);
60 STASIS_MESSAGE_TYPE_DEFN(ast_channel_monitor_stop_type);
61 /*! @} */
62
63 /*! \brief Topic for all channels */
64 struct stasis_topic *channel_topic_all;
65
66 /*! \brief Caching topic for all channels */
67 struct stasis_caching_topic *channel_topic_all_cached;
68
69 struct stasis_topic *ast_channel_topic_all(void)
70 {
71         return channel_topic_all;
72 }
73
74 struct stasis_caching_topic *ast_channel_topic_all_cached(void)
75 {
76         return channel_topic_all_cached;
77 }
78
79 static const char *channel_snapshot_get_id(struct stasis_message *message)
80 {
81         struct ast_channel_snapshot *snapshot;
82         if (ast_channel_snapshot_type() != stasis_message_type(message)) {
83                 return NULL;
84         }
85         snapshot = stasis_message_data(message);
86         return snapshot->uniqueid;
87 }
88
89 /*! \internal \brief Hash function for \ref ast_channel_snapshot objects */
90 static int channel_snapshot_hash_cb(const void *obj, const int flags)
91 {
92         const struct ast_channel_snapshot *snapshot = obj;
93         const char *name = (flags & OBJ_KEY) ? obj : snapshot->name;
94         return ast_str_case_hash(name);
95 }
96
97 /*! \internal \brief Comparison function for \ref ast_channel_snapshot objects */
98 static int channel_snapshot_cmp_cb(void *obj, void *arg, int flags)
99 {
100         struct ast_channel_snapshot *left = obj;
101         struct ast_channel_snapshot *right = arg;
102         const char *match = (flags & OBJ_KEY) ? arg : right->name;
103         return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
104 }
105
106 static void channel_snapshot_dtor(void *obj)
107 {
108         struct ast_channel_snapshot *snapshot = obj;
109         ast_string_field_free_memory(snapshot);
110 }
111
112 struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
113 {
114         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
115
116         snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor);
117         if (!snapshot || ast_string_field_init(snapshot, 1024)) {
118                 return NULL;
119         }
120
121         ast_string_field_set(snapshot, name, ast_channel_name(chan));
122         ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
123         ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
124         ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
125         ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
126         ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
127         ast_string_field_set(snapshot, parkinglot, ast_channel_parkinglot(chan));
128         ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
129         if (ast_channel_appl(chan)) {
130                 ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
131         }
132         if (ast_channel_data(chan)) {
133                 ast_string_field_set(snapshot, data, ast_channel_data(chan));
134         }
135         ast_string_field_set(snapshot, context, ast_channel_context(chan));
136         ast_string_field_set(snapshot, exten, ast_channel_exten(chan));
137
138         ast_string_field_set(snapshot, caller_name,
139                 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
140         ast_string_field_set(snapshot, caller_number,
141                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
142
143         ast_string_field_set(snapshot, connected_name,
144                 S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
145         ast_string_field_set(snapshot, connected_number,
146                 S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
147         ast_string_field_set(snapshot, language, ast_channel_language(chan));
148
149         snapshot->creationtime = ast_channel_creationtime(chan);
150         snapshot->state = ast_channel_state(chan);
151         snapshot->priority = ast_channel_priority(chan);
152         snapshot->amaflags = ast_channel_amaflags(chan);
153         snapshot->hangupcause = ast_channel_hangupcause(chan);
154         snapshot->flags = *ast_channel_flags(chan);
155         snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
156
157         snapshot->manager_vars = ast_channel_get_manager_vars(chan);
158
159         ao2_ref(snapshot, +1);
160         return snapshot;
161 }
162
163 static void publish_message_for_channel_topics(struct stasis_message *message, struct ast_channel *chan)
164 {
165         if (chan) {
166                 stasis_publish(ast_channel_topic(chan), message);
167         } else {
168                 stasis_publish(ast_channel_topic_all(), message);
169         }
170 }
171
172 static void channel_blob_dtor(void *obj)
173 {
174         struct ast_channel_blob *event = obj;
175         ao2_cleanup(event->snapshot);
176         ast_json_unref(event->blob);
177 }
178
179 void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
180 {
181         RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
182         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
183         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
184         struct ast_channel_snapshot *caller_snapshot;
185         struct ast_channel_snapshot *peer_snapshot;
186
187         ast_assert(peer != NULL);
188         blob = ast_json_pack("{s: s, s: s}",
189                              "dialstatus", S_OR(dialstatus, ""),
190                              "dialstring", S_OR(dialstring, ""));
191         if (!blob) {
192                 return;
193         }
194         payload = ast_multi_channel_blob_create(blob);
195         if (!payload) {
196                 return;
197         }
198
199         if (caller) {
200                 caller_snapshot = ast_channel_snapshot_create(caller);
201                 if (!caller_snapshot) {
202                         return;
203                 }
204                 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
205         }
206
207         peer_snapshot = ast_channel_snapshot_create(peer);
208         if (!peer_snapshot) {
209                 return;
210         }
211         ast_multi_channel_blob_add_channel(payload, "peer", peer_snapshot);
212
213         msg = stasis_message_create(ast_channel_dial_type(), payload);
214         if (!msg) {
215                 return;
216         }
217
218         publish_message_for_channel_topics(msg, caller);
219 }
220
221 static struct stasis_message *create_channel_blob_message(struct ast_channel_snapshot *snapshot,
222                 struct stasis_message_type *type,
223                 struct ast_json *blob)
224
225 {
226         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
227         RAII_VAR(struct ast_channel_blob *, obj, NULL, ao2_cleanup);
228
229         if (blob == NULL) {
230                 blob = ast_json_null();
231         }
232
233         obj = ao2_alloc(sizeof(*obj), channel_blob_dtor);
234         if (!obj) {
235                 return NULL;
236         }
237
238         if (snapshot) {
239                 obj->snapshot = snapshot;
240                 ao2_ref(obj->snapshot, +1);
241         }
242         obj->blob = ast_json_ref(blob);
243
244         msg = stasis_message_create(type, obj);
245         if (!msg) {
246                 return NULL;
247         }
248
249         ao2_ref(msg, +1);
250         return msg;
251 }
252
253 struct stasis_message *ast_channel_blob_create_from_cache(const char *channel_id,
254                                                struct stasis_message_type *type,
255                                                struct ast_json *blob)
256 {
257         RAII_VAR(struct ast_channel_snapshot *, snapshot,
258                         ast_channel_snapshot_get_latest(channel_id),
259                         ao2_cleanup);
260
261         return create_channel_blob_message(snapshot, type, blob);
262 }
263
264 struct stasis_message *ast_channel_blob_create(struct ast_channel *chan,
265         struct stasis_message_type *type, struct ast_json *blob)
266 {
267         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
268
269         if (chan) {
270                 snapshot = ast_channel_snapshot_create(chan);
271         }
272
273         return create_channel_blob_message(snapshot, type, blob);
274 }
275
276 /*! \brief A channel snapshot wrapper object used in \ref ast_multi_channel_blob objects */
277 struct channel_role_snapshot {
278         struct ast_channel_snapshot *snapshot;  /*!< A channel snapshot */
279         char role[0];                                                   /*!< The role assigned to the channel */
280 };
281
282 /*! \brief A multi channel blob data structure for multi_channel_blob stasis messages */
283 struct ast_multi_channel_blob {
284         struct ao2_container *channel_snapshots;        /*!< A container holding the snapshots */
285         struct ast_json *blob;                                          /*< A blob of JSON data */
286 };
287
288 /*! \internal \brief Standard comparison function for \ref channel_role_snapshot objects */
289 static int channel_role_single_cmp_cb(void *obj, void *arg, int flags)
290 {
291         struct channel_role_snapshot *left = obj;
292         struct channel_role_snapshot *right = arg;
293         const char *match = (flags & OBJ_KEY) ? arg : right->role;
294         return strcasecmp(left->role, match) ? 0 : (CMP_MATCH | CMP_STOP);
295 }
296
297 /*! \internal \brief Multi comparison function for \ref channel_role_snapshot objects */
298 static int channel_role_multi_cmp_cb(void *obj, void *arg, int flags)
299 {
300         struct channel_role_snapshot *left = obj;
301         struct channel_role_snapshot *right = arg;
302         const char *match = (flags & OBJ_KEY) ? arg : right->role;
303         return strcasecmp(left->role, match) ? 0 : (CMP_MATCH);
304 }
305
306 /*! \internal \brief Hash function for \ref channel_role_snapshot objects */
307 static int channel_role_hash_cb(const void *obj, const int flags)
308 {
309         const struct channel_role_snapshot *snapshot = obj;
310         const char *name = (flags & OBJ_KEY) ? obj : snapshot->role;
311         return ast_str_case_hash(name);
312 }
313
314 /*! \internal \brief Destructor for \ref ast_multi_channel_blob objects */
315 static void multi_channel_blob_dtor(void *obj)
316 {
317         struct ast_multi_channel_blob *multi_blob = obj;
318
319         ao2_cleanup(multi_blob->channel_snapshots);
320         ast_json_unref(multi_blob->blob);
321 }
322
323 struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *blob)
324 {
325         RAII_VAR(struct ast_multi_channel_blob *, obj,
326                         ao2_alloc(sizeof(*obj), multi_channel_blob_dtor),
327                         ao2_cleanup);
328
329         ast_assert(blob != NULL);
330
331         if (!obj) {
332                 return NULL;
333         }
334
335         obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
336                         channel_role_hash_cb, channel_role_single_cmp_cb);
337         if (!obj->channel_snapshots) {
338                 return NULL;
339         }
340
341         obj->blob = ast_json_ref(blob);
342
343         ao2_ref(obj, +1);
344         return obj;
345 }
346
347 struct ast_channel_snapshot *ast_channel_snapshot_get_latest(const char *uniqueid)
348 {
349         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
350         struct ast_channel_snapshot *snapshot;
351
352         ast_assert(!ast_strlen_zero(uniqueid));
353
354         message = stasis_cache_get(ast_channel_topic_all_cached(),
355                         ast_channel_snapshot_type(),
356                         uniqueid);
357         if (!message) {
358                 return NULL;
359         }
360
361         snapshot = stasis_message_data(message);
362         if (!snapshot) {
363                 return NULL;
364         }
365         ao2_ref(snapshot, +1);
366         return snapshot;
367 }
368
369 static void channel_role_snapshot_dtor(void *obj)
370 {
371         struct channel_role_snapshot *role_snapshot = obj;
372         ao2_cleanup(role_snapshot->snapshot);
373 }
374
375 void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
376 {
377         RAII_VAR(struct channel_role_snapshot *, role_snapshot, NULL, ao2_cleanup);
378         int role_len = strlen(role) + 1;
379
380         if (!obj || ast_strlen_zero(role) || !snapshot) {
381                 return;
382         }
383
384         role_snapshot = ao2_alloc(sizeof(*role_snapshot) + role_len, channel_role_snapshot_dtor);
385         if (!role_snapshot) {
386                 return;
387         }
388         ast_copy_string(role_snapshot->role, role, role_len);
389         role_snapshot->snapshot = snapshot;
390         ao2_ref(role_snapshot->snapshot, +1);
391         ao2_link(obj->channel_snapshots, role_snapshot);
392 }
393
394 struct ast_channel_snapshot *ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
395 {
396         struct channel_role_snapshot *role_snapshot;
397
398         if (!obj || ast_strlen_zero(role)) {
399                 return NULL;
400         }
401         role_snapshot = ao2_find(obj->channel_snapshots, role, OBJ_KEY);
402         /* Note that this function does not increase the ref count on snapshot */
403         if (!role_snapshot) {
404                 return NULL;
405         }
406         ao2_ref(role_snapshot, -1);
407         return role_snapshot->snapshot;
408 }
409
410 struct ao2_container *ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
411 {
412         RAII_VAR(struct ao2_container *, ret_container,
413                 ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS, channel_snapshot_hash_cb, channel_snapshot_cmp_cb),
414                 ao2_cleanup);
415         struct ao2_iterator *it_role_snapshots;
416         struct channel_role_snapshot *role_snapshot;
417         char *arg;
418
419         if (!obj || ast_strlen_zero(role) || !ret_container) {
420                 return NULL;
421         }
422         arg = ast_strdupa(role);
423
424         it_role_snapshots = ao2_callback(obj->channel_snapshots, OBJ_MULTIPLE | OBJ_KEY, channel_role_multi_cmp_cb, arg);
425         if (!it_role_snapshots) {
426                 return NULL;
427         }
428
429         while ((role_snapshot = ao2_iterator_next(it_role_snapshots))) {
430                 ao2_link(ret_container, role_snapshot->snapshot);
431                 ao2_ref(role_snapshot, -1);
432         }
433         ao2_iterator_destroy(it_role_snapshots);
434
435         ao2_ref(ret_container, +1);
436         return ret_container;
437 }
438
439 struct ast_json *ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
440 {
441         if (!obj) {
442                 return NULL;
443         }
444         return obj->blob;
445 }
446
447 void ast_channel_publish_snapshot(struct ast_channel *chan)
448 {
449         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
450         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
451
452         snapshot = ast_channel_snapshot_create(chan);
453         if (!snapshot) {
454                 return;
455         }
456
457         message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
458         if (!message) {
459                 return;
460         }
461
462         ast_assert(ast_channel_topic(chan) != NULL);
463         stasis_publish(ast_channel_topic(chan), message);
464 }
465
466 void ast_channel_publish_varset(struct ast_channel *chan, const char *name, const char *value)
467 {
468         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
469         RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
470
471         ast_assert(name != NULL);
472         ast_assert(value != NULL);
473
474         blob = ast_json_pack("{s: s, s: s}",
475                              "variable", name,
476                              "value", value);
477         if (!blob) {
478                 ast_log(LOG_ERROR, "Error creating message\n");
479                 return;
480         }
481
482         msg = ast_channel_blob_create(chan, ast_channel_varset_type(),
483                 ast_json_ref(blob));
484
485         if (!msg) {
486                 return;
487         }
488
489         publish_message_for_channel_topics(msg, chan);
490 }
491
492 void ast_publish_channel_state(struct ast_channel *chan)
493 {
494         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
495         RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
496
497         ast_assert(chan != NULL);
498         if (!chan) {
499                 return;
500         }
501
502         snapshot = ast_channel_snapshot_create(chan);
503         if (!snapshot) {
504                 return;
505         }
506
507         message = stasis_message_create(ast_channel_snapshot_type(), snapshot);
508         if (!message) {
509                 return;
510         }
511
512         ast_assert(ast_channel_topic(chan) != NULL);
513         stasis_publish(ast_channel_topic(chan), message);
514 }
515
516 struct ast_json *ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot)
517 {
518         RAII_VAR(struct ast_json *, json_chan, NULL, ast_json_unref);
519
520         if (snapshot == NULL) {
521                 return NULL;
522         }
523
524         json_chan = ast_json_pack("{ s: s, s: s, s: s, s: s, s: s, s: s, s: s,"
525                                   "  s: s, s: s, s: s, s: s, s: o, s: o, s: o,"
526                                   "  s: o"
527                                   "}",
528                                   "name", snapshot->name,
529                                   "state", ast_state2str(snapshot->state),
530                                   "accountcode", snapshot->accountcode,
531                                   "peeraccount", snapshot->peeraccount,
532                                   "userfield", snapshot->userfield,
533                                   "uniqueid", snapshot->uniqueid,
534                                   "linkedid", snapshot->linkedid,
535                                   "parkinglot", snapshot->parkinglot,
536                                   "hangupsource", snapshot->hangupsource,
537                                   "appl", snapshot->appl,
538                                   "data", snapshot->data,
539                                   "dialplan", ast_json_dialplan_cep(snapshot->context, snapshot->exten, snapshot->priority),
540                                   "caller", ast_json_name_number(snapshot->caller_name, snapshot->caller_number),
541                                   "connected", ast_json_name_number(snapshot->connected_name, snapshot->connected_number),
542                                   "creationtime", ast_json_timeval(snapshot->creationtime, NULL));
543
544         return ast_json_ref(json_chan);
545 }
546
547 int ast_channel_snapshot_cep_equal(
548         const struct ast_channel_snapshot *old_snapshot,
549         const struct ast_channel_snapshot *new_snapshot)
550 {
551         ast_assert(old_snapshot != NULL);
552         ast_assert(new_snapshot != NULL);
553
554         /* We actually get some snapshots with CEP set, but before the
555          * application is set. Since empty application is invalid, we treat
556          * setting the application from nothing as a CEP change.
557          */
558         if (ast_strlen_zero(old_snapshot->appl) &&
559             !ast_strlen_zero(new_snapshot->appl)) {
560                 return 0;
561         }
562
563         return old_snapshot->priority == new_snapshot->priority &&
564                 strcmp(old_snapshot->context, new_snapshot->context) == 0 &&
565                 strcmp(old_snapshot->exten, new_snapshot->exten) == 0;
566 }
567
568 int ast_channel_snapshot_caller_id_equal(
569         const struct ast_channel_snapshot *old_snapshot,
570         const struct ast_channel_snapshot *new_snapshot)
571 {
572         ast_assert(old_snapshot != NULL);
573         ast_assert(new_snapshot != NULL);
574         return strcmp(old_snapshot->caller_number, new_snapshot->caller_number) == 0 &&
575                 strcmp(old_snapshot->caller_name, new_snapshot->caller_name) == 0;
576 }
577
578 static void stasis_channels_cleanup(void)
579 {
580         channel_topic_all_cached = stasis_caching_unsubscribe_and_join(channel_topic_all_cached);
581         ao2_cleanup(channel_topic_all);
582         channel_topic_all = NULL;
583         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_snapshot_type);
584         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dial_type);
585         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_varset_type);
586         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_user_event_type);
587         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_request_type);
588         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_begin_type);
589         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_dtmf_end_type);
590         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hold_type);
591         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_unhold_type);
592         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_start_type);
593         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_chanspy_stop_type);
594         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_fax_type);
595         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_hangup_handler_type);
596         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_start_type);
597         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_moh_stop_type);
598         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_start_type);
599         STASIS_MESSAGE_TYPE_CLEANUP(ast_channel_monitor_stop_type);
600 }
601
602 void ast_stasis_channels_init(void)
603 {
604         ast_register_cleanup(stasis_channels_cleanup);
605
606         STASIS_MESSAGE_TYPE_INIT(ast_channel_snapshot_type);
607         STASIS_MESSAGE_TYPE_INIT(ast_channel_dial_type);
608         STASIS_MESSAGE_TYPE_INIT(ast_channel_varset_type);
609         STASIS_MESSAGE_TYPE_INIT(ast_channel_user_event_type);
610         STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_request_type);
611         STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_begin_type);
612         STASIS_MESSAGE_TYPE_INIT(ast_channel_dtmf_end_type);
613         STASIS_MESSAGE_TYPE_INIT(ast_channel_hold_type);
614         STASIS_MESSAGE_TYPE_INIT(ast_channel_unhold_type);
615         STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_start_type);
616         STASIS_MESSAGE_TYPE_INIT(ast_channel_chanspy_stop_type);
617         STASIS_MESSAGE_TYPE_INIT(ast_channel_fax_type);
618         STASIS_MESSAGE_TYPE_INIT(ast_channel_hangup_handler_type);
619         STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_start_type);
620         STASIS_MESSAGE_TYPE_INIT(ast_channel_moh_stop_type);
621         STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_start_type);
622         STASIS_MESSAGE_TYPE_INIT(ast_channel_monitor_stop_type);
623
624         channel_topic_all = stasis_topic_create("ast_channel_topic_all");
625         channel_topic_all_cached = stasis_caching_topic_create(channel_topic_all, channel_snapshot_get_id);
626 }