]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
cel: Add STREAM_BEGIN, STREAM_END and DTMF event types.
authorSperl Viktor <viktike32@gmail.com>
Mon, 30 Jun 2025 11:38:50 +0000 (13:38 +0200)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Mon, 11 Aug 2025 13:52:30 +0000 (13:52 +0000)
Fixes: #1280
UserNote: Enabling the tracking of the
STREAM_BEGIN and the STREAM_END event
types in cel.conf will log media files and
music on hold played to each channel.
The STREAM_BEGIN event's extra field will
contain a JSON with the file details (path,
format and language), or the class name, in
case of music on hold is played. The DTMF
event's extra field will contain a JSON with
the digit and the duration in milliseconds.

configs/samples/cel.conf.sample
include/asterisk/cel.h
main/cel.c
main/channel.c
main/file.c
res/res_musiconhold.c

index 755fcd3eda47a4f8d0edf9283f35080d06fe1c49..f6f90cf108d66b7199371dae9f66c540c99c2ea5 100644 (file)
@@ -59,6 +59,12 @@ apps=dial,park
 ;  USER_DEFINED     -- Triggered from the dialplan, and has a name given by the
 ;                      user
 ;  LOCAL_OPTIMIZE   -- A local channel pair is optimizing away.
+;  STREAM_BEGIN     -- A stream started playing: it can be a standalone sound file
+;                      playing back, or a music-on-hold class started
+;  STREAM_END       -- A playing stream ended
+;  DTMF             -- A DTMF digit was processed: these events are dispatched at the
+;                      end, when the button is released and the duration is present in
+;                      the extra field
 ;
 ; Default value: none
 ;                (Track no events)
