app_cdr,app_forkcdr,func_cdr: Synchronize with engine when manipulating state
[asterisk/asterisk.git] / apps / app_forkcdr.c
index 6231d38..af5ae6a 100644 (file)
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/cdr.h"
 #include "asterisk/app.h"
 #include "asterisk/module.h"
+#include "asterisk/stasis.h"
 
 /*** DOCUMENTATION
        <application name="ForkCDR" language="en_US">
@@ -102,8 +103,41 @@ AST_APP_OPTIONS(forkcdr_exec_options, {
        AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
 });
 
+STASIS_MESSAGE_TYPE_DEFN_LOCAL(forkcdr_message_type);
+
+/*! \internal \brief Message payload for the Stasis message sent to fork the CDR */
+struct fork_cdr_message_payload {
+       /*! The name of the channel whose CDR will be forked */
+       const char *channel_name;
+       /*! Option flags that control how the CDR will be forked */
+       struct ast_flags *flags;
+};
+
+static void forkcdr_callback(void *data, struct stasis_subscription *sub, struct stasis_message *message)
+{
+       struct fork_cdr_message_payload *payload;
+
+       if (stasis_message_type(message) != forkcdr_message_type()) {
+               return;
+       }
+
+       payload = stasis_message_data(message);
+       if (!payload) {
+               return;
+       }
+
+       if (ast_cdr_fork(payload->channel_name, payload->flags)) {
+               ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s\n",
+                       payload->channel_name);
+       }
+}
+
 static int forkcdr_exec(struct ast_channel *chan, const char *data)
 {
+       RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
+       RAII_VAR(struct fork_cdr_message_payload *, payload, ao2_alloc(sizeof(*payload), NULL), ao2_cleanup);
+       RAII_VAR(struct stasis_subscription *, subscription, NULL, ao2_cleanup);
+
        char *parse;
        struct ast_flags flags = { 0, };
        AST_DECLARE_APP_ARGS(args,
@@ -118,21 +152,48 @@ static int forkcdr_exec(struct ast_channel *chan, const char *data)
                ast_app_parse_options(forkcdr_exec_options, &flags, NULL, args.options);
        }
 
-       if (ast_cdr_fork(ast_channel_name(chan), &flags)) {
-               ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s\n", ast_channel_name(chan));
+       if (!payload) {
+               return -1;
+       }
+
+       payload->channel_name = ast_channel_name(chan);
+       payload->flags = &flags;
+       message = stasis_message_create(forkcdr_message_type(), payload);
+       if (!message) {
+               ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s: unable to create message\n",
+                       ast_channel_name(chan));
+               return -1;
+       }
+
+       subscription = stasis_subscribe(ast_channel_topic(chan), forkcdr_callback, NULL);
+       if (!subscription) {
+               ast_log(AST_LOG_WARNING, "Failed to fork CDR for channel %s: unable to create subscription\n",
+                       payload->channel_name);
+               return -1;
        }
 
+       stasis_publish(ast_channel_topic(chan), message);
+
+       subscription = stasis_unsubscribe_and_join(subscription);
+
        return 0;
 }
 
 static int unload_module(void)
 {
+       STASIS_MESSAGE_TYPE_CLEANUP(forkcdr_message_type);
+
        return ast_unregister_application(app);
 }
 
 static int load_module(void)
 {
-       return ast_register_application_xml(app, forkcdr_exec);
+       int res = 0;
+
+       res |= STASIS_MESSAGE_TYPE_INIT(forkcdr_message_type);
+       res |= ast_register_application_xml(app, forkcdr_exec);
+
+       return res;
 }
 
 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");