Statistics
| Branch: | Revision:

janus-gateway / events.c @ 1f44763c

History | View | Annotate | Download (8.41 KB)

1 6c173b76 Lorenzo Miniero
/*! \file    events.c
2
 * \author   Lorenzo Miniero <lorenzo@meetecho.com>
3
 * \copyright GNU General Public License v3
4
 * \brief    Event handler notifications
5
 * \details  Event handler plugins can receive events from the Janus core
6
 * and other plugins, in order to handle them somehow. This methods
7
 * provide helpers to notify events to such handlers. 
8
 * 
9
 * \ingroup core
10
 * \ref core
11
 */
12
 
13
#include <stdarg.h>
14
15
#include "events.h"
16
#include "utils.h"
17
18 1d31e31f Lorenzo Miniero
static gboolean eventsenabled = FALSE;
19 6c173b76 Lorenzo Miniero
static GHashTable *eventhandlers = NULL;
20 d97e0296 Lorenzo Miniero
21
static GAsyncQueue *events = NULL;
22
static json_t exit_event;
23
24
static GThread *events_thread;
25
void *janus_events_thread(void *data);
26
27
int janus_events_init(gboolean enabled, GHashTable *handlers) {
28
        /* We setup a thread for passing events to the handlers */
29
        GError *error = NULL;
30
        events_thread = g_thread_try_new("janus events thread", janus_events_thread, NULL, &error);
31
        if(error != NULL) {
32
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Events handler thread...\n", error->code, error->message ? error->message : "??");
33
                return -1;
34
        }
35
        events = g_async_queue_new();
36 6c173b76 Lorenzo Miniero
        eventhandlers = handlers;
37 d97e0296 Lorenzo Miniero
        eventsenabled = enabled;
38
        return 0;
39
}
40
41
void janus_events_deinit(void) {
42
        eventsenabled = FALSE;
43
44
        g_async_queue_push(events, &exit_event);
45
        if(events_thread != NULL) {
46
                g_thread_join(events_thread);
47
                events_thread = NULL;
48
        }
49 a906be89 Lorenzo Miniero
        if(events != NULL)
50
                g_async_queue_unref(events);
51 6c173b76 Lorenzo Miniero
}
52
53 1d31e31f Lorenzo Miniero
gboolean janus_events_is_enabled(void) {
54
        return eventsenabled;
55
}
56
57 6c173b76 Lorenzo Miniero
void janus_events_notify_handlers(int type, guint64 session_id, ...) {
58 3f4cdb2c Lorenzo Miniero
        /* This method has a variable list of arguments, depending on the event type */
59
        va_list args;
60
        va_start(args, session_id);
61
62
        if(!eventsenabled || eventhandlers == NULL || g_hash_table_size(eventhandlers) == 0) {
63
                /* Event handlers disabled, or no event handler plugins available: free resources, if needed */
64
                if(type == JANUS_EVENT_TYPE_MEDIA || type == JANUS_EVENT_TYPE_WEBRTC) {
65
                        /* These events allocate a json_t object for their data, skip some arguments and unref it */
66
                        va_arg(args, guint64);
67
                        json_t *body = va_arg(args, json_t *);
68
                        json_decref(body);
69
                } else if(type == JANUS_EVENT_TYPE_CORE) {
70
                        /* Core events also allocate a json_t object for its data, unref it */
71
                        json_t *body = va_arg(args, json_t *);
72
                        json_decref(body);
73 5e1c5670 Lorenzo Miniero
                } else if(type == JANUS_EVENT_TYPE_SESSION) {
74
                        /* Session events may allocate a json_t object for transport-related info, unref it */
75
                        va_arg(args, char *);
76
                        json_t *transport = va_arg(args, json_t *);
77
                        if(transport != NULL)
78
                                json_decref(transport);
79
                } else if(type == JANUS_EVENT_TYPE_PLUGIN) {
80 3f4cdb2c Lorenzo Miniero
                        /* Plugin originated events also allocate a json_t object for the plugin data, skip some arguments and unref it */
81
                        va_arg(args, guint64);
82
                        va_arg(args, char *);
83
                        json_t *data = va_arg(args, json_t *);
84
                        json_decref(data);
85 5e1c5670 Lorenzo Miniero
                } else if(type == JANUS_EVENT_TYPE_TRANSPORT) {
86
                        /* Transport originated events also allocate a json_t object for the transport data, skip some arguments and unref it */
87
                        va_arg(args, char *);
88
                        va_arg(args, void *);
89
                        json_t *data = va_arg(args, json_t *);
90
                        json_decref(data);
91 3f4cdb2c Lorenzo Miniero
                }
92
                va_end(args);
93 6c173b76 Lorenzo Miniero
                return;
94 3f4cdb2c Lorenzo Miniero
        }
95 6c173b76 Lorenzo Miniero
96
        /* Prepare the event to notify as a Jansson json_t object */
97
        json_t *event = json_object();
98
        json_object_set_new(event, "type", json_integer(type));
99 60bdc106 Lorenzo Miniero
        json_object_set_new(event, "timestamp", json_integer(janus_get_real_time()));
100 c734a91a Lorenzo Miniero
        if(type != JANUS_EVENT_TYPE_CORE) {                        /* Core events don't have a session ID */
101
                if(session_id == 0 && (type == JANUS_EVENT_TYPE_PLUGIN || type == JANUS_EVENT_TYPE_TRANSPORT)) {
102
                        /* ... but plugin/transport events may not have one either */
103
                } else {
104
                        json_object_set_new(event, "session_id", json_integer(session_id));
105
                }
106
        }
107 6c173b76 Lorenzo Miniero
        json_t *body = NULL;
108 eba63a19 Lorenzo Miniero
        if(type != JANUS_EVENT_TYPE_MEDIA && type != JANUS_EVENT_TYPE_WEBRTC && type != JANUS_EVENT_TYPE_CORE)
109 6c173b76 Lorenzo Miniero
                body = json_object();
110
111
        /* Each type may require different arguments */
112
        switch(type) {
113
                case JANUS_EVENT_TYPE_SESSION: {
114
                        /* For sessions, there's just a generic event name (what happened) */
115
                        char *name = va_arg(args, char *);
116
                        json_object_set_new(body, "name", json_string(name));
117 5e1c5670 Lorenzo Miniero
                        json_t *transport = va_arg(args, json_t *);
118
                        if(transport != NULL)
119
                                json_object_set(body, "transport", transport);
120 6c173b76 Lorenzo Miniero
                        break;
121
                }
122
                case JANUS_EVENT_TYPE_HANDLE: {
123 4d8c7356 Lorenzo Miniero
                        /* For handles, there's the handle ID, a generic event name (what happened)
124
                         * and the plugin package name this handle is (or was) attached to */
125 6c173b76 Lorenzo Miniero
                        guint64 handle_id = va_arg(args, guint64);
126
                        json_object_set_new(event, "handle_id", json_integer(handle_id));
127
                        char *name = va_arg(args, char *);
128
                        json_object_set_new(body, "name", json_string(name));
129 4d8c7356 Lorenzo Miniero
                        char *plugin = va_arg(args, char *);
130
                        json_object_set_new(body, "plugin", json_string(plugin));
131 c8ca0de5 Lorenzo Miniero
                        /* Handle-related events may include an opaque ID provided by who's using the plugin:
132
                         * in event handlers, it may be useful for inter-handle mappings or other things */
133
                        char *opaque_id = va_arg(args, char *);
134
                        if(opaque_id != NULL)
135
                                json_object_set_new(body, "opaque_id", json_string(opaque_id));
136 6c173b76 Lorenzo Miniero
                        break;
137
                }
138
                case JANUS_EVENT_TYPE_JSEP: {
139
                        /* For JSEP-related events, there's the handle ID, whether the SDP is local or remote, the JSEP type and the SDP itself */
140
                        guint64 handle_id = va_arg(args, guint64);
141
                        json_object_set_new(event, "handle_id", json_integer(handle_id));
142
                        char *owner = va_arg(args, char *);
143
                        json_object_set_new(body, "owner", json_string(owner));
144
                        json_t *jsep = json_object();
145
                        char *sdp_type = va_arg(args, char *);
146
                        json_object_set_new(jsep, "type", json_string(sdp_type));
147
                        char *sdp = va_arg(args, char *);
148
                        json_object_set_new(jsep, "sdp", json_string(sdp));
149
                        json_object_set_new(body, "jsep", jsep);
150
                        break;
151
                }
152
                case JANUS_EVENT_TYPE_WEBRTC:
153
                case JANUS_EVENT_TYPE_MEDIA: {
154
                        /* For WebRTC and media-related events, there's the handle ID and a json_t object with info on what happened */
155
                        guint64 handle_id = va_arg(args, guint64);
156
                        json_object_set_new(event, "handle_id", json_integer(handle_id));
157
                        /* The body is what we get from the event */
158
                        body = va_arg(args, json_t *);
159
                        break;
160
                }
161 5e1c5670 Lorenzo Miniero
                case JANUS_EVENT_TYPE_PLUGIN: {
162 6c173b76 Lorenzo Miniero
                        /* For plugin-originated events, there's the handle ID, the plugin name, and a generic, plugin specific, json_t object */
163
                        guint64 handle_id = va_arg(args, guint64);
164 c734a91a Lorenzo Miniero
                        if(handle_id > 0)        /* Plugins and transports may not specify a session and handle ID for out of context events */
165
                                json_object_set_new(event, "handle_id", json_integer(handle_id));
166 6c173b76 Lorenzo Miniero
                        char *name = va_arg(args, char *);
167
                        json_object_set_new(body, "plugin", json_string(name));
168
                        json_t *data = va_arg(args, json_t *);
169
                        json_object_set(body, "data", data);
170
                        break;
171
                }
172 5e1c5670 Lorenzo Miniero
                case JANUS_EVENT_TYPE_TRANSPORT: {
173
                        char *name = va_arg(args, char *);
174
                        json_object_set_new(body, "transport", json_string(name));
175
                        char *instance = va_arg(args, void *);
176
                        char id[32];
177
                        memset(id, 0, sizeof(id));
178
                        g_snprintf(id, sizeof(id), "%p", instance);
179
                        json_object_set_new(body, "id", json_string(id));
180
                        json_t *data = va_arg(args, json_t *);
181
                        json_object_set(body, "data", data);
182
                        break;
183
                }
184 84c1291c Lorenzo Miniero
                case JANUS_EVENT_TYPE_CORE: {
185
                        /* For core-related events, there's a json_t object with info on what happened */
186
                        body = va_arg(args, json_t *);
187
                        break;
188
                }
189 6c173b76 Lorenzo Miniero
                default:
190
                        JANUS_LOG(LOG_WARN, "Unknown event type '%d'\n", type);
191
                        json_decref(event);
192
                        json_decref(body);
193
                        return;
194
        }
195
        json_object_set_new(event, "event", body);
196
        va_end(args);
197
198 d97e0296 Lorenzo Miniero
        /* Enqueue the event */
199
        g_async_queue_push(events, event);
200
}
201
202
void *janus_events_thread(void *data) {
203
        JANUS_LOG(LOG_VERB, "Joining Events handler thread\n");
204
        json_t *event = NULL;
205
206
        while(eventsenabled) {
207
                /* Any event in queue? */
208
                event = g_async_queue_pop(events);
209
                if(event == NULL)
210 6c173b76 Lorenzo Miniero
                        continue;
211 d97e0296 Lorenzo Miniero
                if(event == &exit_event)
212
                        break;
213
214
                /* Notify all interested handlers, increasing the event reference to make sure it's not lost because of errors */
215
                int type = json_integer_value(json_object_get(event, "type"));
216
                GHashTableIter iter;
217
                gpointer value;
218
                g_hash_table_iter_init(&iter, eventhandlers);
219
                json_incref(event);
220
                while(g_hash_table_iter_next(&iter, NULL, &value)) {
221
                        janus_eventhandler *e = value;
222
                        if(e == NULL)
223
                                continue;
224
                        if(!janus_flags_is_set(&e->events_mask, type))
225
                                continue;
226
                        e->incoming_event(event);
227
                }
228
                json_decref(event);
229
230
                /* Unref the final event reference, interested handlers will have their own reference */
231
                json_decref(event);
232 6c173b76 Lorenzo Miniero
        }
233 d97e0296 Lorenzo Miniero
234
        JANUS_LOG(LOG_VERB, "Leaving EchoTest handler thread\n");
235
        return NULL;
236 6c173b76 Lorenzo Miniero
}