index 7444938ce69dc9e3c54dd2e8d23c22623137244c..8a1e8b884f12ad253a90cdea5763d7b45f3f70f6 100644 (file)
@@ -77,6 +77,12 @@ enum ast_cel_event_type {
        AST_CEL_LOCAL_OPTIMIZE = 17,
        /*! \brief A local channel optimization has begun */
        AST_CEL_LOCAL_OPTIMIZE_BEGIN = 18,
+       /*! \brief A stream started */
+       AST_CEL_STREAM_BEGIN = 19,
+       /*! \brief A stream ended */
+       AST_CEL_STREAM_END = 20,
+       /*! \brief A DTMF digit was processed */
+       AST_CEL_DTMF = 21,
 };
 
 /*!
index 26440f4a4b3fe75a6e443478868ab56c1b6af950..4e99f632429ece7d9cc8c13a3640204f486aeeb7 100644 (file)
                                                <enum name="LINKEDID_END"/>
                                                <enum name="LOCAL_OPTIMIZE"/>
                                                <enum name="LOCAL_OPTIMIZE_BEGIN"/>
+                                               <enum name="STREAM_BEGIN"/>
+                                               <enum name="STREAM_END"/>
+                                               <enum name="DTMF"/>
                                        </enumlist>
                                        </description>
                                </configOption>
@@ -338,6 +341,9 @@ static const char * const cel_event_types[CEL_MAX_EVENT_IDS] = {
        [AST_CEL_LINKEDID_END]     = "LINKEDID_END",
        [AST_CEL_LOCAL_OPTIMIZE]   = "LOCAL_OPTIMIZE",
        [AST_CEL_LOCAL_OPTIMIZE_BEGIN]   = "LOCAL_OPTIMIZE_BEGIN",
+       [AST_CEL_STREAM_BEGIN]     = "STREAM_BEGIN",
+       [AST_CEL_STREAM_END]       = "STREAM_END",
+       [AST_CEL_DTMF]             = "DTMF",
 };
 
 struct cel_backend {
@@ -849,12 +855,8 @@ int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *
        r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
 
        r->event_name = ast_cel_get_type_name(r->event_type);
-       if (r->event_type == AST_CEL_USER_DEFINED) {
-               r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
-       } else {
-               r->user_defined_name = "";
-       }
 
+       r->user_defined_name= S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME), "");
        r->caller_id_name   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
        r->caller_id_num    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNUM), "");
        r->caller_id_ani    = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDANI), "");
@@ -1282,6 +1284,8 @@ static void cel_generic_cb(
 
        switch (event_type) {
        case AST_CEL_USER_DEFINED:
+       case AST_CEL_DTMF:
+       case AST_CEL_STREAM_BEGIN:
                {
                        const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
                        struct ast_json *extra = ast_json_object_get(event_details, "extra");
@@ -1289,6 +1293,13 @@ static void cel_generic_cb(
                                event, extra, NULL);
                        break;
                }
+       case AST_CEL_STREAM_END:
+               {
+                       const char *event = ast_json_string_get(ast_json_object_get(event_details, "event"));
+                       cel_report_event(obj->snapshot, event_type, stasis_message_timestamp(message),
+                               event, NULL, NULL);
+                       break;
+               }
        default:
                ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
                break;
index 374d6974c5d7bd557b9f48bdf8ec7afde90977ae..dc7bbdf7bd11ccb4f63b14d5a52d4982f3fa636a 100644 (file)
@@ -42,6 +42,7 @@
 #include "asterisk/mod_format.h"
 #include "asterisk/sched.h"
 #include "asterisk/channel.h"
+#include "asterisk/cel.h"
 #include "asterisk/musiconhold.h"
 #include "asterisk/say.h"
 #include "asterisk/file.h"
@@ -3338,34 +3339,45 @@ static const char *dtmf_direction_to_string(enum DtmfDirection direction)
 static void send_dtmf_begin_event(struct ast_channel *chan,
        enum DtmfDirection direction, const char digit)
 {
-       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+       RAII_VAR(struct ast_json *, channel_blob, NULL, ast_json_unref);
        char digit_str[] = { digit, '\0' };
 
-       blob = ast_json_pack("{ s: s, s: s }",
+       channel_blob = ast_json_pack("{ s: s, s: s }",
                "digit", digit_str,
                "direction", dtmf_direction_to_string(direction));
-       if (!blob) {
-               return;
-       }
 
-       ast_channel_publish_blob(chan, ast_channel_dtmf_begin_type(), blob);
+       if (channel_blob) {
+               ast_channel_publish_blob(chan, ast_channel_dtmf_begin_type(), channel_blob);
+       }
 }
 
 static void send_dtmf_end_event(struct ast_channel *chan,
        enum DtmfDirection direction, const char digit, long duration_ms)
 {
-       RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
+       RAII_VAR(struct ast_json *, channel_blob, NULL, ast_json_unref);
+       RAII_VAR(struct ast_json *, cel_blob, NULL, ast_json_unref);
        char digit_str[] = { digit, '\0' };
 
-       blob = ast_json_pack("{ s: s, s: s, s: I }",
+       channel_blob = ast_json_pack("{ s: s, s: s, s: I }",
                "digit", digit_str,
                "direction", dtmf_direction_to_string(direction),
                "duration_ms", (ast_json_int_t)duration_ms);
-       if (!blob) {
-               return;
+
+       if (channel_blob) {
+               ast_channel_publish_blob(chan, ast_channel_dtmf_end_type(), channel_blob);
        }
 
-       ast_channel_publish_blob(chan, ast_channel_dtmf_end_type(), blob);
+       cel_blob = ast_json_pack("{ s: s, s: { s: s, s: I }}",
+               "event", dtmf_direction_to_string(direction),
+               "extra",
+                       "digit", digit_str,
+                       "duration_ms", (ast_json_int_t)duration_ms);
+
+       if (cel_blob) {
+               ast_cel_publish_event(chan, AST_CEL_DTMF, cel_blob);
+       } else {
+               ast_log(LOG_WARNING, "Unable to build extradata for DTMF CEL event on channel %s", ast_channel_name(chan));
+       }
 }
 
 static void send_flash_event(struct ast_channel *chan)
index 039e33b19aa65d0fadb5492f5bb87f76d25dfce5..eb45911d54e7aa015c4457c0520907c1d0477c4c 100644 (file)
@@ -39,6 +39,7 @@
 #include "asterisk/mod_format.h"
 #include "asterisk/cli.h"
 #include "asterisk/channel.h"
+#include "asterisk/cel.h"
 #include "asterisk/sched.h"
 #include "asterisk/translate.h"
 #include "asterisk/utils.h"
@@ -221,15 +222,25 @@ int ast_file_fdtemp(const char *path, char **filename, const char *template_name
 
 int ast_stopstream(struct ast_channel *tmp)
 {
+       struct ast_json * cel_event = NULL;
+
        ast_channel_lock(tmp);
 
        /* Stop a running stream if there is one */
        if (ast_channel_stream(tmp)) {
                ast_closestream(ast_channel_stream(tmp));
                ast_channel_stream_set(tmp, NULL);
+
+               cel_event = ast_json_pack("{ s: s }", "event", "FILE_STREAM_END");
+               if (cel_event) {
+                       ast_cel_publish_event(tmp, AST_CEL_STREAM_END, cel_event);
+               }
+
                if (ast_channel_oldwriteformat(tmp) && ast_set_write_format(tmp, ast_channel_oldwriteformat(tmp)))
                        ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_format_get_name(ast_channel_oldwriteformat(tmp)));
        }
