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