+       ast_json_unref(cel_event);
+
        /* Stop the video stream too */
        if (ast_channel_vstream(tmp) != NULL) {
                ast_closestream(ast_channel_vstream(tmp));
@@ -1301,6 +1312,7 @@ int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj
 int ast_streamfile(struct ast_channel *chan, const char *filename,
        const char *preflang)
 {
+       struct ast_json * cel_event = NULL;
        struct ast_filestream *fs = NULL;
        struct ast_filestream *vfs = NULL;
        off_t pos;
@@ -1367,6 +1379,20 @@ int ast_streamfile(struct ast_channel *chan, const char *filename,
        if (!res && vfs)
                res = ast_playstream(vfs);
 
+       cel_event = ast_json_pack("{ s: s, s: {s: s, s: s, s: s}}",
+               "event", "FILE_STREAM_BEGIN",
+               "extra",
+                       "sound", tmp_filename,
+                       "format", ast_format_get_name(ast_channel_writeformat(chan)),
+                       "language", preflang ? preflang : "default"
+       );
+       if (cel_event) {
+               ast_cel_publish_event(chan, AST_CEL_STREAM_BEGIN, cel_event);
+       } else {
+               ast_log(LOG_WARNING, "Unable to build extradata for sound file STREAM_BEGIN event on channel %s", ast_channel_name(chan));
+       }
+       ast_json_unref(cel_event);
+
        if (VERBOSITY_ATLEAST(3)) {
                ast_channel_lock(chan);
                ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), tmp_filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default");
index 64bd2261906ec2b8a7dd5353c7e339aa5bf24f4e..3c8941e3451caf5f38b3e845ed7f5f76a3cc6be2 100644 (file)
@@ -54,6 +54,7 @@
 #include "asterisk/lock.h"
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
+#include "asterisk/cel.h"
 #include "asterisk/pbx.h"
 #include "asterisk/app.h"
 #include "asterisk/module.h"
@@ -253,10 +254,23 @@ static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
 {
        struct stasis_message *message;
        struct ast_json *json_object;
+       struct ast_json *cel_event;
 
        ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n",
                moh_class_name, ast_channel_name(chan));
 
+       cel_event = ast_json_pack("{ s: s, s: {s: s }}",
+               "event", "MOH_STREAM_BEGIN",
+               "extra",
+                       "class", moh_class_name
+       );
+       if (cel_event) {
+               ast_cel_publish_event(chan, AST_CEL_STREAM_BEGIN, cel_event);
+       } else {
+               ast_log(LOG_WARNING, "Unable to build extradata for music on hold STREAM_BEGIN event on channel %s", ast_channel_name(chan));
+       }
+       ast_json_unref(cel_event);
+
        json_object = ast_json_pack("{s: s}", "class", moh_class_name);
        if (!json_object) {
                return;
@@ -277,9 +291,16 @@ static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
 static void moh_post_stop(struct ast_channel *chan)
 {
        struct stasis_message *message;
+       struct ast_json *cel_event;
 
        ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
 
+       cel_event = ast_json_pack("{ s: s }", "event", "MOH_STREAM_END");
+       if (cel_event) {
+               ast_cel_publish_event(chan, AST_CEL_STREAM_END, cel_event);
+       }
+       ast_json_unref(cel_event);
+
        message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
                ast_channel_moh_stop_type(), NULL);
        if (message) {