Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_audiobridge.c @ 71a04f89

History | View | Annotate | Download (121 KB)

1
/*! \file   janus_audiobridge.c
2
 * \author Lorenzo Miniero <lorenzo@meetecho.com>
3
 * \copyright GNU General Public License v3
4
 * \brief  Janus AudioBridge plugin
5
 * \details  This is a plugin implementing an audio conference bridge for
6
 * Janus, specifically mixing Opus streams. This means that it replies
7
 * by providing in the SDP only support for Opus, and disabling video.
8
 * Opus encoding and decoding is implemented using libopus (http://opus.codec.org).
9
 * The plugin provides an API to allow peers to join and leave conference
10
 * rooms. Peers can then mute/unmute themselves by sending specific messages
11
 * to the plugin: any way a peer mutes/unmutes, an event is triggered
12
 * to the other participants, so that it can be rendered in the UI
13
 * accordingly.
14
 * 
15
 * Rooms to make available are listed in the plugin configuration file.
16
 * A pre-filled configuration file is provided in \c conf/janus.plugin.audiobridge.cfg
17
 * and includes a demo room for testing.
18
 * 
19
 * To add more rooms or modify the existing one, you can use the following
20
 * syntax:
21
 * 
22
 * \verbatim
23
[<unique room ID>]
24
description = This is my awesome room
25
is_private = yes|no (private rooms don't appear when you do a 'list' request)
26
secret = <optional password needed for manipulating (e.g. destroying) the room>
27
pin = <optional password needed for joining the room>
28
sampling_rate = <sampling rate> (e.g., 16000 for wideband mixing)
29
record = true|false (whether this room should be recorded, default=false)
30
record_file =        /path/to/recording.wav (where to save the recording)
31
\endverbatim
32
 *
33
 * \section bridgeapi Audio Bridge API
34
 * 
35
 * The Audio Bridge API supports several requests, some of which are
36
 * synchronous and some asynchronous. There are some situations, though,
37
 * (invalid JSON, invalid request) which will always result in a
38
 * synchronous error response even for asynchronous requests. 
39
 * 
40
 * \c create , \c destroy , \c exists, \c list, \c listparticipants
41
 * and \c resetdecoder are synchronous requests, which means you'll
42
 * get a response directly within the context of the transaction.
43
 * \c create allows you to create a new audio conference bridge
44
 * dynamically, as an alternative to using the configuration file;
45
 * \c destroy removes an audio conference bridge and destroys it, kicking
46
 * all the users out as part of the process; \c exists allows you to
47
 * check whether a specific audio conference exists; \c list
48
 * lists all the available rooms, while \c listparticipants lists all
49
 * the participants of a specific room and their details; finally,
50
 * \c resetdecoder marks the Opus decoder for the participant as invalid,
51
 * and forces it to be recreated (which might be needed if the audio
52
 * for generated by the participant becomes garbled). 
53
 * 
54
 * The \c join , \c configure , \c changeroom and \c leave requests
55
 * instead are all asynchronous, which means you'll get a notification
56
 * about their success or failure in an event. \c join allows you to
57
 * join a specific audio conference bridge; \c configure can be used
58
 * to modify some of the participation settings (e.g., mute/unmute);
59
 * \c changeroom can be used to leave the current room and move to a
60
 * different one without having to tear down the PeerConnection and
61
 * recreate it again (useful for sidebars and "waiting rooms"); finally,
62
 * \c leave allows you to leave an audio conference bridge for good.
63
 * 
64
 * \c create can be used to create a new audio room, and has to be
65
 * formatted as follows:
66
 * 
67
\verbatim
68
{
69
        "request" : "create",
70
        "room" : <unique numeric ID, optional, chosen by plugin if missing>,
71
        "permanent" : <true|false, whether the room should be saved in the config file, default false>,
72
        "description" : "<pretty name of the room, optional>",
73
        "secret" : "<password required to edit/destroy the room, optional>",
74
        "pin" : "<password required to join the room, optional>",
75
        "is_private" : <true|false, whether the room should appear in a list request>,
76
        "sampling" : <sampling rate of the room, optional, 16000 by default>,
77
        "record" : <true|false, whether to record the room or not, default false>,
78
        "record_file" : "</path/to/the/recording.wav, optional>",
79
}
80
\endverbatim
81
 *
82
 * A successful creation procedure will result in a \c created response:
83
 * 
84
\verbatim
85
{
86
        "audiobridge" : "created",
87
        "room" : <unique numeric ID>
88
}
89
\endverbatim
90
 *
91
 * An error instead (and the same applies to all other requests, so this
92
 * won't be repeated) would provide both an error code and a more verbose
93
 * description of the cause of the issue:
94
 * 
95
\verbatim
96
{
97
        "audiobridge" : "event",
98
        "error_code" : <numeric ID, check Macros below>,
99
        "error" : "<error description as a string>"
100
}
101
\endverbatim
102
 * 
103
 * Notice that, in general, all users can create rooms. If you want to
104
 * limit this functionality, you can configure an admin \c admin_key in
105
 * the plugin settings. When configured, only "create" requests that
106
 * include the correct \c admin_key value in an "admin_key" property
107
 * will succeed, and will be rejected otherwise.
108
 * 
109
 * On the other hand, \c destroy can be used to destroy an existing audio
110
 * room, whether created dynamically or statically, and has to be
111
 * formatted as follows:
112
 * 
113
\verbatim
114
{
115
        "request" : "destroy",
116
        "room" : <unique numeric ID of the room to destroy>,
117
        "secret" : "<room secret, mandatory if configured>",
118
        "permanent" : <true|false, whether the room should be also removed from the config file, default false>
119
}
120
\endverbatim
121
 *
122
 * A successful destruction procedure will result in a \c destroyed response:
123
 * 
124
\verbatim
125
{
126
        "audiobridge" : "created",
127
        "room" : <unique numeric ID>
128
}
129
\endverbatim
130
 *
131
 * You can check whether a room exists using the \c exists request,
132
 * which has to be formatted as follows:
133
 * 
134
\verbatim
135
{
136
        "request" : "exists",
137
        "room" : <unique numeric ID of the room to check>
138
}
139
\endverbatim
140
 *
141
 * A successful request will result in a \c success response:
142
 * 
143
\verbatim
144
{
145
        "audiobridge" : "success",
146
        "room" : <unique numeric ID>,
147
        "exists" : <true|false>
148
}
149
\endverbatim
150
 * 
151
 * To get a list of the available rooms (excluded those configured or
152
 * created as private rooms) you can make use of the \c list request,
153
 * which has to be formatted as follows:
154
 * 
155
\verbatim
156
{
157
        "request" : "list"
158
}
159
\endverbatim
160
 *
161
 * A successful request will produce a list of rooms in a \c success response:
162
 * 
163
\verbatim
164
{
165
        "audiobridge" : "success",
166
        "rooms" : [                // Array of room objects
167
                {        // Room #1
168
                        "room" : <unique numeric ID>,
169
                        "description" : "<Name of the room>",
170
                        "sampling_rate" : <sampling rate of the mixer>,
171
                        "record" : <true|false, whether the room is being recorded>,
172
                        "num_participants" : <count of the participants>
173
                },
174
                // Other rooms
175
        ]
176
}
177
\endverbatim
178
 *
179
 * To get a list of the participants in a specific room, instead, you
180
 * can make use of the \c listparticipants request, which has to be
181
 * formatted as follows:
182
 * 
183
\verbatim
184
{
185
        "request" : "listparticipants",
186
        "room" : <unique numeric ID of the room>
187
}
188
\endverbatim
189
 *
190
 * A successful request will produce a list of participants in a
191
 * \c participants response:
192
 * 
193
\verbatim
194
{
195
        "audiobridge" : "participants",
196
        "room" : <unique numeric ID of the room>,
197
        "participants" : [                // Array of participant objects
198
                {        // Participant #1
199
                        "id" : <unique numeric ID of the participant>,
200
                        "display" : "<display name of the participant, if any; optional>",
201
                        "muted" : <true|false, whether user is muted or not>
202
                },
203
                // Other participants
204
        ]
205
}
206
\endverbatim
207
 * 
208
 * To mark the Opus decoder context for the current participant as
209
 * invalid and force it to be recreated, use the \c resetdecoder request:
210
 * 
211
\verbatim
212
{
213
        "request" : "resetdecoder"
214
}
215
\endverbatim
216
 *
217
 * A successful request will produce a \c success response:
218
 * 
219
\verbatim
220
{
221
        "audiobridge" : "success"
222
}
223
\endverbatim
224
 * 
225
 * That completes the list of synchronous requests you can send to the
226
 * AudioBridge plugin. As anticipated, though, there are also several
227
 * asynchronous requests you can send, specifically those related to
228
 * joining and updating one's presence as a participant in an audio room.
229
 * 
230
 * The way you'd interact with the plugin is usually as follows:
231
 * 
232
 * -# you use a \c join request to join an audio room, and wait for the
233
 * \c joined event; this event will also include a list of the other
234
 * participants, if any;
235
 * -# you send a \c configure request attached to an audio-only JSEP offer
236
 * to start configuring your participation in the room (e.g., join unmuted
237
 * or muted), and wait for a \c configured event, which will be attached
238
 * to a JSEP answer by the plugin to complete the setup of the WebRTC
239
 * PeerConnection;
240
 * -# you send other \c configure requests (without any JSEP-related
241
 * attachment) to mute/unmute yourself during the audio conference;
242
 * -# you intercept events originated by the plugin (\c joined , \c leaving )
243
 * to notify you about users joining/leaving/muting/unmuting;
244
 * -# you eventually send a \c leave request to leave a room; if you leave the
245
 * PeerConnection instance intact, you can subsequently join a different
246
 * room without requiring a new negotiation (and so just use a \c join + JSEP-less \c configure to join).
247
 * 
248
 * Notice that there's also a \c changeroom request available: you can use
249
 * this request to immediately leave the room you're in and join a different
250
 * one, without requiring you to do a \c leave + \c join + \c configure
251
 * round. Of course remember not to pass any JSEP-related payload when
252
 * doing a \c changeroom as the same pre-existing PeerConnection will be
253
 * re-used for the purpose.
254
 * 
255
 * About the syntax of all the above mentioned requests, \c join has
256
 * to be formatted as follows:
257
 * 
258
\verbatim
259
{
260
        "request" : "join",
261
        "room" : <numeric ID of the room to join>,
262
        "id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
263
        "pin" : "<password required to join the room, if any; optional>",
264
        "display" : "<display name to have in the room; optional>",
265
        "muted" : <true|false, whether to start unmuted or muted>,
266
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>
267
}
268
\endverbatim
269
 *
270
 * A successful request will produce a \c joined event:
271
 * 
272
\verbatim
273
{
274
        "audiobridge" : "joined",
275
        "room" : <numeric ID of the room>,
276
        "id" : <unique ID assigned to the participant>,
277
        "display" : "<display name of the new participant>",
278
        "participants" : [
279
                // Array of existing participants in the room
280
        ]
281
}
282
\endverbatim
283
 * 
284
 * The other participants in the room will be notified about the new
285
 * participant by means of a different \c joined event, which will only
286
 * include the \c room and the new participant as the only object in
287
 * a \c participants array.
288
 *
289
 * At this point, the media-related settings of the participant can be
290
 * modified by means of a \c configure request. The \c configure request
291
 * has to be formatted as follows:
292
 *
293
\verbatim
294
{
295
        "request" : "configure",
296
        "muted" : <true|false, whether to unmute or mute>,
297
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>,
298
        "record": <true|false, whether to record this user's contribution to a .mjr file (mixer not involved),
299
        "filename": "<basename of the file to record to, -audio.mjr will be added by the plugin>"
300
}
301
\endverbatim
302
 *
303
 * \c muted instructs the plugin to mute or unmute the participant;
304
 * \c quality changes the complexity of the Opus encoder for the
305
 * participant; \c record can be used to record this participant's contribution
306
 * to a Janus .mjr file, and \c filename to provide a basename for the path to
307
 * save the file to (notice that this is different from the recording of a whole
308
 * room: this feature only records the packets this user is sending, and is not
309
 * related to the mixer stuff). A successful request will result in a \c ok event:
310
 * 
311
\verbatim
312
{
313
        "audiobridge" : "event",
314
        "room" : <numeric ID of the room>,
315
        "result" : "ok"
316
}
317
\endverbatim
318
 *
319
 * In case the \c muted property was modified, the other participants in
320
 * the room will be notified about this by means of a \c event notification,
321
 * which will only include the \c room and the updated participant as the
322
 * only object in a \c participants array.
323
 *
324
 * As anticipated, you can leave an audio room using the \c leave request,
325
 * which has to be formatted as follows:
326
 * 
327
\verbatim
328
{
329
        "request" : "leave"
330
}
331
\endverbatim
332
 * 
333
 * All the participants will receive an \c event notification with the
334
 * ID of the participant who just left:
335
 * 
336
\verbatim
337
{
338
        "audiobridge" : "event",
339
        "room" : <numeric ID of the room>,
340
        "leaving" : <numeric ID of the participant who left>
341
}
342
\endverbatim
343
 *
344
 * For what concerns the \c changeroom request, instead, it's pretty much
345
 * the same as a \c join request and as such has to be formatted as follows:
346
 * 
347
\verbatim
348
{
349
        "request" : "changeroom",
350
        "room" : <numeric ID of the room to move to>,
351
        "id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
352
        "display" : "<display name to have in the room; optional>",
353
        "muted" : <true|false, whether to start unmuted or muted>,
354
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>
355
}
356
\endverbatim
357
 * 
358
 * Such a request will trigger all the above-described leaving/joined
359
 * events to the other participants, as it is indeed wrapping a \c leave
360
 * followed by a \c join and as such the other participants in both rooms
361
 * need to be updated accordingly. The participant who switched room
362
 * instead will be sent a \c roomchanged event which is pretty similar
363
 * to what \c joined looks like:
364
 * 
365
 * A successful request will produce a \c joined event:
366
 * 
367
\verbatim
368
{
369
        "audiobridge" : "roomchanged",
370
        "room" : <numeric ID of the new room>,
371
        "id" : <unique ID assigned to the participant in the new room>,
372
        "display" : "<display name of the new participant>",
373
        "participants" : [
374
                // Array of existing participants in the new room
375
        ]
376
}
377
\endverbatim
378
 *  
379
 * \ingroup plugins
380
 * \ref plugins
381
 */
382

    
383
#include "plugin.h"
384

    
385
#include <jansson.h>
386
#include <opus/opus.h>
387
#include <sys/time.h>
388

    
389
#include "../debug.h"
390
#include "../apierror.h"
391
#include "../config.h"
392
#include "../mutex.h"
393
#include "../rtp.h"
394
#include "../rtcp.h"
395
#include "../record.h"
396
#include "../utils.h"
397

    
398

    
399
/* Plugin information */
400
#define JANUS_AUDIOBRIDGE_VERSION                        9
401
#define JANUS_AUDIOBRIDGE_VERSION_STRING        "0.0.9"
402
#define JANUS_AUDIOBRIDGE_DESCRIPTION                "This is a plugin implementing an audio conference bridge for Janus, mixing Opus streams."
403
#define JANUS_AUDIOBRIDGE_NAME                                "JANUS AudioBridge plugin"
404
#define JANUS_AUDIOBRIDGE_AUTHOR                        "Meetecho s.r.l."
405
#define JANUS_AUDIOBRIDGE_PACKAGE                        "janus.plugin.audiobridge"
406

    
407
/* Plugin methods */
408
janus_plugin *create(void);
409
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path);
410
void janus_audiobridge_destroy(void);
411
int janus_audiobridge_get_api_compatibility(void);
412
int janus_audiobridge_get_version(void);
413
const char *janus_audiobridge_get_version_string(void);
414
const char *janus_audiobridge_get_description(void);
415
const char *janus_audiobridge_get_name(void);
416
const char *janus_audiobridge_get_author(void);
417
const char *janus_audiobridge_get_package(void);
418
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error);
419
struct janus_plugin_result *janus_audiobridge_handle_message(janus_plugin_session *handle, char *transaction, char *message, char *sdp_type, char *sdp);
420
void janus_audiobridge_setup_media(janus_plugin_session *handle);
421
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len);
422
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len);
423
void janus_audiobridge_hangup_media(janus_plugin_session *handle);
424
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error);
425
char *janus_audiobridge_query_session(janus_plugin_session *handle);
426

    
427
/* Plugin setup */
428
static janus_plugin janus_audiobridge_plugin =
429
        JANUS_PLUGIN_INIT (
430
                .init = janus_audiobridge_init,
431
                .destroy = janus_audiobridge_destroy,
432

    
433
                .get_api_compatibility = janus_audiobridge_get_api_compatibility,
434
                .get_version = janus_audiobridge_get_version,
435
                .get_version_string = janus_audiobridge_get_version_string,
436
                .get_description = janus_audiobridge_get_description,
437
                .get_name = janus_audiobridge_get_name,
438
                .get_author = janus_audiobridge_get_author,
439
                .get_package = janus_audiobridge_get_package,
440
                
441
                .create_session = janus_audiobridge_create_session,
442
                .handle_message = janus_audiobridge_handle_message,
443
                .setup_media = janus_audiobridge_setup_media,
444
                .incoming_rtp = janus_audiobridge_incoming_rtp,
445
                .incoming_rtcp = janus_audiobridge_incoming_rtcp,
446
                .hangup_media = janus_audiobridge_hangup_media,
447
                .destroy_session = janus_audiobridge_destroy_session,
448
                .query_session = janus_audiobridge_query_session,
449
        );
450

    
451
/* Plugin creator */
452
janus_plugin *create(void) {
453
        JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_AUDIOBRIDGE_NAME);
454
        return &janus_audiobridge_plugin;
455
}
456

    
457
/* Parameter validation */
458
static struct janus_json_parameter request_parameters[] = {
459
        {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
460
};
461
static struct janus_json_parameter adminkey_parameters[] = {
462
        {"admin_key", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
463
};
464
static struct janus_json_parameter create_parameters[] = {
465
        {"description", JSON_STRING, 0},
466
        {"secret", JSON_STRING, 0},
467
        {"pin", JSON_STRING, 0},
468
        {"is_private", JANUS_JSON_BOOL, 0},
469
        {"sampling", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
470
        {"record", JANUS_JSON_BOOL, 0},
471
        {"record_file", JSON_STRING, 0},
472
        {"permanent", JANUS_JSON_BOOL, 0},
473
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
474
};
475
static struct janus_json_parameter destroy_parameters[] = {
476
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
477
        {"permanent", JANUS_JSON_BOOL, 0}
478
};
479
static struct janus_json_parameter room_parameters[] = {
480
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
481
};
482
static struct janus_json_parameter join_parameters[] = {
483
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
484
        {"display", JSON_STRING, 0},
485
        {"muted", JANUS_JSON_BOOL, 0},
486
        {"quality", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
487
        {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
488
};
489
static struct janus_json_parameter configure_parameters[] = {
490
        {"muted", JANUS_JSON_BOOL, 0},
491
        {"quality", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
492
        {"record", JANUS_JSON_BOOL, 0},
493
        {"filename", JSON_STRING, 0}
494
};
495

    
496
/* Static configuration instance */
497
static janus_config *config = NULL;
498
static const char *config_folder = NULL;
499
static janus_mutex config_mutex;
500

    
501
/* Useful stuff */
502
static volatile gint initialized = 0, stopping = 0;
503
static gboolean notify_events = TRUE;
504
static janus_callbacks *gateway = NULL;
505
static GThread *handler_thread;
506
static GThread *watchdog;
507
static void *janus_audiobridge_handler(void *data);
508
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data);
509
static void *janus_audiobridge_mixer_thread(void *data);
510
static void *janus_audiobridge_participant_thread(void *data);
511

    
512
typedef struct janus_audiobridge_message {
513
        janus_plugin_session *handle;
514
        char *transaction;
515
        json_t *message;
516
        char *sdp_type;
517
        char *sdp;
518
} janus_audiobridge_message;
519
static GAsyncQueue *messages = NULL;
520
static janus_audiobridge_message exit_message;
521

    
522
static void janus_audiobridge_message_free(janus_audiobridge_message *msg) {
523
        if(!msg || msg == &exit_message)
524
                return;
525

    
526
        msg->handle = NULL;
527

    
528
        g_free(msg->transaction);
529
        msg->transaction = NULL;
530
        if(msg->message)
531
                json_decref(msg->message);
532
        msg->message = NULL;
533
        g_free(msg->sdp_type);
534
        msg->sdp_type = NULL;
535
        g_free(msg->sdp);
536
        msg->sdp = NULL;
537

    
538
        g_free(msg);
539
}
540

    
541

    
542
typedef struct janus_audiobridge_room {
543
        guint64 room_id;                        /* Unique room ID */
544
        gchar *room_name;                        /* Room description */
545
        gchar *room_secret;                        /* Secret needed to manipulate (e.g., destroy) this room */
546
        gchar *room_pin;                        /* Password needed to join this room, if any */
547
        gboolean is_private;                        /* Whether this room is 'private' (as in hidden) or not */
548
        uint32_t sampling_rate;                /* Sampling rate of the mix (e.g., 16000 for wideband; can be 8, 12, 16, 24 or 48kHz) */
549
        gboolean record;                        /* Whether this room has to be recorded or not */
550
        gchar *record_file;                        /* Path of the recording file */
551
        FILE *recording;                        /* File to record the room into */
552
        gboolean destroy;                        /* Value to flag the room for destruction */
553
        GHashTable *participants;        /* Map of participants */
554
        GThread *thread;                        /* Mixer thread for this room */
555
        gint64 destroyed;                        /* When this room has been destroyed */
556
        janus_mutex mutex;                        /* Mutex to lock this room instance */
557
} janus_audiobridge_room;
558
static GHashTable *rooms;
559
static janus_mutex rooms_mutex;
560
static GList *old_rooms;
561
static char *admin_key = NULL;
562

    
563
typedef struct janus_audiobridge_session {
564
        janus_plugin_session *handle;
565
        gpointer participant;
566
        gboolean started;
567
        gboolean stopping;
568
        volatile gint hangingup;
569
        gint64 destroyed;        /* Time at which this session was marked as destroyed */
570
} janus_audiobridge_session;
571
static GHashTable *sessions;
572
static GList *old_sessions;
573
static janus_mutex sessions_mutex;
574

    
575
typedef struct janus_audiobridge_rtp_context {
576
        /* Needed to fix seq and ts in case of publisher switching */
577
        uint32_t a_last_ssrc, a_last_ts, a_base_ts, a_base_ts_prev;
578
        uint16_t a_last_seq, a_base_seq, a_base_seq_prev;
579
} janus_audiobridge_rtp_context;
580

    
581
typedef struct janus_audiobridge_participant {
582
        janus_audiobridge_session *session;
583
        janus_audiobridge_room *room;        /* Room */
584
        guint64 user_id;                /* Unique ID in the room */
585
        gchar *display;                        /* Display name (just for fun) */
586
        gboolean prebuffering;        /* Whether this participant needs pre-buffering of a few packets (just joined) */
587
        gboolean active;                /* Whether this participant can receive media at all */
588
        gboolean working;                /* Whether this participant is currently encoding/decoding */
589
        gboolean muted;                        /* Whether this participant is muted */
590
        int opus_complexity;        /* Complexity to use in the encoder (by default, DEFAULT_COMPLEXITY) */
591
        /* RTP stuff */
592
        GList *inbuf;                        /* Incoming audio from this participant, as an ordered list of packets */
593
        GAsyncQueue *outbuf;        /* Mixed audio for this participant */
594
        janus_mutex qmutex;                /* Incoming queue mutex */
595
        int opus_pt;                        /* Opus payload type */
596
        janus_audiobridge_rtp_context context;        /* Needed in case the participant changes room */
597
        /* Opus stuff */
598
        OpusEncoder *encoder;                /* Opus encoder instance */
599
        OpusDecoder *decoder;                /* Opus decoder instance */
600
        gboolean reset;                                /* Whether or not the Opus context must be reset, without re-joining the room */
601
        GThread *thread;                        /* Encoding thread for this participant */
602
        janus_recorder *arc;                /* The Janus recorder instance for this user's audio, if enabled */
603
        janus_mutex rec_mutex;                /* Mutex to protect the recorder from race conditions */
604
        gint64 destroyed;                        /* When this participant has been destroyed */
605
} janus_audiobridge_participant;
606

    
607
/* Packets we get from gstreamer and relay */
608
typedef struct janus_audiobridge_rtp_relay_packet {
609
        rtp_header *data;
610
        gint length;
611
        uint32_t ssrc;
612
        uint32_t timestamp;
613
        uint16_t seq_number;
614
} janus_audiobridge_rtp_relay_packet;
615

    
616
/* Helper to sort incoming RTP packets by sequence numbers */
617
static gint janus_audiobridge_rtp_sort(gconstpointer a, gconstpointer b) {
618
        janus_audiobridge_rtp_relay_packet *pkt1 = (janus_audiobridge_rtp_relay_packet *)a;
619
        janus_audiobridge_rtp_relay_packet *pkt2 = (janus_audiobridge_rtp_relay_packet *)b;
620
        if(pkt1->seq_number < 100 && pkt2->seq_number > 65000) {
621
                /* Sequence number was probably reset, pkt2 is older */
622
                return 1;
623
        } else if(pkt2->seq_number < 100 && pkt1->seq_number > 65000) {
624
                /* Sequence number was probably reset, pkt1 is older */
625
                return -1;
626
        }
627
        /* Simply compare timestamps */
628
        if(pkt1->seq_number < pkt2->seq_number)
629
                return -1;
630
        else if(pkt1->seq_number > pkt2->seq_number)
631
                return 1;
632
        return 0;
633
}
634

    
635
/* SDP offer/answer template */
636
#define sdp_template \
637
                "v=0\r\n" \
638
                "o=- %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n"        /* We need current time here */ \
639
                "s=%s\r\n"                                                        /* Audio bridge name */ \
640
                "t=0 0\r\n" \
641
                "m=audio 1 RTP/SAVPF %d\r\n"                /* Opus payload type */ \
642
                "c=IN IP4 1.1.1.1\r\n" \
643
                "a=rtpmap:%d opus/48000/2\r\n"                /* Opus payload type */ \
644
                "a=fmtp:%d maxplaybackrate=%"SCNu32"; stereo=0; sprop-stereo=0; useinbandfec=0\r\n" \
645
                                                                                        /* Opus payload type and room sampling rate */
646

    
647
/* Helper struct to generate and parse WAVE headers */
648
typedef struct wav_header {
649
        char riff[4];
650
        uint32_t len;
651
        char wave[4];
652
        char fmt[4];
653
        uint32_t formatsize;
654
        uint16_t format;
655
        uint16_t channels;
656
        uint32_t samplerate;
657
        uint32_t avgbyterate;
658
        uint16_t samplebytes;
659
        uint16_t channelbits;
660
        char data[4];
661
        uint32_t blocksize;
662
} wav_header;
663

    
664

    
665
/* Mixer settings */
666
#define DEFAULT_PREBUFFERING        6
667

    
668

    
669
/* Opus settings */                
670
#define        BUFFER_SAMPLES        8000
671
#define        OPUS_SAMPLES        160
672
#define USE_FEC                        0
673
#define DEFAULT_COMPLEXITY        4
674

    
675

    
676
/* Error codes */
677
#define JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR        499
678
#define JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE                480
679
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON        481
680
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST        482
681
#define JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT        483
682
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT        484
683
#define JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM        485
684
#define JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS                486
685
#define JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED                487
686
#define JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR        488
687
#define JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED        489
688
#define JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS                490
689
#define JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED        491
690

    
691

    
692
/* AudioBridge watchdog/garbage collector (sort of) */
693
void *janus_audiobridge_watchdog(void *data);
694
void *janus_audiobridge_watchdog(void *data) {
695
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog started\n");
696
        gint64 now = 0;
697
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
698
                janus_mutex_lock(&sessions_mutex);
699
                /* Iterate on all the sessions */
700
                now = janus_get_monotonic_time();
701
                if(old_sessions != NULL) {
702
                        GList *sl = old_sessions;
703
                        JANUS_LOG(LOG_HUGE, "Checking %d old AudioBridge sessions...\n", g_list_length(old_sessions));
704
                        while(sl) {
705
                                janus_audiobridge_session *session = (janus_audiobridge_session *)sl->data;
706
                                if(!session) {
707
                                        sl = sl->next;
708
                                        continue;
709
                                }
710
                                if(now-session->destroyed >= 5*G_USEC_PER_SEC) {
711
                                        /* We're lazy and actually get rid of the stuff only after a few seconds */
712
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge session\n");
713
                                        GList *rm = sl->next;
714
                                        old_sessions = g_list_delete_link(old_sessions, sl);
715
                                        sl = rm;
716
                                        session->handle = NULL;
717
                                        g_free(session);
718
                                        session = NULL;
719
                                        continue;
720
                                }
721
                                sl = sl->next;
722
                        }
723
                }
724
                janus_mutex_unlock(&sessions_mutex);
725
                janus_mutex_lock(&rooms_mutex);
726
                if(old_rooms != NULL) {
727
                        GList *rl = old_rooms;
728
                        now = janus_get_monotonic_time();
729
                        while(rl) {
730
                                janus_audiobridge_room *audiobridge = (janus_audiobridge_room*)rl->data;
731
                                if(!initialized || stopping){
732
                                        break;
733
                                }
734
                                if(!audiobridge) {
735
                                        rl = rl->next;
736
                                        continue;
737
                                }
738
                                if(now - audiobridge->destroyed >= 5*G_USEC_PER_SEC) {
739
                                        /* Free resources */
740
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge room %"SCNu64"\n", audiobridge->room_id);
741
                                        g_free(audiobridge->room_name);
742
                                        g_free(audiobridge->room_secret);
743
                                        g_free(audiobridge->room_pin);
744
                                        g_free(audiobridge->record_file);
745
                                        g_hash_table_destroy(audiobridge->participants);
746
                                        g_free(audiobridge);
747
                                        /* Move on */
748
                                        GList *rm = rl->next;
749
                                        old_rooms = g_list_delete_link(old_rooms, rl);
750
                                        rl = rm;
751
                                        continue;
752
                                }
753
                                rl = rl->next;
754
                        }
755
                }
756
                janus_mutex_unlock(&rooms_mutex);
757
                g_usleep(500000);
758
        }
759
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog stopped\n");
760
        return NULL;
761
}
762

    
763

    
764
/* Plugin implementation */
765
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) {
766
        if(g_atomic_int_get(&stopping)) {
767
                /* Still stopping from before */
768
                return -1;
769
        }
770
        if(callback == NULL || config_path == NULL) {
771
                /* Invalid arguments */
772
                return -1;
773
        }
774

    
775
        /* Read configuration */
776
        char filename[255];
777
        g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_AUDIOBRIDGE_PACKAGE);
778
        JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
779
        config = janus_config_parse(filename);
780
        config_folder = config_path;
781
        if(config != NULL)
782
                janus_config_print(config);
783
        janus_mutex_init(&config_mutex);
784
        
785
        rooms = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
786
        janus_mutex_init(&rooms_mutex);
787
        sessions = g_hash_table_new(NULL, NULL);
788
        janus_mutex_init(&sessions_mutex);
789
        messages = g_async_queue_new_full((GDestroyNotify) janus_audiobridge_message_free);
790
        /* This is the callback we'll need to invoke to contact the gateway */
791
        gateway = callback;
792

    
793
        /* Parse configuration to populate the rooms list */
794
        if(config != NULL) {
795
                /* Any admin key to limit who can "create"? */
796
                janus_config_item *key = janus_config_get_item_drilldown(config, "general", "admin_key");
797
                if(key != NULL && key->value != NULL)
798
                        admin_key = g_strdup(key->value);
799
                janus_config_item *events = janus_config_get_item_drilldown(config, "general", "events");
800
                if(events != NULL && events->value != NULL)
801
                        notify_events = janus_is_true(events->value);
802
                if(!notify_events && callback->events_is_enabled()) {
803
                        JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_AUDIOBRIDGE_NAME);
804
                }
805
                /* Iterate on all rooms */
806
                GList *cl = janus_config_get_categories(config);
807
                while(cl != NULL) {
808
                        janus_config_category *cat = (janus_config_category *)cl->data;
809
                        if(cat->name == NULL || !strcasecmp(cat->name, "general")) {
810
                                cl = cl->next;
811
                                continue;
812
                        }
813
                        JANUS_LOG(LOG_VERB, "Adding audio room '%s'\n", cat->name);
814
                        janus_config_item *desc = janus_config_get_item(cat, "description");
815
                        janus_config_item *priv = janus_config_get_item(cat, "is_private");
816
                        janus_config_item *sampling = janus_config_get_item(cat, "sampling_rate");
817
                        janus_config_item *secret = janus_config_get_item(cat, "secret");
818
                        janus_config_item *pin = janus_config_get_item(cat, "pin");
819
                        janus_config_item *record = janus_config_get_item(cat, "record");
820
                        janus_config_item *recfile = janus_config_get_item(cat, "record_file");
821
                        if(sampling == NULL || sampling->value == NULL) {
822
                                JANUS_LOG(LOG_ERR, "Can't add the audio room, missing mandatory information...\n");
823
                                cl = cl->next;
824
                                continue;
825
                        }
826
                        /* Create the audio bridge room */
827
                        janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room));
828
                        if(audiobridge == NULL) {
829
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
830
                                cl = cl->next;
831
                                continue;
832
                        }
833
                        audiobridge->room_id = atol(cat->name);
834
                        char *description = NULL;
835
                        if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0)
836
                                description = g_strdup(desc->value);
837
                        else
838
                                description = g_strdup(cat->name);
839
                        if(description == NULL) {
840
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
841
                                cl = cl->next;
842
                                continue;
843
                        }
844
                        audiobridge->room_name = description;
845
                        audiobridge->is_private = priv && priv->value && janus_is_true(priv->value);
846
                        audiobridge->sampling_rate = atol(sampling->value);
847
                        switch(audiobridge->sampling_rate) {
848
                                case 8000:
849
                                case 12000:
850
                                case 16000:
851
                                case 24000:
852
                                case 48000:
853
                                        JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
854
                                        break;
855
                                default:
856
                                        JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
857
                                        cl = cl->next;
858
                                        continue;
859
                        }
860
                        if(secret != NULL && secret->value != NULL) {
861
                                audiobridge->room_secret = g_strdup(secret->value);
862
                        }
863
                        if(pin != NULL && pin->value != NULL) {
864
                                audiobridge->room_pin = g_strdup(pin->value);
865
                        }
866
                        audiobridge->record = FALSE;
867
                        if(record && record->value && janus_is_true(record->value))
868
                                audiobridge->record = TRUE;
869
                        if(recfile && recfile->value)
870
                                audiobridge->record_file = g_strdup(recfile->value);
871
                        audiobridge->recording = NULL;
872
                        audiobridge->destroy = 0;
873
                        audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
874
                        audiobridge->destroyed = 0;
875
                        janus_mutex_init(&audiobridge->mutex);
876
                        JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
877
                                audiobridge->room_id, audiobridge->room_name,
878
                                audiobridge->is_private ? "private" : "public",
879
                                audiobridge->room_secret ? audiobridge->room_secret : "no secret",
880
                                audiobridge->room_pin ? audiobridge->room_pin : "no pin");
881
                        /* We need a thread for the mix */
882
                        GError *error = NULL;
883
                        audiobridge->thread = g_thread_try_new("audiobridge mixer thread", &janus_audiobridge_mixer_thread, audiobridge, &error);
884
                        if(error != NULL) {
885
                                /* FIXME We should clear some resources... */
886
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
887
                        } else {
888
                                janus_mutex_lock(&rooms_mutex);
889
                                g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
890
                                janus_mutex_unlock(&rooms_mutex);
891
                        }
892
                        cl = cl->next;
893
                }
894
                /* Done: we keep the configuration file open in case we get a "create" or "destroy" with permanent=true */
895
        }
896

    
897
        /* Show available rooms */
898
        janus_mutex_lock(&rooms_mutex);
899
        GHashTableIter iter;
900
        gpointer value;
901
        g_hash_table_iter_init(&iter, rooms);
902
        while (g_hash_table_iter_next(&iter, NULL, &value)) {
903
                janus_audiobridge_room *ar = value;
904
                JANUS_LOG(LOG_VERB, "  ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n",
905
                        ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT");
906
        }
907
        janus_mutex_unlock(&rooms_mutex);
908

    
909
        g_atomic_int_set(&initialized, 1);
910

    
911
        GError *error = NULL;
912
        /* Start the sessions watchdog */
913
        watchdog = g_thread_try_new("abridge watchdog", &janus_audiobridge_watchdog, NULL, &error);
914
        if(error != NULL) {
915
                g_atomic_int_set(&initialized, 0);
916
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge watchdog thread...\n", error->code, error->message ? error->message : "??");
917
                janus_config_destroy(config);
918
                return -1;
919
        }
920
        /* Launch the thread that will handle incoming messages */
921
        handler_thread = g_thread_try_new("janus audiobridge handler", janus_audiobridge_handler, NULL, &error);
922
        if(error != NULL) {
923
                g_atomic_int_set(&initialized, 0);
924
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", error->code, error->message ? error->message : "??");
925
                janus_config_destroy(config);
926
                return -1;
927
        }
928
        JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_AUDIOBRIDGE_NAME);
929
        return 0;
930
}
931

    
932
void janus_audiobridge_destroy(void) {
933
        if(!g_atomic_int_get(&initialized))
934
                return;
935
        g_atomic_int_set(&stopping, 1);
936

    
937
        g_async_queue_push(messages, &exit_message);
938
        if(handler_thread != NULL) {
939
                g_thread_join(handler_thread);
940
                handler_thread = NULL;
941
        }
942
        if(watchdog != NULL) {
943
                g_thread_join(watchdog);
944
                watchdog = NULL;
945
        }
946
        /* FIXME We should destroy the sessions cleanly */
947
        janus_mutex_lock(&sessions_mutex);
948
        g_hash_table_destroy(sessions);
949
        janus_mutex_unlock(&sessions_mutex);
950
        janus_mutex_lock(&rooms_mutex);
951
        g_hash_table_destroy(rooms);
952
        janus_mutex_unlock(&rooms_mutex);
953
        g_async_queue_unref(messages);
954
        messages = NULL;
955
        sessions = NULL;
956

    
957
        janus_config_destroy(config);
958
        g_free(admin_key);
959

    
960
        g_atomic_int_set(&initialized, 0);
961
        g_atomic_int_set(&stopping, 0);
962
        JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_AUDIOBRIDGE_NAME);
963
}
964

    
965
int janus_audiobridge_get_api_compatibility(void) {
966
        /* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
967
        return JANUS_PLUGIN_API_VERSION;
968
}
969

    
970
int janus_audiobridge_get_version(void) {
971
        return JANUS_AUDIOBRIDGE_VERSION;
972
}
973

    
974
const char *janus_audiobridge_get_version_string(void) {
975
        return JANUS_AUDIOBRIDGE_VERSION_STRING;
976
}
977

    
978
const char *janus_audiobridge_get_description(void) {
979
        return JANUS_AUDIOBRIDGE_DESCRIPTION;
980
}
981

    
982
const char *janus_audiobridge_get_name(void) {
983
        return JANUS_AUDIOBRIDGE_NAME;
984
}
985

    
986
const char *janus_audiobridge_get_author(void) {
987
        return JANUS_AUDIOBRIDGE_AUTHOR;
988
}
989

    
990
const char *janus_audiobridge_get_package(void) {
991
        return JANUS_AUDIOBRIDGE_PACKAGE;
992
}
993

    
994
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error) {
995
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
996
                *error = -1;
997
                return;
998
        }        
999
        janus_audiobridge_session *session = (janus_audiobridge_session *)g_malloc0(sizeof(janus_audiobridge_session));
1000
        if(session == NULL) {
1001
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
1002
                *error = -2;
1003
                return;
1004
        }
1005
        session->handle = handle;
1006
        session->started = FALSE;
1007
        session->stopping = FALSE;
1008
        session->destroyed = 0;
1009
        g_atomic_int_set(&session->hangingup, 0);
1010
        handle->plugin_handle = session;
1011
        janus_mutex_lock(&sessions_mutex);
1012
        g_hash_table_insert(sessions, handle, session);
1013
        janus_mutex_unlock(&sessions_mutex);
1014

    
1015
        return;
1016
}
1017

    
1018
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error) {
1019
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1020
                *error = -1;
1021
                return;
1022
        }        
1023
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle; 
1024
        if(!session) {
1025
                JANUS_LOG(LOG_ERR, "No AudioBridge session associated with this handle...\n");
1026
                *error = -2;
1027
                return;
1028
        }
1029
        JANUS_LOG(LOG_VERB, "Removing AudioBridge session...\n");
1030
        janus_mutex_lock(&sessions_mutex);
1031
        if(!session->destroyed) {
1032
                g_hash_table_remove(sessions, handle);
1033
                janus_audiobridge_hangup_media(handle);
1034
                session->destroyed = janus_get_monotonic_time();
1035
                /* Cleaning up and removing the session is done in a lazy way */
1036
                old_sessions = g_list_append(old_sessions, session);
1037
        }
1038
        janus_mutex_unlock(&sessions_mutex);
1039

    
1040
        return;
1041
}
1042

    
1043
char *janus_audiobridge_query_session(janus_plugin_session *handle) {
1044
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1045
                return NULL;
1046
        }        
1047
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1048
        if(!session) {
1049
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1050
                return NULL;
1051
        }
1052
        /* Show the participant/room info, if any */
1053
        json_t *info = json_object();
1054
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1055
        json_object_set_new(info, "state", json_string(participant && participant->room ? "inroom" : "idle"));
1056
        if(participant) {
1057
                janus_mutex_lock(&rooms_mutex);
1058
                janus_audiobridge_room *room = participant->room;
1059
                if(room != NULL)
1060
                        json_object_set_new(info, "room", json_integer(room->room_id));
1061
                janus_mutex_unlock(&rooms_mutex);
1062
                json_object_set_new(info, "id", json_integer(participant->user_id));
1063
                if(participant->display)
1064
                        json_object_set_new(info, "display", json_string(participant->display));
1065
                json_object_set_new(info, "muted", json_string(participant->muted ? "true" : "false"));
1066
                json_object_set_new(info, "active", json_string(participant->active ? "true" : "false"));
1067
                json_object_set_new(info, "pre-buffering", json_string(participant->prebuffering ? "true" : "false"));
1068
                if(participant->inbuf) {
1069
                        janus_mutex_lock(&participant->qmutex);
1070
                        json_object_set_new(info, "queue-in", json_integer(g_list_length(participant->inbuf)));
1071
                        janus_mutex_unlock(&participant->qmutex);
1072
                }
1073
                if(participant->outbuf)
1074
                        json_object_set_new(info, "queue-out", json_integer(g_async_queue_length(participant->outbuf)));
1075
                if(participant->arc && participant->arc->filename)
1076
                        json_object_set_new(info, "audio-recording", json_string(participant->arc->filename));
1077
        }
1078
        json_object_set_new(info, "started", json_string(session->started ? "true" : "false"));
1079
        json_object_set_new(info, "destroyed", json_integer(session->destroyed));
1080
        char *info_text = json_dumps(info, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1081
        json_decref(info);
1082
        return info_text;
1083
}
1084

    
1085
struct janus_plugin_result *janus_audiobridge_handle_message(janus_plugin_session *handle, char *transaction, char *message, char *sdp_type, char *sdp) {
1086
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1087
                return janus_plugin_result_new(JANUS_PLUGIN_ERROR, g_atomic_int_get(&stopping) ? "Shutting down" : "Plugin not initialized");
1088

    
1089
        /* Pre-parse the message */
1090
        int error_code = 0;
1091
        char error_cause[512];
1092
        json_t *root = NULL;
1093
        json_t *response = NULL;
1094
        
1095
        if(message == NULL) {
1096
                JANUS_LOG(LOG_ERR, "No message??\n");
1097
                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
1098
                g_snprintf(error_cause, 512, "%s", "No message??");
1099
                goto error;
1100
        }
1101
        JANUS_LOG(LOG_VERB, "Handling message: %s\n", message);
1102

    
1103
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1104
        if(!session) {
1105
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1106
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1107
                g_snprintf(error_cause, 512, "%s", "session associated with this handle...");
1108
                goto error;
1109
        }
1110
        if(session->destroyed) {
1111
                JANUS_LOG(LOG_ERR, "Session has already been marked as destroyed...\n");
1112
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1113
                g_snprintf(error_cause, 512, "%s", "Session has already been marked as destroyed...");
1114
                goto error;
1115
        }
1116
        json_error_t error;
1117
        root = json_loads(message, 0, &error);
1118
        if(!root) {
1119
                JANUS_LOG(LOG_ERR, "JSON error: on line %d: %s\n", error.line, error.text);
1120
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON;
1121
                g_snprintf(error_cause, 512, "JSON error: on line %d: %s", error.line, error.text);
1122
                goto error;
1123
        }
1124
        if(!json_is_object(root)) {
1125
                JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
1126
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON;
1127
                g_snprintf(error_cause, 512, "JSON error: not an object");
1128
                goto error;
1129
        }
1130
        /* Get the request first */
1131
        JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
1132
                error_code, error_cause, TRUE,
1133
                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1134
        if(error_code != 0)
1135
                goto error;
1136
        json_t *request = json_object_get(root, "request");
1137
        /* Some requests ('create', 'destroy', 'exists', 'list') can be handled synchronously */
1138
        const char *request_text = json_string_value(request);
1139
        if(!strcasecmp(request_text, "create")) {
1140
                /* Create a new audiobridge */
1141
                JANUS_LOG(LOG_VERB, "Creating a new audiobridge\n");
1142
                JANUS_VALIDATE_JSON_OBJECT(root, create_parameters,
1143
                        error_code, error_cause, TRUE,
1144
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1145
                if(error_code != 0)
1146
                        goto error;
1147
                if(admin_key != NULL) {
1148
                        /* An admin key was specified: make sure it was provided, and that it's valid */
1149
                        JANUS_VALIDATE_JSON_OBJECT(root, adminkey_parameters,
1150
                                error_code, error_cause, TRUE,
1151
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1152
                        if(error_code != 0)
1153
                                goto error;
1154
                        JANUS_CHECK_SECRET(admin_key, root, "admin_key", error_code, error_cause,
1155
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1156
                        if(error_code != 0)
1157
                                goto error;
1158
                }
1159
                json_t *desc = json_object_get(root, "description");
1160
                json_t *secret = json_object_get(root, "secret");
1161
                json_t *pin = json_object_get(root, "pin");
1162
                json_t *is_private = json_object_get(root, "is_private");
1163
                json_t *sampling = json_object_get(root, "sampling");
1164
                json_t *record = json_object_get(root, "record");
1165
                json_t *recfile = json_object_get(root, "record_file");
1166
                json_t *permanent = json_object_get(root, "permanent");
1167
                gboolean save = permanent ? json_is_true(permanent) : FALSE;
1168
                if(save && config == NULL) {
1169
                        JANUS_LOG(LOG_ERR, "No configuration file, can't create permanent room\n");
1170
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1171
                        g_snprintf(error_cause, 512, "No configuration file, can't create permanent room");
1172
                        goto error;
1173
                }
1174
                guint64 room_id = 0;
1175
                json_t *room = json_object_get(root, "room");
1176
                room_id = json_integer_value(room);
1177
                if(room_id == 0) {
1178
                        JANUS_LOG(LOG_WARN, "Desired room ID is 0, which is not allowed... picking random ID instead\n");
1179
                }
1180
                janus_mutex_lock(&rooms_mutex);
1181
                if(room_id > 0) {
1182
                        /* Let's make sure the room doesn't exist already */
1183
                        if(g_hash_table_lookup(rooms, &room_id) != NULL) {
1184
                                /* It does... */
1185
                                janus_mutex_unlock(&rooms_mutex);
1186
                                JANUS_LOG(LOG_ERR, "Room %"SCNu64" already exists!\n", room_id);
1187
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS;
1188
                                g_snprintf(error_cause, 512, "Room %"SCNu64" already exists", room_id);
1189
                                goto error;
1190
                        }
1191
                }
1192
                /* Create the audio bridge room */
1193
                janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room));
1194
                if(audiobridge == NULL) {
1195
                        janus_mutex_unlock(&rooms_mutex);
1196
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1197
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1198
                        g_snprintf(error_cause, 512, "Memory error");
1199
                        goto error;
1200
                }
1201
                /* Generate a random ID */
1202
                if(room_id == 0) {
1203
                        while(room_id == 0) {
1204
                                room_id = janus_random_uint64();
1205
                                if(g_hash_table_lookup(rooms, &room_id) != NULL) {
1206
                                        /* Room ID already taken, try another one */
1207
                                        room_id = 0;
1208
                                }
1209
                        }
1210
                }
1211
                audiobridge->room_id = room_id;
1212
                char *description = NULL;
1213
                if(desc != NULL && strlen(json_string_value(desc)) > 0) {
1214
                        description = g_strdup(json_string_value(desc));
1215
                } else {
1216
                        char roomname[255];
1217
                        g_snprintf(roomname, 255, "Room %"SCNu64"", audiobridge->room_id);
1218
                        description = g_strdup(roomname);
1219
                }
1220
                if(description == NULL) {
1221
                        janus_mutex_unlock(&rooms_mutex);
1222
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1223
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1224
                        g_snprintf(error_cause, 512, "Memory error");
1225
                        goto error;
1226
                }
1227
                audiobridge->room_name = description;
1228
                audiobridge->is_private = is_private ? json_is_true(is_private) : FALSE;
1229
                if(secret)
1230
                        audiobridge->room_secret = g_strdup(json_string_value(secret));
1231
                if(pin)
1232
                        audiobridge->room_pin = g_strdup(json_string_value(pin));
1233
                if(sampling)
1234
                        audiobridge->sampling_rate = json_integer_value(sampling);
1235
                else
1236
                        audiobridge->sampling_rate = 16000;
1237
                switch(audiobridge->sampling_rate) {
1238
                        case 8000:
1239
                        case 12000:
1240
                        case 16000:
1241
                        case 24000:
1242
                        case 48000:
1243
                                JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
1244
                                break;
1245
                        default:
1246
                                janus_mutex_unlock(&rooms_mutex);
1247
                                JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
1248
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1249
                                g_snprintf(error_cause, 512, "We currently only support 16kHz (wideband) as a sampling rate for audio rooms, %"SCNu32" TBD...", audiobridge->sampling_rate);
1250
                                goto error;
1251
                }
1252
                audiobridge->record = FALSE;
1253
                if(record && json_is_true(record))
1254
                        audiobridge->record = TRUE;
1255
                if(recfile)
1256
                        audiobridge->record_file = g_strdup(json_string_value(recfile));
1257
                audiobridge->recording = NULL;
1258
                audiobridge->destroy = 0;
1259
                audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
1260
                audiobridge->destroyed = 0;
1261
                janus_mutex_init(&audiobridge->mutex);
1262
                g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1263
                JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
1264
                        audiobridge->room_id, audiobridge->room_name,
1265
                        audiobridge->is_private ? "private" : "public",
1266
                        audiobridge->room_secret ? audiobridge->room_secret : "no secret",
1267
                        audiobridge->room_pin ? audiobridge->room_pin : "no pin");
1268
                /* We need a thread for the mix */
1269
                GError *error = NULL;
1270
                audiobridge->thread = g_thread_try_new("audiobridge mixer thread", &janus_audiobridge_mixer_thread, audiobridge, &error);
1271
                if(error != NULL) {
1272
                        janus_mutex_unlock(&rooms_mutex);
1273
                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
1274
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1275
                        g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the mixer thread", error->code, error->message ? error->message : "??");
1276
                        g_free(audiobridge->room_name);
1277
                        g_free(audiobridge->room_secret);
1278
                        g_free(audiobridge->record_file);
1279
                        g_hash_table_destroy(audiobridge->participants);
1280
                        g_free(audiobridge);
1281
                        goto error;
1282
                } else {
1283
                        g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1284
                }
1285
                if(save) {
1286
                        /* This room is permanent: save to the configuration file too
1287
                         * FIXME: We should check if anything fails... */
1288
                        JANUS_LOG(LOG_VERB, "Saving room %"SCNu64" permanently in config file\n", audiobridge->room_id);
1289
                        janus_mutex_lock(&config_mutex);
1290
                        char cat[BUFSIZ], value[BUFSIZ];
1291
                        /* The room ID is the category */
1292
                        g_snprintf(cat, BUFSIZ, "%"SCNu64, audiobridge->room_id);
1293
                        janus_config_add_category(config, cat);
1294
                        /* Now for the values */
1295
                        janus_config_add_item(config, cat, "description", audiobridge->room_name);
1296
                        if(audiobridge->is_private)
1297
                                janus_config_add_item(config, cat, "is_private", "yes");
1298
                        g_snprintf(value, BUFSIZ, "%"SCNu32, audiobridge->sampling_rate);
1299
                        janus_config_add_item(config, cat, "sampling_rate", value);
1300
                        if(audiobridge->room_secret)
1301
                                janus_config_add_item(config, cat, "secret", audiobridge->room_secret);
1302
                        if(audiobridge->room_pin)
1303
                                janus_config_add_item(config, cat, "pin", audiobridge->room_pin);
1304
                        if(audiobridge->record_file) {
1305
                                janus_config_add_item(config, cat, "record", "yes");
1306
                                janus_config_add_item(config, cat, "record_file", audiobridge->record_file);
1307
                        }
1308
                        /* Save modified configuration */
1309
                        janus_config_save(config, config_folder, JANUS_AUDIOBRIDGE_PACKAGE);
1310
                        janus_mutex_unlock(&config_mutex);
1311
                }
1312
                /* Send info back */
1313
                response = json_object();
1314
                json_object_set_new(response, "audiobridge", json_string("created"));
1315
                json_object_set_new(response, "room", json_integer(audiobridge->room_id));
1316
                /* Also notify event handlers */
1317
                if(notify_events && gateway->events_is_enabled()) {
1318
                        json_t *info = json_object();
1319
                        json_object_set_new(info, "event", json_string("created"));
1320
                        json_object_set_new(info, "room", json_integer(audiobridge->room_id));
1321
                        gateway->notify_event(session->handle, info);
1322
                }
1323
                janus_mutex_unlock(&rooms_mutex);
1324
                goto plugin_response;
1325
        } else if(!strcasecmp(request_text, "destroy")) {
1326
                JANUS_LOG(LOG_VERB, "Attempt to destroy an existing audiobridge room\n");
1327
                JANUS_VALIDATE_JSON_OBJECT(root, destroy_parameters,
1328
                        error_code, error_cause, TRUE,
1329
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1330
                if(error_code != 0)
1331
                        goto error;
1332
                json_t *room = json_object_get(root, "room");
1333
                json_t *permanent = json_object_get(root, "permanent");
1334
                gboolean save = permanent ? json_is_true(permanent) : FALSE;
1335
                if(save && config == NULL) {
1336
                        JANUS_LOG(LOG_ERR, "No configuration file, can't destroy room permanently\n");
1337
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1338
                        g_snprintf(error_cause, 512, "No configuration file, can't destroy room permanently");
1339
                        goto error;
1340
                }
1341
                guint64 room_id = json_integer_value(room);
1342
                janus_mutex_lock(&rooms_mutex);
1343
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1344
                if(audiobridge == NULL) {
1345
                        janus_mutex_unlock(&rooms_mutex);
1346
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1347
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1348
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1349
                        goto error;
1350
                }
1351
                janus_mutex_lock(&audiobridge->mutex);
1352
                /* A secret may be required for this action */
1353
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1354
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1355
                if(error_code != 0) {
1356
                        janus_mutex_unlock(&audiobridge->mutex);
1357
                        janus_mutex_unlock(&rooms_mutex);
1358
                        goto error;
1359
                }
1360
                /* Remove room */
1361
                g_hash_table_remove(rooms, &room_id);
1362
                if(save) {
1363
                        /* This change is permanent: save to the configuration file too
1364
                         * FIXME: We should check if anything fails... */
1365
                        JANUS_LOG(LOG_VERB, "Destroying room %"SCNu64" permanently in config file\n", room_id);
1366
                        janus_mutex_lock(&config_mutex);
1367
                        char cat[BUFSIZ];
1368
                        /* The room ID is the category */
1369
                        g_snprintf(cat, BUFSIZ, "%"SCNu64, room_id);
1370
                        janus_config_remove_category(config, cat);
1371
                        /* Save modified configuration */
1372
                        janus_config_save(config, config_folder, JANUS_AUDIOBRIDGE_PACKAGE);
1373
                        janus_mutex_unlock(&config_mutex);
1374
                }
1375
                /* Prepare response/notification */
1376
                response = json_object();
1377
                json_object_set_new(response, "audiobridge", json_string("destroyed"));
1378
                json_object_set_new(response, "room", json_integer(room_id));
1379
                char *response_text = json_dumps(response, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1380
                /* Notify all participants that the fun is over, and that they'll be kicked */
1381
                JANUS_LOG(LOG_VERB, "Notifying all participants\n");
1382
                GHashTableIter iter;
1383
                gpointer value;
1384
                g_hash_table_iter_init(&iter, audiobridge->participants);
1385
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1386
                        janus_audiobridge_participant *p = value;
1387
                        if(p && p->session) {
1388
                                p->room = NULL;
1389
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, response_text, NULL, NULL);
1390
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1391
                                /* Get rid of queued packets */
1392
                                janus_mutex_lock(&p->qmutex);
1393
                                p->active = FALSE;
1394
                                while(p->inbuf) {
1395
                                        GList *first = g_list_first(p->inbuf);
1396
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1397
                                        p->inbuf = g_list_remove_link(p->inbuf, first);
1398
                                        first = NULL;
1399
                                        if(pkt == NULL)
1400
                                                continue;
1401
                                        if(pkt->data)
1402
                                                g_free(pkt->data);
1403
                                        pkt->data = NULL;
1404
                                        g_free(pkt);
1405
                                        pkt = NULL;
1406
                                }
1407
                                janus_mutex_unlock(&p->qmutex);
1408
                        }
1409
                }
1410
                g_free(response_text);
1411
                /* Also notify event handlers */
1412
                if(notify_events && gateway->events_is_enabled()) {
1413
                        json_t *info = json_object();
1414
                        json_object_set_new(info, "event", json_string("destroyed"));
1415
                        json_object_set_new(info, "room", json_integer(room_id));
1416
                        gateway->notify_event(session->handle, info);
1417
                }
1418
                JANUS_LOG(LOG_VERB, "Waiting for the mixer thread to complete...\n");
1419
                audiobridge->destroyed = janus_get_monotonic_time();
1420
                janus_mutex_unlock(&audiobridge->mutex);
1421
                janus_mutex_unlock(&rooms_mutex);
1422
                g_thread_join(audiobridge->thread);
1423
                /* Done */
1424
                JANUS_LOG(LOG_VERB, "Audiobridge room destroyed\n");
1425
                goto plugin_response;
1426
        } else if(!strcasecmp(request_text, "list")) {
1427
                /* List all rooms (but private ones) and their details (except for the secret, of course...) */
1428
                json_t *list = json_array();
1429
                JANUS_LOG(LOG_VERB, "Request for the list for all video rooms\n");
1430
                janus_mutex_lock(&rooms_mutex);
1431
                GHashTableIter iter;
1432
                gpointer value;
1433
                g_hash_table_iter_init(&iter, rooms);
1434
                while(g_hash_table_iter_next(&iter, NULL, &value)) {
1435
                        janus_audiobridge_room *room = value;
1436
                        if(!room)
1437
                                continue;
1438
                        janus_mutex_lock(&room->mutex);
1439
                        if(room->is_private) {
1440
                                /* Skip private room */
1441
                                janus_mutex_unlock(&room->mutex);
1442
                                JANUS_LOG(LOG_VERB, "Skipping private room '%s'\n", room->room_name);
1443
                                continue;
1444
                        }
1445
                        json_t *rl = json_object();
1446
                        json_object_set_new(rl, "room", json_integer(room->room_id));
1447
                        json_object_set_new(rl, "description", json_string(room->room_name));
1448
                        json_object_set_new(rl, "sampling_rate", json_integer(room->sampling_rate));
1449
                        json_object_set_new(rl, "record", json_string(room->record ? "true" : "false"));
1450
                        /* TODO: Possibly list participant details... or make it a separate API call for a specific room */
1451
                        json_object_set_new(rl, "num_participants", json_integer(g_hash_table_size(room->participants)));
1452
                        json_array_append_new(list, rl);
1453
                        janus_mutex_unlock(&room->mutex);
1454
                }
1455
                janus_mutex_unlock(&rooms_mutex);
1456
                response = json_object();
1457
                json_object_set_new(response, "audiobridge", json_string("success"));
1458
                json_object_set_new(response, "list", list);
1459
                goto plugin_response;
1460
        } else if(!strcasecmp(request_text, "exists")) {
1461
                /* Check whether a given room exists or not, returns true/false */        
1462
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
1463
                        error_code, error_cause, TRUE,
1464
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1465
                if(error_code != 0)
1466
                        goto error;
1467
                json_t *room = json_object_get(root, "room");
1468
                guint64 room_id = json_integer_value(room);
1469
                janus_mutex_lock(&rooms_mutex);
1470
                gboolean room_exists = g_hash_table_contains(rooms, &room_id);
1471
                janus_mutex_unlock(&rooms_mutex);
1472
                response = json_object();
1473
                json_object_set_new(response, "audiobridge", json_string("success"));
1474
                json_object_set_new(response, "room", json_integer(room_id));
1475
                json_object_set_new(response, "exists", json_string(room_exists ? "true" : "false"));
1476
                goto plugin_response;
1477
        } else if(!strcasecmp(request_text, "listparticipants")) {
1478
                /* List all participants in a room */        
1479
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
1480
                        error_code, error_cause, TRUE,
1481
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1482
                if(error_code != 0)
1483
                        goto error;
1484
                json_t *room = json_object_get(root, "room");
1485
                guint64 room_id = json_integer_value(room);
1486
                janus_mutex_lock(&rooms_mutex);
1487
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1488
                if(audiobridge == NULL) {
1489
                        janus_mutex_unlock(&rooms_mutex);
1490
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1491
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1492
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1493
                        goto error;
1494
                }
1495
                janus_mutex_lock(&audiobridge->mutex);
1496
                if(audiobridge->destroyed) {
1497
                        janus_mutex_unlock(&audiobridge->mutex);
1498
                        janus_mutex_unlock(&rooms_mutex);
1499
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1500
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1501
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1502
                        goto error;
1503
                }
1504
                /* Return a list of all participants */
1505
                json_t *list = json_array();
1506
                GHashTableIter iter;
1507
                gpointer value;
1508
                g_hash_table_iter_init(&iter, audiobridge->participants);
1509
                while (!audiobridge->destroyed && g_hash_table_iter_next(&iter, NULL, &value)) {
1510
                        janus_audiobridge_participant *p = value;
1511
                        json_t *pl = json_object();
1512
                        json_object_set_new(pl, "id", json_integer(p->user_id));
1513
                        if(p->display)
1514
                                json_object_set_new(pl, "display", json_string(p->display));
1515
                        json_object_set_new(pl, "muted", json_string(p->muted ? "true" : "false"));
1516
                        json_array_append_new(list, pl);
1517
                }
1518
                janus_mutex_unlock(&audiobridge->mutex);
1519
                janus_mutex_unlock(&rooms_mutex);
1520
                response = json_object();
1521
                json_object_set_new(response, "audiobridge", json_string("participants"));
1522
                json_object_set_new(response, "room", json_integer(room_id));
1523
                json_object_set_new(response, "participants", list);
1524
                goto plugin_response;
1525
        } else if(!strcasecmp(request_text, "resetdecoder")) {
1526
                /* Mark the Opus decoder for the participant invalid and recreate it */        
1527
                janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1528
                if(participant == NULL || participant->room == NULL) {
1529
                        JANUS_LOG(LOG_ERR, "Can't reset (not in a room)\n");
1530
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
1531
                        g_snprintf(error_cause, 512, "Can't reset (not in a room)");
1532
                        goto error;
1533
                }
1534
                participant->reset = TRUE;
1535
                response = json_object();
1536
                json_object_set_new(response, "audiobridge", json_string("success"));
1537
                goto plugin_response;
1538
        } else if(!strcasecmp(request_text, "join") || !strcasecmp(request_text, "configure")
1539
                        || !strcasecmp(request_text, "changeroom") || !strcasecmp(request_text, "leave")) {
1540
                /* These messages are handled asynchronously */
1541
                janus_audiobridge_message *msg = g_malloc0(sizeof(janus_audiobridge_message));
1542
                if(msg == NULL) {
1543
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1544
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1545
                        g_snprintf(error_cause, 512, "Memory error");
1546
                        goto error;
1547
                }
1548

    
1549
                g_free(message);
1550
                msg->handle = handle;
1551
                msg->transaction = transaction;
1552
                msg->message = root;
1553
                msg->sdp_type = sdp_type;
1554
                msg->sdp = sdp;
1555

    
1556
                g_async_queue_push(messages, msg);
1557

    
1558
                return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL);
1559
        } else {
1560
                JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
1561
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
1562
                g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
1563
                goto error;
1564
        }
1565

    
1566
plugin_response:
1567
                {
1568
                        if (!response) {
1569
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1570
                                g_snprintf(error_cause, 512, "Invalid response");
1571
                                goto error;
1572
                        }
1573
                        if(root != NULL)
1574
                                json_decref(root);
1575
                        g_free(transaction);
1576
                        g_free(message);
1577
                        g_free(sdp_type);
1578
                        g_free(sdp);
1579

    
1580
                        char *response_text = json_dumps(response, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1581
                        json_decref(response);
1582
                        janus_plugin_result *result = janus_plugin_result_new(JANUS_PLUGIN_OK, response_text);
1583
                        g_free(response_text);
1584
                        return result;
1585
                }
1586

    
1587
error:
1588
                {
1589
                        if(root != NULL)
1590
                                json_decref(root);
1591
                        g_free(transaction);
1592
                        g_free(message);
1593
                        g_free(sdp_type);
1594
                        g_free(sdp);
1595

    
1596
                        /* Prepare JSON error event */
1597
                        json_t *event = json_object();
1598
                        json_object_set_new(event, "audiobridge", json_string("event"));
1599
                        json_object_set_new(event, "error_code", json_integer(error_code));
1600
                        json_object_set_new(event, "error", json_string(error_cause));
1601
                        char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1602
                        json_decref(event);
1603
                        janus_plugin_result *result = janus_plugin_result_new(JANUS_PLUGIN_OK, event_text);
1604
                        g_free(event_text);
1605
                        return result;
1606
                }
1607

    
1608
}
1609

    
1610
void janus_audiobridge_setup_media(janus_plugin_session *handle) {
1611
        JANUS_LOG(LOG_INFO, "WebRTC media is now available\n");
1612
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1613
                return;
1614
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1615
        if(!session) {
1616
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1617
                return;
1618
        }
1619
        if(session->destroyed)
1620
                return;
1621
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1622
        if(!participant)
1623
                return;
1624
        g_atomic_int_set(&session->hangingup, 0);
1625
        /* FIXME Only send this peer the audio mix when we get this event */
1626
        session->started = TRUE;
1627
}
1628

    
1629
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len) {
1630
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1631
                return;
1632
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1633
        if(!session || session->destroyed || session->stopping || !session->participant)
1634
                return;
1635
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1636
        if(!participant->active || participant->muted || !participant->decoder || !participant->room)
1637
                return;
1638
        /* Save the frame if we're recording this leg */
1639
        janus_recorder_save_frame(participant->arc, buf, len);
1640
        if(participant->active && participant->decoder) {
1641
                /* First of all, check if a reset on the decoder is due */
1642
                if(participant->reset) {
1643
                        /* Create a new decoder and get rid of the old one */
1644
                        int error = 0;
1645
                        OpusDecoder *decoder = opus_decoder_create(participant->room->sampling_rate, 1, &error);
1646
                        if(error != OPUS_OK) {
1647
                                JANUS_LOG(LOG_ERR, "Error resetting Opus decoder...\n");
1648
                        } else {
1649
                                if(participant->decoder)
1650
                                        opus_decoder_destroy(participant->decoder);
1651
                                participant->decoder = decoder;
1652
                                JANUS_LOG(LOG_VERB, "Opus decoder reset\n");
1653
                        }
1654
                        participant->reset = FALSE;
1655
                }
1656
                /* Decode frame (Opus -> slinear) */
1657
                rtp_header *rtp = (rtp_header *)buf;
1658
                janus_audiobridge_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
1659
                if(pkt == NULL) {
1660
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1661
                        return;
1662
                }
1663
                pkt->data = g_malloc0(BUFFER_SAMPLES*sizeof(opus_int16));
1664
                if(pkt->data == NULL) {
1665
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1666
                        g_free(pkt);
1667
                        return;
1668
                }
1669
                pkt->ssrc = 0;
1670
                pkt->timestamp = ntohl(rtp->timestamp);
1671
                pkt->seq_number = ntohs(rtp->seq_number);
1672
                participant->working = TRUE;
1673
                pkt->length = opus_decode(participant->decoder, (const unsigned char *)buf+12, len-12, (opus_int16 *)pkt->data, BUFFER_SAMPLES, USE_FEC);
1674
                participant->working = FALSE;
1675
                if(pkt->length < 0) {
1676
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", pkt->length, opus_strerror(pkt->length));
1677
                        g_free(pkt->data);
1678
                        g_free(pkt);
1679
                        return;
1680
                }
1681
                /* Enqueue the decoded frame */
1682
                janus_mutex_lock(&participant->qmutex);
1683
                /* Insert packets sorting by sequence number */
1684
                participant->inbuf = g_list_insert_sorted(participant->inbuf, pkt, &janus_audiobridge_rtp_sort);
1685
                if(participant->prebuffering) {
1686
                        /* Still pre-buffering: do we have enough packets now? */
1687
                        if(g_list_length(participant->inbuf) == DEFAULT_PREBUFFERING) {
1688
                                participant->prebuffering = FALSE;
1689
                                JANUS_LOG(LOG_VERB, "Prebuffering done! Finally adding the user to the mix\n");
1690
                        } else {
1691
                                JANUS_LOG(LOG_VERB, "Still prebuffering (got %d packets), not adding the user to the mix yet\n", g_list_length(participant->inbuf));
1692
                        }
1693
                } else {
1694
                        /* Make sure we're not queueing too many packets: if so, get rid of the older ones */
1695
                        if(g_list_length(participant->inbuf) >= DEFAULT_PREBUFFERING*2) {
1696
                                JANUS_LOG(LOG_WARN, "Too many packets in queue (%d > %d), removing older ones\n",
1697
                                        g_list_length(participant->inbuf), DEFAULT_PREBUFFERING*2);
1698
                                while(g_list_length(participant->inbuf) > DEFAULT_PREBUFFERING*2) {
1699
                                        /* Remove this packet: it's too old */
1700
                                        GList *first = g_list_first(participant->inbuf);
1701
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1702
                                        participant->inbuf = g_list_remove_link(participant->inbuf, first);
1703
                                        first = NULL;
1704
                                        if(pkt == NULL)
1705
                                                continue;
1706
                                        if(pkt->data)
1707
                                                g_free(pkt->data);
1708
                                        pkt->data = NULL;
1709
                                        g_free(pkt);
1710
                                        pkt = NULL;
1711
                                }
1712
                        }
1713
                }
1714
                janus_mutex_unlock(&participant->qmutex);
1715
        }
1716
}
1717

    
1718
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len) {
1719
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1720
                return;
1721
        /* FIXME Should we care? */
1722
}
1723

    
1724
void janus_audiobridge_hangup_media(janus_plugin_session *handle) {
1725
        JANUS_LOG(LOG_INFO, "No WebRTC media anymore\n");
1726
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1727
                return;
1728
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1729
        if(!session) {
1730
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1731
                return;
1732
        }
1733
        session->started = FALSE;
1734
        if(session->destroyed || !session->participant)
1735
                return;
1736
        if(g_atomic_int_add(&session->hangingup, 1))
1737
                return;
1738
        /* Get rid of participant */
1739
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1740
        janus_mutex_lock(&rooms_mutex);
1741
        janus_audiobridge_room *audiobridge = participant->room;
1742
        if(audiobridge != NULL) {
1743
                janus_mutex_lock(&audiobridge->mutex);
1744
                json_t *event = json_object();
1745
                json_object_set_new(event, "audiobridge", json_string("event"));
1746
                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
1747
                json_object_set_new(event, "leaving", json_integer(participant->user_id));
1748
                char *leaving_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1749
                json_decref(event);
1750
                g_hash_table_remove(audiobridge->participants, &participant->user_id);
1751
                GHashTableIter iter;
1752
                gpointer value;
1753
                g_hash_table_iter_init(&iter, audiobridge->participants);
1754
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1755
                        janus_audiobridge_participant *p = value;
1756
                        if(p == participant) {
1757
                                continue;        /* Skip the leaving participant itself */
1758
                        }
1759
                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
1760
                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, leaving_text, NULL, NULL);
1761
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1762
                }
1763
                g_free(leaving_text);
1764
                /* Also notify event handlers */
1765
                if(notify_events && gateway->events_is_enabled()) {
1766
                        json_t *info = json_object();
1767
                        json_object_set_new(info, "event", json_string("left"));
1768
                        json_object_set_new(info, "room", json_integer(audiobridge->room_id));
1769
                        json_object_set_new(info, "id", json_integer(participant->user_id));
1770
                        gateway->notify_event(session->handle, info);
1771
                }
1772
                janus_mutex_unlock(&audiobridge->mutex);
1773
        }
1774
        /* Get rid of the recorders, if available */
1775
        janus_mutex_lock(&participant->rec_mutex);
1776
        if(participant->arc) {
1777
                janus_recorder_close(participant->arc);
1778
                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
1779
                janus_recorder_free(participant->arc);
1780
        }
1781
        participant->arc = NULL;
1782
        janus_mutex_unlock(&participant->rec_mutex);
1783
        /* Free the participant resources */
1784
        janus_mutex_lock(&participant->qmutex);
1785
        participant->active = FALSE;
1786
        participant->muted = TRUE;
1787
        if(participant->display)
1788
                g_free(participant->display);
1789
        participant->display = NULL;
1790
        participant->prebuffering = TRUE;
1791
        /* Make sure we're not using the encoder/decoder right now, we're going to destroy them */
1792
        while(participant->working)
1793
                g_usleep(5000);
1794
        if(participant->encoder)
1795
                opus_encoder_destroy(participant->encoder);
1796
        participant->encoder = NULL;
1797
        if(participant->decoder)
1798
                opus_decoder_destroy(participant->decoder);
1799
        participant->decoder = NULL;
1800
        participant->reset = FALSE;
1801
        /* Get rid of queued packets */
1802
        while(participant->inbuf) {
1803
                GList *first = g_list_first(participant->inbuf);
1804
                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1805
                participant->inbuf = g_list_remove_link(participant->inbuf, first);
1806
                first = NULL;
1807
                if(pkt == NULL)
1808
                        continue;
1809
                if(pkt->data)
1810
                        g_free(pkt->data);
1811
                pkt->data = NULL;
1812
                g_free(pkt);
1813
                pkt = NULL;
1814
        }
1815
        janus_mutex_unlock(&participant->qmutex);
1816
        if(audiobridge != NULL) {
1817
                janus_mutex_unlock(&audiobridge->mutex);
1818
        }
1819
        janus_mutex_unlock(&rooms_mutex);
1820
}
1821

    
1822
/* Thread to handle incoming messages */
1823
static void *janus_audiobridge_handler(void *data) {
1824
        JANUS_LOG(LOG_VERB, "Joining AudioBridge handler thread\n");
1825
        janus_audiobridge_message *msg = NULL;
1826
        int error_code = 0;
1827
        char error_cause[512];
1828
        json_t *root = NULL;
1829
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
1830
                msg = g_async_queue_pop(messages);
1831
                if(msg == NULL)
1832
                        continue;
1833
                if(msg == &exit_message)
1834
                        break;
1835
                if(msg->handle == NULL) {
1836
                        janus_audiobridge_message_free(msg);
1837
                        continue;
1838
                }
1839
                janus_audiobridge_session *session = NULL;
1840
                janus_mutex_lock(&sessions_mutex);
1841
                if(g_hash_table_lookup(sessions, msg->handle) != NULL) {
1842
                        session = (janus_audiobridge_session *)msg->handle->plugin_handle;
1843
                }
1844
                janus_mutex_unlock(&sessions_mutex);
1845
                if(!session) {
1846
                        JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1847
                        janus_audiobridge_message_free(msg);
1848
                        continue;
1849
                }
1850
                if(session->destroyed) {
1851
                        janus_audiobridge_message_free(msg);
1852
                        continue;
1853
                }
1854
                /* Handle request */
1855
                error_code = 0;
1856
                root = NULL;
1857
                if(msg->message == NULL) {
1858
                        JANUS_LOG(LOG_ERR, "No message??\n");
1859
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
1860
                        g_snprintf(error_cause, 512, "%s", "No message??");
1861
                        goto error;
1862
                }
1863
                root = msg->message;
1864
                /* Get the request first */
1865
                JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
1866
                        error_code, error_cause, TRUE,
1867
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1868
                if(error_code != 0)
1869
                        goto error;
1870
                json_t *request = json_object_get(root, "request");
1871
                const char *request_text = json_string_value(request);
1872
                json_t *event = NULL;
1873
                if(!strcasecmp(request_text, "join")) {
1874
                        JANUS_LOG(LOG_VERB, "Configuring new participant\n");
1875
                        janus_audiobridge_participant *participant = session->participant;
1876
                        if(participant != NULL && participant->room != NULL) {
1877
                                JANUS_LOG(LOG_ERR, "Already in a room (use changeroom to join another one)\n");
1878
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED;
1879
                                g_snprintf(error_cause, 512, "Already in a room (use changeroom to join another one)");
1880
                                goto error;
1881
                        }
1882
                        JANUS_VALIDATE_JSON_OBJECT(root, join_parameters,
1883
                                error_code, error_cause, TRUE,
1884
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1885
                        if(error_code != 0)
1886
                                goto error;
1887
                        json_t *room = json_object_get(root, "room");
1888
                        guint64 room_id = json_integer_value(room);
1889
                        janus_mutex_lock(&rooms_mutex);
1890
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1891
                        if(audiobridge == NULL) {
1892
                                janus_mutex_unlock(&rooms_mutex);
1893
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1894
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1895
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1896
                                goto error;
1897
                        }
1898
                        janus_mutex_lock(&audiobridge->mutex);
1899
                        /* A pin may be required for this action */
1900
                        JANUS_CHECK_SECRET(audiobridge->room_pin, root, "pin", error_code, error_cause,
1901
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1902
                        if(error_code != 0) {
1903
                                janus_mutex_unlock(&audiobridge->mutex);
1904
                                janus_mutex_unlock(&rooms_mutex);
1905
                                goto error;
1906
                        }
1907
                        json_t *display = json_object_get(root, "display");
1908
                        const char *display_text = display ? json_string_value(display) : NULL;
1909
                        json_t *muted = json_object_get(root, "muted");
1910
                        json_t *quality = json_object_get(root, "quality");
1911
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
1912
                        if(complexity < 1 || complexity > 10) {
1913
                                janus_mutex_unlock(&audiobridge->mutex);
1914
                                janus_mutex_unlock(&rooms_mutex);
1915
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
1916
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1917
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
1918
                                goto error;
1919
                        }
1920
                        guint64 user_id = 0;
1921
                        json_t *id = json_object_get(root, "id");
1922
                        if(id) {
1923
                                user_id = json_integer_value(id);
1924
                                if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
1925
                                        /* User ID already taken */
1926
                                        janus_mutex_unlock(&audiobridge->mutex);
1927
                                        janus_mutex_unlock(&rooms_mutex);
1928
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
1929
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
1930
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
1931
                                        goto error;
1932
                                }
1933
                        }
1934
                        if(user_id == 0) {
1935
                                /* Generate a random ID */
1936
                                while(user_id == 0) {
1937
                                        user_id = janus_random_uint64();
1938
                                        if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
1939
                                                /* User ID already taken, try another one */
1940
                                                user_id = 0;
1941
                                        }
1942
                                }
1943
                        }
1944
                        JANUS_LOG(LOG_VERB, "  -- Participant ID: %"SCNu64"\n", user_id);
1945
                        if(participant == NULL) {
1946
                                participant = g_malloc0(sizeof(janus_audiobridge_participant));
1947
                                if(participant == NULL) {
1948
                                        janus_mutex_unlock(&audiobridge->mutex);
1949
                                        janus_mutex_unlock(&rooms_mutex);
1950
                                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1951
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1952
                                        g_snprintf(error_cause, 512, "Memory error");
1953
                                        goto error;
1954
                                }
1955
                                participant->active = FALSE;
1956
                                participant->prebuffering = TRUE;
1957
                                participant->display = NULL;
1958
                                participant->inbuf = NULL;
1959
                                participant->outbuf = NULL;
1960
                                participant->encoder = NULL;
1961
                                participant->decoder = NULL;
1962
                                participant->reset = FALSE;
1963
                                janus_mutex_init(&participant->qmutex);
1964
                                participant->arc = NULL;
1965
                                janus_mutex_init(&participant->rec_mutex);
1966
                        }
1967
                        participant->session = session;
1968
                        participant->room = audiobridge;
1969
                        participant->user_id = user_id;
1970
                        if(participant->display != NULL)
1971
                                g_free(participant->display);
1972
                        participant->display = display_text ? g_strdup(display_text) : NULL;
1973
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* By default, everyone's unmuted when joining */
1974
                        participant->opus_complexity = complexity;
1975
                        if(participant->outbuf == NULL)
1976
                                participant->outbuf = g_async_queue_new();
1977
                        participant->active = session->started;
1978
                        if(!session->started) {
1979
                                /* Initialize the RTP context only if we're renegotiating */
1980
                                participant->context.a_last_ssrc = 0;
1981
                                participant->context.a_last_ts = 0;
1982
                                participant->context.a_base_ts = 0;
1983
                                participant->context.a_base_ts_prev = 0;
1984
                                participant->context.a_last_seq = 0;
1985
                                participant->context.a_base_seq = 0;
1986
                                participant->context.a_base_seq_prev = 0;
1987
                                participant->opus_pt = 0;
1988
                        }
1989
                        JANUS_LOG(LOG_VERB, "Creating Opus encoder/decoder (sampling rate %d)\n", audiobridge->sampling_rate);
1990
                        /* Opus encoder */
1991
                        int error = 0;
1992
                        if(participant->encoder == NULL) {
1993
                                participant->encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
1994
                                if(error != OPUS_OK) {
1995
                                        janus_mutex_unlock(&audiobridge->mutex);
1996
                                        janus_mutex_unlock(&rooms_mutex);
1997
                                        if(participant->display)
1998
                                                g_free(participant->display);
1999
                                        g_free(participant);
2000
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2001
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2002
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2003
                                        goto error;
2004
                                }
2005
                                if(audiobridge->sampling_rate == 8000) {
2006
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
2007
                                } else if(audiobridge->sampling_rate == 12000) {
2008
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
2009
                                } else if(audiobridge->sampling_rate == 16000) {
2010
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2011
                                } else if(audiobridge->sampling_rate == 24000) {
2012
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
2013
                                } else if(audiobridge->sampling_rate == 48000) {
2014
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
2015
                                } else {
2016
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
2017
                                        audiobridge->sampling_rate = 16000;
2018
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2019
                                }
2020
                                /* FIXME This settings should be configurable */
2021
                                opus_encoder_ctl(participant->encoder, OPUS_SET_INBAND_FEC(USE_FEC));
2022
                        }
2023
                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2024
                        if(participant->decoder == NULL) {
2025
                                /* Opus decoder */
2026
                                error = 0;
2027
                                participant->decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
2028
                                if(error != OPUS_OK) {
2029
                                        janus_mutex_unlock(&audiobridge->mutex);
2030
                                        janus_mutex_unlock(&rooms_mutex);
2031
                                        if(participant->display)
2032
                                                g_free(participant->display);
2033
                                        if(participant->encoder)
2034
                                                opus_encoder_destroy(participant->encoder);
2035
                                        participant->encoder = NULL;
2036
                                        if(participant->decoder)
2037
                                                opus_decoder_destroy(participant->decoder);
2038
                                        participant->decoder = NULL;
2039
                                        g_free(participant);
2040
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2041
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2042
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2043
                                        goto error;
2044
                                }
2045
                        }
2046
                        participant->reset = FALSE;
2047
                        /* Finally, start the encoding thread if it hasn't already */
2048
                        if(participant->thread == NULL) {
2049
                                GError *error = NULL;
2050
                                participant->thread = g_thread_try_new("audiobridge participant thread", &janus_audiobridge_participant_thread, participant, &error);
2051
                                if(error != NULL) {
2052
                                        /* FIXME We should fail here... */
2053
                                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the participant thread...\n", error->code, error->message ? error->message : "??");
2054
                                }
2055
                        }
2056
                        
2057
                        /* Done */
2058
                        session->participant = participant;
2059
                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2060
                        /* Notify the other participants */
2061
                        json_t *newuser = json_object();
2062
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
2063
                        json_object_set_new(newuser, "room", json_integer(room_id));
2064
                        json_t *newuserlist = json_array();
2065
                        json_t *pl = json_object();
2066
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2067
                        if(participant->display)
2068
                                json_object_set_new(pl, "display", json_string(participant->display));
2069
                        json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
2070
                        json_array_append_new(newuserlist, pl);
2071
                        json_object_set_new(newuser, "participants", newuserlist);
2072
                        char *newuser_text = json_dumps(newuser, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2073
                        json_decref(newuser);
2074
                        GHashTableIter iter;
2075
                        gpointer value;
2076
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2077
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2078
                                janus_audiobridge_participant *p = value;
2079
                                if(p == participant) {
2080
                                        continue;
2081
                                }
2082
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2083
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser_text, NULL, NULL);
2084
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2085
                        }
2086
                        g_free(newuser_text);
2087
                        /* Return a list of all available participants for the new participant now */
2088
                        json_t *list = json_array();
2089
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2090
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2091
                                janus_audiobridge_participant *p = value;
2092
                                if(p == participant) {
2093
                                        continue;
2094
                                }
2095
                                json_t *pl = json_object();
2096
                                json_object_set_new(pl, "id", json_integer(p->user_id));
2097
                                if(p->display)
2098
                                        json_object_set_new(pl, "display", json_string(p->display));
2099
                                json_object_set_new(pl, "muted", json_string(p->muted ? "true" : "false"));
2100
                                json_array_append_new(list, pl);
2101
                        }
2102
                        janus_mutex_unlock(&audiobridge->mutex);
2103
                        janus_mutex_unlock(&rooms_mutex);
2104
                        event = json_object();
2105
                        json_object_set_new(event, "audiobridge", json_string("joined"));
2106
                        json_object_set_new(event, "room", json_integer(room_id));
2107
                        json_object_set_new(event, "id", json_integer(user_id));
2108
                        json_object_set_new(event, "participants", list);
2109
                        /* Also notify event handlers */
2110
                        if(notify_events && gateway->events_is_enabled()) {
2111
                                json_t *info = json_object();
2112
                                json_object_set_new(info, "event", json_string("joined"));
2113
                                json_object_set_new(info, "room", json_integer(room_id));
2114
                                json_object_set_new(info, "id", json_integer(user_id));
2115
                                json_object_set_new(info, "display", json_string(participant->display));
2116
                                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
2117
                                gateway->notify_event(session->handle, info);
2118
                        }
2119
                } else if(!strcasecmp(request_text, "configure")) {
2120
                        /* Handle this participant */
2121
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2122
                        if(participant == NULL || participant->room == NULL) {
2123
                                JANUS_LOG(LOG_ERR, "Can't configure (not in a room)\n");
2124
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2125
                                g_snprintf(error_cause, 512, "Can't configure (not in a room)");
2126
                                goto error;
2127
                        }
2128
                        /* Configure settings for this participant */
2129
                        JANUS_VALIDATE_JSON_OBJECT(root, configure_parameters,
2130
                                error_code, error_cause, TRUE,
2131
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2132
                        if(error_code != 0)
2133
                                goto error;
2134
                        json_t *muted = json_object_get(root, "muted");
2135
                        json_t *quality = json_object_get(root, "quality");
2136
                        json_t *record = json_object_get(root, "record");
2137
                        json_t *recfile = json_object_get(root, "filename");
2138
                        if(quality) {
2139
                                int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
2140
                                if(complexity < 1 || complexity > 10) {
2141
                                        JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2142
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2143
                                        g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2144
                                        goto error;
2145
                                }
2146
                                participant->opus_complexity = complexity;
2147
                                if(participant->encoder)
2148
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2149
                        }
2150
                        if(muted) {
2151
                                participant->muted = json_is_true(muted);
2152
                                JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %"SCNu64", user %"SCNu64")\n", participant->muted ? "true" : "false", participant->room->room_id, participant->user_id);
2153
                                if(participant->muted) {
2154
                                        /* Clear the queued packets waiting to be handled */
2155
                                        janus_mutex_lock(&participant->qmutex);
2156
                                        while(participant->inbuf) {
2157
                                                GList *first = g_list_first(participant->inbuf);
2158
                                                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2159
                                                participant->inbuf = g_list_remove_link(participant->inbuf, first);
2160
                                                first = NULL;
2161
                                                if(pkt == NULL)
2162
                                                        continue;
2163
                                                if(pkt->data)
2164
                                                        g_free(pkt->data);
2165
                                                pkt->data = NULL;
2166
                                                g_free(pkt);
2167
                                                pkt = NULL;
2168
                                        }
2169
                                        janus_mutex_unlock(&participant->qmutex);
2170
                                }
2171
                                /* Notify all other participants about the mute/unmute */
2172
                                janus_mutex_lock(&rooms_mutex);
2173
                                janus_audiobridge_room *audiobridge = participant->room;
2174
                                if(audiobridge != NULL) {
2175
                                        janus_mutex_lock(&audiobridge->mutex);
2176
                                        json_t *list = json_array();
2177
                                        json_t *pl = json_object();
2178
                                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2179
                                        if(participant->display)
2180
                                                json_object_set_new(pl, "display", json_string(participant->display));
2181
                                        json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
2182
                                        json_array_append_new(list, pl);
2183
                                        json_t *pub = json_object();
2184
                                        json_object_set_new(pub, "audiobridge", json_string("event"));
2185
                                        json_object_set_new(pub, "room", json_integer(participant->room->room_id));
2186
                                        json_object_set_new(pub, "participants", list);
2187
                                        char *pub_text = json_dumps(pub, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2188
                                        json_decref(pub);
2189
                                        GHashTableIter iter;
2190
                                        gpointer value;
2191
                                        g_hash_table_iter_init(&iter, audiobridge->participants);
2192
                                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2193
                                                janus_audiobridge_participant *p = value;
2194
                                                if(p == participant) {
2195
                                                        continue;        /* Skip the new participant itself */
2196
                                                }
2197
                                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2198
                                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub_text, NULL, NULL);
2199
                                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2200
                                        }
2201
                                        g_free(pub_text);
2202
                                        janus_mutex_unlock(&audiobridge->mutex);
2203
                                }
2204
                                janus_mutex_unlock(&rooms_mutex);
2205
                        }
2206
                        if(record) {
2207
                                janus_mutex_lock(&participant->rec_mutex);
2208
                                if(json_is_true(record)) {
2209
                                        /* Start recording (ignore if recording already) */
2210
                                        if(participant->arc != NULL) {
2211
                                                JANUS_LOG(LOG_WARN, "Already recording participant's audio (room %"SCNu64", user %"SCNu64")\n",
2212
                                                        participant->user_id, participant->room->room_id);
2213
                                        } else {
2214
                                                JANUS_LOG(LOG_INFO, "Starting recording of participant's audio (room %"SCNu64", user %"SCNu64")\n",
2215
                                                        participant->user_id, participant->room->room_id);
2216
                                                char filename[255];
2217
                                                gint64 now = janus_get_real_time();
2218
                                                memset(filename, 0, 255);
2219
                                                const char *recording_base = json_string_value(recfile);
2220
                                                if(recording_base) {
2221
                                                        /* Use the filename and path we have been provided */
2222
                                                        g_snprintf(filename, 255, "%s-audio", recording_base);
2223
                                                        participant->arc = janus_recorder_create(NULL, "opus", filename);
2224
                                                        if(participant->arc == NULL) {
2225
                                                                /* FIXME We should notify the fact the recorder could not be created */
2226
                                                                JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this participant!\n");
2227
                                                        }
2228
                                                } else {
2229
                                                        /* Build a filename */
2230
                                                        g_snprintf(filename, 255, "audiobridge-%"SCNu64"-%"SCNu64"-%"SCNi64"-audio",
2231
                                                                participant->user_id, participant->room->room_id, now);
2232
                                                        participant->arc = janus_recorder_create(NULL, "opus", filename);
2233
                                                        if(participant->arc == NULL) {
2234
                                                                /* FIXME We should notify the fact the recorder could not be created */
2235
                                                                JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this participant!\n");
2236
                                                        }
2237
                                                }
2238
                                        }
2239
                                } else {
2240
                                        /* Stop recording (ignore if not recording) */
2241
                                        if(participant->arc) {
2242
                                                janus_recorder_close(participant->arc);
2243
                                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2244
                                                janus_recorder_free(participant->arc);
2245
                                        }
2246
                                        participant->arc = NULL;
2247
                                }
2248
                                janus_mutex_unlock(&participant->rec_mutex);
2249
                        }
2250
                        /* Done */
2251
                        event = json_object();
2252
                        json_object_set_new(event, "audiobridge", json_string("event"));
2253
                        json_object_set_new(event, "result", json_string("ok"));
2254
                        /* Also notify event handlers */
2255
                        if(notify_events && gateway->events_is_enabled()) {
2256
                                janus_audiobridge_room *audiobridge = participant->room;
2257
                                json_t *info = json_object();
2258
                                json_object_set_new(info, "event", json_string("configured"));
2259
                                json_object_set_new(info, "room", json_integer(audiobridge->room_id));
2260
                                json_object_set_new(info, "id", json_integer(participant->user_id));
2261
                                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
2262
                                json_object_set_new(info, "quality", json_integer(participant->opus_complexity));
2263
                                gateway->notify_event(session->handle, info);
2264
                        }
2265
                } else if(!strcasecmp(request_text, "changeroom")) {
2266
                        /* The participant wants to leave the current room and join another one without reconnecting (e.g., a sidebar) */
2267
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2268
                        if(participant == NULL || participant->room == NULL) {
2269
                                JANUS_LOG(LOG_ERR, "Can't change room (not in a room in the first place)\n");
2270
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2271
                                g_snprintf(error_cause, 512, "Can't change room (not in a room in the first place)");
2272
                                goto error;
2273
                        }
2274
                        JANUS_VALIDATE_JSON_OBJECT(root, join_parameters,
2275
                                error_code, error_cause, TRUE,
2276
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2277
                        if(error_code != 0)
2278
                                goto error;
2279
                        json_t *room = json_object_get(root, "room");
2280
                        guint64 room_id = json_integer_value(room);
2281
                        janus_mutex_lock(&rooms_mutex);
2282
                        /* Is this the same room we're in? */
2283
                        if(participant->room && participant->room->room_id == room_id) {
2284
                                janus_mutex_unlock(&rooms_mutex);
2285
                                JANUS_LOG(LOG_ERR, "Already in this room\n");
2286
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED;
2287
                                g_snprintf(error_cause, 512, "Already in this room");
2288
                                goto error;
2289
                        }
2290
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2291
                        if(audiobridge == NULL) {
2292
                                janus_mutex_unlock(&rooms_mutex);
2293
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2294
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2295
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2296
                                goto error;
2297
                        }
2298
                        janus_mutex_lock(&audiobridge->mutex);
2299
                        /* A pin may be required for this action */
2300
                        JANUS_CHECK_SECRET(audiobridge->room_pin, root, "pin", error_code, error_cause,
2301
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2302
                        if(error_code != 0) {
2303
                                janus_mutex_unlock(&audiobridge->mutex);
2304
                                janus_mutex_unlock(&rooms_mutex);
2305
                                goto error;
2306
                        }
2307
                        json_t *display = json_object_get(root, "display");
2308
                        const char *display_text = display ? json_string_value(display) : NULL;
2309
                        json_t *muted = json_object_get(root, "muted");
2310
                        json_t *quality = json_object_get(root, "quality");
2311
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
2312
                        if(complexity < 1 || complexity > 10) {
2313
                                janus_mutex_unlock(&audiobridge->mutex);
2314
                                janus_mutex_unlock(&rooms_mutex);
2315
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2316
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2317
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2318
                                goto error;
2319
                        }
2320
                        guint64 user_id = 0;
2321
                        json_t *id = json_object_get(root, "id");
2322
                        if(id) {
2323
                                user_id = json_integer_value(id);
2324
                                if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2325
                                        /* User ID already taken */
2326
                                        janus_mutex_unlock(&audiobridge->mutex);
2327
                                        janus_mutex_unlock(&rooms_mutex);
2328
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
2329
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
2330
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
2331
                                        goto error;
2332
                                }
2333
                        }
2334
                        if(user_id == 0) {
2335
                                /* Generate a random ID */
2336
                                while(user_id == 0) {
2337
                                        user_id = janus_random_uint64();
2338
                                        if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2339
                                                /* User ID already taken, try another one */
2340
                                                user_id = 0;
2341
                                        }
2342
                                }
2343
                        }
2344
                        JANUS_LOG(LOG_VERB, "  -- Participant ID in new room %"SCNu64": %"SCNu64"\n", room_id, user_id);
2345
                        participant->prebuffering = TRUE;
2346
                        /* Is the sampling rate of the new room the same as the one in the old room, or should we update the decoder/encoder? */
2347
                        janus_audiobridge_room *old_audiobridge = participant->room;
2348
                        /* Leave the old room first... */
2349
                        janus_mutex_lock(&old_audiobridge->mutex);
2350
                        g_hash_table_remove(old_audiobridge->participants, &participant->user_id);
2351
                        if(old_audiobridge->sampling_rate != audiobridge->sampling_rate) {
2352
                                /* Create a new one that takes into account the sampling rate we want now */
2353
                                int error = 0;
2354
                                OpusEncoder *new_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
2355
                                if(error != OPUS_OK) {
2356
                                        if(new_encoder)
2357
                                                opus_encoder_destroy(new_encoder);
2358
                                        new_encoder = NULL;
2359
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2360
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2361
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2362
                                        /* Join the old room again... */
2363
                                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2364
                                        janus_mutex_unlock(&old_audiobridge->mutex);
2365
                                        janus_mutex_unlock(&audiobridge->mutex);
2366
                                        janus_mutex_unlock(&rooms_mutex);
2367
                                        goto error;
2368
                                }
2369
                                if(audiobridge->sampling_rate == 8000) {
2370
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
2371
                                } else if(audiobridge->sampling_rate == 12000) {
2372
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
2373
                                } else if(audiobridge->sampling_rate == 16000) {
2374
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2375
                                } else if(audiobridge->sampling_rate == 24000) {
2376
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
2377
                                } else if(audiobridge->sampling_rate == 48000) {
2378
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
2379
                                } else {
2380
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
2381
                                        audiobridge->sampling_rate = 16000;
2382
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2383
                                }
2384
                                /* FIXME This settings should be configurable */
2385
                                opus_encoder_ctl(new_encoder, OPUS_SET_INBAND_FEC(USE_FEC));
2386
                                opus_encoder_ctl(new_encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2387
                                /* Opus decoder */
2388
                                error = 0;
2389
                                OpusDecoder *new_decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
2390
                                if(error != OPUS_OK) {
2391
                                        if(new_encoder)
2392
                                                opus_encoder_destroy(new_encoder);
2393
                                        new_encoder = NULL;
2394
                                        if(new_decoder)
2395
                                                opus_decoder_destroy(new_decoder);
2396
                                        new_decoder = NULL;
2397
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2398
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2399
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2400
                                        /* Join the old room again... */
2401
                                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2402
                                        janus_mutex_unlock(&old_audiobridge->mutex);
2403
                                        janus_mutex_unlock(&audiobridge->mutex);
2404
                                        janus_mutex_unlock(&rooms_mutex);
2405
                                        goto error;
2406
                                }
2407
                                participant->reset = FALSE;
2408
                                /* Destroy the previous encoder/decoder and update the references */
2409
                                if(participant->encoder)
2410
                                        opus_encoder_destroy(participant->encoder);
2411
                                participant->encoder = new_encoder;
2412
                                if(participant->decoder)
2413
                                        opus_decoder_destroy(participant->decoder);
2414
                                participant->decoder = new_decoder;
2415
                        }
2416
                        /* Everything looks fine, start by telling the folks in the old room this participant is going away */
2417
                        event = json_object();
2418
                        json_object_set_new(event, "audiobridge", json_string("event"));
2419
                        json_object_set_new(event, "room", json_integer(old_audiobridge->room_id));
2420
                        json_object_set_new(event, "leaving", json_integer(participant->user_id));
2421
                        char *leaving_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2422
                        GHashTableIter iter;
2423
                        gpointer value;
2424
                        g_hash_table_iter_init(&iter, old_audiobridge->participants);
2425
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2426
                                janus_audiobridge_participant *p = value;
2427
                                if(p == participant) {
2428
                                        continue;        /* Skip the new participant itself */
2429
                                }
2430
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2431
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, leaving_text, NULL, NULL);
2432
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2433
                        }
2434
                        g_free(leaving_text);
2435
                        /* Also notify event handlers */
2436
                        if(notify_events && gateway->events_is_enabled()) {
2437
                                json_t *info = json_object();
2438
                                json_object_set_new(info, "event", json_string("left"));
2439
                                json_object_set_new(info, "room", json_integer(old_audiobridge->room_id));
2440
                                json_object_set_new(info, "id", json_integer(participant->user_id));
2441
                                gateway->notify_event(session->handle, info);
2442
                        }
2443
                        janus_mutex_unlock(&old_audiobridge->mutex);
2444
                        /* Stop recording, if we were (since this is a new room, a new recording would be required, so a new configure) */
2445
                        janus_mutex_lock(&participant->rec_mutex);
2446
                        if(participant->arc) {
2447
                                janus_recorder_close(participant->arc);
2448
                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2449
                                janus_recorder_free(participant->arc);
2450
                        }
2451
                        participant->arc = NULL;
2452
                        janus_mutex_unlock(&participant->rec_mutex);
2453
                        /* Done, join the new one */
2454
                        participant->user_id = user_id;
2455
                        if(display_text) {
2456
                                g_free(participant->display);
2457
                                participant->display = display_text ? g_strdup(display_text) : NULL;
2458
                        }
2459
                        participant->room = audiobridge;
2460
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* When switching to a new room, you're unmuted by default */
2461
                        if(quality) {
2462
                                participant->opus_complexity = complexity;
2463
                                if(participant->encoder)
2464
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2465
                        }
2466
                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2467
                        /* Notify the other participants */
2468
                        json_t *newuser = json_object();
2469
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
2470
                        json_object_set_new(newuser, "room", json_integer(audiobridge->room_id));
2471
                        json_t *newuserlist = json_array();
2472
                        json_t *pl = json_object();
2473
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2474
                        if(participant->display)
2475
                                json_object_set_new(pl, "display", json_string(participant->display));
2476
                        json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
2477
                        json_array_append_new(newuserlist, pl);
2478
                        json_object_set_new(newuser, "participants", newuserlist);
2479
                        char *newuser_text = json_dumps(newuser, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2480
                        json_decref(newuser);
2481
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2482
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2483
                                janus_audiobridge_participant *p = value;
2484
                                if(p == participant) {
2485
                                        continue;
2486
                                }
2487
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2488
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser_text, NULL, NULL);
2489
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2490
                        }
2491
                        g_free(newuser_text);
2492
                        /* Return a list of all available participants for the new participant now */
2493
                        json_t *list = json_array();
2494
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2495
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2496
                                janus_audiobridge_participant *p = value;
2497
                                if(p == participant) {
2498
                                        continue;
2499
                                }
2500
                                json_t *pl = json_object();
2501
                                json_object_set_new(pl, "id", json_integer(p->user_id));
2502
                                if(p->display)
2503
                                        json_object_set_new(pl, "display", json_string(p->display));
2504
                                json_object_set_new(pl, "muted", json_string(p->muted ? "true" : "false"));
2505
                                json_array_append_new(list, pl);
2506
                        }
2507
                        event = json_object();
2508
                        json_object_set_new(event, "audiobridge", json_string("roomchanged"));
2509
                        json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2510
                        json_object_set_new(event, "id", json_integer(user_id));
2511
                        json_object_set_new(event, "participants", list);
2512
                        /* Also notify event handlers */
2513
                        if(notify_events && gateway->events_is_enabled()) {
2514
                                json_t *info = json_object();
2515
                                json_object_set_new(info, "event", json_string("joined"));
2516
                                json_object_set_new(info, "room", json_integer(audiobridge->room_id));
2517
                                json_object_set_new(info, "id", json_integer(participant->user_id));
2518
                                json_object_set_new(info, "display", json_string(participant->display));
2519
                                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
2520
                                gateway->notify_event(session->handle, info);
2521
                        }
2522
                        janus_mutex_unlock(&audiobridge->mutex);
2523
                        janus_mutex_unlock(&rooms_mutex);
2524
                } else if(!strcasecmp(request_text, "leave")) {
2525
                        /* This participant is leaving */
2526
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2527
                        if(participant == NULL || participant->room == NULL) {
2528
                                JANUS_LOG(LOG_ERR, "Can't leave (not in a room)\n");
2529
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2530
                                g_snprintf(error_cause, 512, "Can't leave (not in a room)");
2531
                                goto error;
2532
                        }
2533
                        /* Tell everybody */
2534
                        janus_mutex_lock(&rooms_mutex);
2535
                        janus_audiobridge_room *audiobridge = participant->room;
2536
                        if(audiobridge != NULL) {
2537
                                janus_mutex_lock(&audiobridge->mutex);
2538
                                event = json_object();
2539
                                json_object_set_new(event, "audiobridge", json_string("event"));
2540
                                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2541
                                json_object_set_new(event, "leaving", json_integer(participant->user_id));
2542
                                char *leaving_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2543
                                GHashTableIter iter;
2544
                                gpointer value;
2545
                                g_hash_table_iter_init(&iter, audiobridge->participants);
2546
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2547
                                        janus_audiobridge_participant *p = value;
2548
                                        if(p == participant) {
2549
                                                continue;        /* Skip the new participant itself */
2550
                                        }
2551
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2552
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, leaving_text, NULL, NULL);
2553
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2554
                                }
2555
                                g_free(leaving_text);
2556
                                /* Actually leave the room... */
2557
                                g_hash_table_remove(audiobridge->participants, &participant->user_id);
2558
                                participant->room = NULL;
2559
                        }
2560
                        /* Get rid of queued packets */
2561
                        janus_mutex_lock(&participant->qmutex);
2562
                        participant->active = FALSE;
2563
                        participant->prebuffering = TRUE;
2564
                        while(participant->inbuf) {
2565
                                GList *first = g_list_first(participant->inbuf);
2566
                                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2567
                                participant->inbuf = g_list_remove_link(participant->inbuf, first);
2568
                                first = NULL;
2569
                                if(pkt == NULL)
2570
                                        continue;
2571
                                if(pkt->data)
2572
                                        g_free(pkt->data);
2573
                                pkt->data = NULL;
2574
                                g_free(pkt);
2575
                                pkt = NULL;
2576
                        }
2577
                        janus_mutex_unlock(&participant->qmutex);
2578
                        /* Stop recording, if we were */
2579
                        janus_mutex_lock(&participant->rec_mutex);
2580
                        if(participant->arc) {
2581
                                janus_recorder_close(participant->arc);
2582
                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2583
                                janus_recorder_free(participant->arc);
2584
                        }
2585
                        participant->arc = NULL;
2586
                        janus_mutex_unlock(&participant->rec_mutex);
2587
                        /* Also notify event handlers */
2588
                        if(notify_events && gateway->events_is_enabled()) {
2589
                                json_t *info = json_object();
2590
                                json_object_set_new(info, "event", json_string("left"));
2591
                                json_object_set_new(info, "room", json_integer(audiobridge->room_id));
2592
                                json_object_set_new(info, "id", json_integer(participant->user_id));
2593
                                gateway->notify_event(session->handle, info);
2594
                        }
2595
                        /* Done */
2596
                        if(audiobridge != NULL)
2597
                                janus_mutex_unlock(&audiobridge->mutex);
2598
                        janus_mutex_unlock(&rooms_mutex);
2599
                } else {
2600
                        JANUS_LOG(LOG_ERR, "Unknown request '%s'\n", request_text);
2601
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
2602
                        g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
2603
                        goto error;
2604
                }
2605

    
2606
                /* Prepare JSON event */
2607
                JANUS_LOG(LOG_VERB, "Preparing JSON event as a reply\n");
2608
                char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2609
                json_decref(event);
2610
                /* Any SDP to handle? */
2611
                if(!msg->sdp) {
2612
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, NULL, NULL);
2613
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2614
                } else {
2615
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg->sdp_type, msg->sdp);
2616
                        const char *type = NULL;
2617
                        if(!strcasecmp(msg->sdp_type, "offer"))
2618
                                type = "answer";
2619
                        if(!strcasecmp(msg->sdp_type, "answer"))
2620
                                type = "offer";
2621
                        /* Fill the SDP template and use that as our answer */
2622
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2623
                        char sdp[1024];
2624
                        /* What is the Opus payload type? */
2625
                        participant->opus_pt = janus_get_codec_pt(msg->sdp, "opus");
2626
                        JANUS_LOG(LOG_VERB, "Opus payload type is %d\n", participant->opus_pt);
2627
                        g_snprintf(sdp, 1024, sdp_template,
2628
                                janus_get_real_time(),                        /* We need current time here */
2629
                                janus_get_real_time(),                        /* We need current time here */
2630
                                participant->room->room_name,        /* Audio bridge name */
2631
                                participant->opus_pt,                        /* Opus payload type */
2632
                                participant->opus_pt,                        /* Opus payload type */
2633
                                participant->opus_pt,                         /* Opus payload type and room sampling rate */
2634
                                participant->room->sampling_rate);
2635
                        /* Did the peer negotiate video? */
2636
                        if(strstr(msg->sdp, "m=video") != NULL) {
2637
                                /* If so, reject it */
2638
                                g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", 1024);                                
2639
                        }
2640
                        /* Did the peer negotiate data channels? */
2641
                        if(strstr(msg->sdp, "DTLS/SCTP") != NULL) {
2642
                                /* If so, reject them */
2643
                                g_strlcat(sdp, "m=application 0 DTLS/SCTP 0\r\n", 1024);
2644
                        }
2645
                        /* How long will the gateway take to push the event? */
2646
                        g_atomic_int_set(&session->hangingup, 0);
2647
                        gint64 start = janus_get_monotonic_time();
2648
                        int res = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, type, sdp);
2649
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (took %"SCNu64" us)\n", res, janus_get_monotonic_time()-start);
2650
                        if(res != JANUS_OK) {
2651
                                /* TODO Failed to negotiate? We should remove this participant */
2652
                        } else {
2653
                                /* Notify all other participants that there's a new boy in town */
2654
                                janus_mutex_lock(&rooms_mutex);
2655
                                janus_audiobridge_room *audiobridge = participant->room;
2656
                                janus_mutex_lock(&audiobridge->mutex);
2657
                                json_t *list = json_array();
2658
                                json_t *pl = json_object();
2659
                                json_object_set_new(pl, "id", json_integer(participant->user_id));
2660
                                if(participant->display)
2661
                                        json_object_set_new(pl, "display", json_string(participant->display));
2662
                                json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
2663
                                json_array_append_new(list, pl);
2664
                                json_t *pub = json_object();
2665
                                json_object_set_new(pub, "audiobridge", json_string("event"));
2666
                                json_object_set_new(pub, "room", json_integer(participant->room->room_id));
2667
                                json_object_set_new(pub, "participants", list);
2668
                                char *pub_text = json_dumps(pub, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2669
                                json_decref(pub);
2670
                                GHashTableIter iter;
2671
                                gpointer value;
2672
                                g_hash_table_iter_init(&iter, audiobridge->participants);
2673
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2674
                                        janus_audiobridge_participant *p = value;
2675
                                        if(p == participant) {
2676
                                                continue;        /* Skip the new participant itself */
2677
                                        }
2678
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2679
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub_text, NULL, NULL);
2680
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2681
                                }
2682
                                g_free(pub_text);
2683
                                participant->active = TRUE;
2684
                                janus_mutex_unlock(&audiobridge->mutex);
2685
                                janus_mutex_unlock(&rooms_mutex);
2686
                        }
2687
                }
2688
                if(event_text)
2689
                        g_free(event_text);
2690
                event_text = NULL;
2691
                if(msg)
2692
                        janus_audiobridge_message_free(msg);
2693
                msg = NULL;
2694

    
2695
                continue;
2696
                
2697
error:
2698
                {
2699
                        /* Prepare JSON error event */
2700
                        json_t *event = json_object();
2701
                        json_object_set_new(event, "audiobridge", json_string("event"));
2702
                        json_object_set_new(event, "error_code", json_integer(error_code));
2703
                        json_object_set_new(event, "error", json_string(error_cause));
2704
                        char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2705
                        json_decref(event);
2706
                        JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
2707
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, NULL, NULL);
2708
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2709
                        g_free(event_text);
2710
                        janus_audiobridge_message_free(msg);
2711
                }
2712
        }
2713
        JANUS_LOG(LOG_VERB, "Leaving AudioBridge handler thread\n");
2714
        return NULL;
2715
}
2716

    
2717
/* Thread to mix the contributions from all participants */
2718
static void *janus_audiobridge_mixer_thread(void *data) {
2719
        JANUS_LOG(LOG_VERB, "Audio bridge thread starting...\n");
2720
        janus_audiobridge_room *audiobridge = (janus_audiobridge_room *)data;
2721
        if(!audiobridge) {
2722
                JANUS_LOG(LOG_ERR, "Invalid room!\n");
2723
                return NULL;
2724
        }
2725
        JANUS_LOG(LOG_VERB, "Thread is for mixing room %"SCNu64" (%s) at rate %"SCNu32"...\n", audiobridge->room_id, audiobridge->room_name, audiobridge->sampling_rate);
2726

    
2727
        /* Do we need to record the mix? */
2728
        if(audiobridge->record) {
2729
                char filename[255];
2730
                if(audiobridge->record_file)
2731
                        g_snprintf(filename, 255, "%s", audiobridge->record_file);
2732
                else
2733
                        g_snprintf(filename, 255, "/tmp/janus-audioroom-%"SCNu64".wav", audiobridge->room_id);
2734
                audiobridge->recording = fopen(filename, "wb");
2735
                if(audiobridge->recording == NULL) {
2736
                        JANUS_LOG(LOG_WARN, "Recording requested, but could NOT open file %s for writing...\n", filename);
2737
                } else {
2738
                        JANUS_LOG(LOG_VERB, "Recording requested, opened file %s for writing\n", filename);
2739
                        /* Write WAV header */
2740
                        wav_header header = {
2741
                                {'R', 'I', 'F', 'F'},
2742
                                0,
2743
                                {'W', 'A', 'V', 'E'},
2744
                                {'f', 'm', 't', ' '},
2745
                                16,
2746
                                1,
2747
                                1,
2748
                                audiobridge->sampling_rate,
2749
                                audiobridge->sampling_rate * 2,
2750
                                2,
2751
                                16,
2752
                                {'d', 'a', 't', 'a'},
2753
                                0
2754
                        };
2755
                        if(fwrite(&header, 1, sizeof(header), audiobridge->recording) != sizeof(header)) {
2756
                                JANUS_LOG(LOG_ERR, "Error writing WAV header...\n");
2757
                        }
2758
                }
2759
        }
2760

    
2761
        /* Buffer (we allocate assuming 48kHz, although we'll likely use less than that) */
2762
        int samples = audiobridge->sampling_rate/50;
2763
        opus_int32 buffer[960], sumBuffer[960];
2764
        opus_int16 outBuffer[960], *curBuffer = NULL;
2765
        memset(buffer, 0, 960*4);
2766
        memset(sumBuffer, 0, 960*4);
2767
        memset(outBuffer, 0, 960*2);
2768

    
2769
        /* Timer */
2770
        struct timeval now, before;
2771
        gettimeofday(&before, NULL);
2772
        now.tv_sec = before.tv_sec;
2773
        now.tv_usec = before.tv_usec;
2774
        time_t passed, d_s, d_us;
2775

    
2776
        /* RTP */
2777
        gint16 seq = 0;
2778
        gint32 ts = 0;
2779

    
2780
        /* Loop */
2781
        int i=0;
2782
        int count = 0, prev_count = 0;
2783
        while(!g_atomic_int_get(&stopping) && audiobridge->destroyed == 0) {        /* FIXME We need a per-room watchdog as well */
2784
                /* See if it's time to prepare a frame */
2785
                gettimeofday(&now, NULL);
2786
                d_s = now.tv_sec - before.tv_sec;
2787
                d_us = now.tv_usec - before.tv_usec;
2788
                if(d_us < 0) {
2789
                        d_us += 1000000;
2790
                        --d_s;
2791
                }
2792
                passed = d_s*1000000 + d_us;
2793
                if(passed < 15000) {        /* Let's wait about 15ms at max */
2794
                        usleep(1000);
2795
                        continue;
2796
                }
2797
                /* Update the reference time */
2798
                before.tv_usec += 20000;
2799
                if(before.tv_usec > 1000000) {
2800
                        before.tv_sec++;
2801
                        before.tv_usec -= 1000000;
2802
                }
2803
                /* Do we need to mix at all? */
2804
                janus_mutex_lock_nodebug(&audiobridge->mutex);
2805
                count = g_hash_table_size(audiobridge->participants);
2806
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
2807
                if(count == 0) {
2808
                        /* No participant, do nothing */
2809
                        if(prev_count > 0) {
2810
                                JANUS_LOG(LOG_VERB, "Last user just left room %"SCNu64", going idle...\n", audiobridge->room_id);
2811
                                prev_count = 0;
2812
                        }
2813
                        continue;
2814
                }
2815
                if(prev_count == 0) {
2816
                        JANUS_LOG(LOG_VERB, "First user just joined room %"SCNu64", waking it up...\n", audiobridge->room_id);
2817
                }
2818
                prev_count = count;
2819
                /* Update RTP header information */
2820
                seq++;
2821
                ts += 960;
2822
                /* Mix all contributions */
2823
                janus_mutex_lock_nodebug(&audiobridge->mutex);
2824
                GList *participants_list = g_hash_table_get_values(audiobridge->participants);
2825
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
2826
                for(i=0; i<samples; i++)
2827
                        buffer[i] = 0;
2828
                GList *ps = participants_list;
2829
                while(ps) {
2830
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
2831
                        janus_mutex_lock(&p->qmutex);
2832
                        if(!p->active || p->muted || p->prebuffering || !p->inbuf) {
2833
                                janus_mutex_unlock(&p->qmutex);
2834
                                ps = ps->next;
2835
                                continue;
2836
                        }
2837
                        GList *peek = g_list_first(p->inbuf);
2838
                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)(peek ? peek->data : NULL);
2839
                        if(pkt != NULL) {
2840
                                curBuffer = (opus_int16 *)pkt->data;
2841
                                for(i=0; i<samples; i++)
2842
                                        buffer[i] += curBuffer[i];
2843
                        }
2844
                        janus_mutex_unlock(&p->qmutex);
2845
                        ps = ps->next;
2846
                }
2847
                /* Are we recording the mix? (only do it if there's someone in, though...) */
2848
                if(audiobridge->recording != NULL && g_list_length(participants_list) > 0) {
2849
                        for(i=0; i<samples; i++) {
2850
                                /* FIXME Smoothen/Normalize instead of truncating? */
2851
                                outBuffer[i] = buffer[i];
2852
                        }
2853
                        fwrite(outBuffer, sizeof(opus_int16), samples, audiobridge->recording);
2854
                }
2855
                /* Send proper packet to each participant (remove own contribution) */
2856
                ps = participants_list;
2857
                while(ps) {
2858
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
2859
                        janus_audiobridge_rtp_relay_packet *pkt = NULL;
2860
                        janus_mutex_lock(&p->qmutex);
2861
                        if(p->active && !p->muted && !p->prebuffering && p->inbuf) {
2862
                                GList *first = g_list_first(p->inbuf);
2863
                                pkt = (janus_audiobridge_rtp_relay_packet *)(first ? first->data : NULL);
2864
                                p->inbuf = g_list_delete_link(p->inbuf, first);
2865
                        }
2866
                        janus_mutex_unlock(&p->qmutex);
2867
                        curBuffer = (opus_int16 *)(pkt ? pkt->data : NULL);
2868
                        for(i=0; i<samples; i++)
2869
                                sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]) : 0);
2870
                        for(i=0; i<samples; i++)
2871
                                /* FIXME Smoothen/Normalize instead of truncating? */
2872
                                outBuffer[i] = sumBuffer[i];
2873
                        /* Enqueue this mixed frame for encoding in the participant thread */
2874
                        janus_audiobridge_rtp_relay_packet *mixedpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
2875
                        if(mixedpkt != NULL) {
2876
                                mixedpkt->data = g_malloc0(samples*2);
2877
                                if(mixedpkt->data == NULL) {
2878
                                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2879
                                        g_free(mixedpkt);
2880
                                } else {
2881
                                        memcpy(mixedpkt->data, outBuffer, samples*2);
2882
                                        mixedpkt->length = samples;        /* We set the number of samples here, not the data length */
2883
                                        mixedpkt->timestamp = ts;
2884
                                        mixedpkt->seq_number = seq;
2885
                                        mixedpkt->ssrc = audiobridge->room_id;
2886
                                        g_async_queue_push(p->outbuf, mixedpkt);
2887
                                }
2888
                        }
2889
                        if(pkt) {
2890
                                if(pkt->data)
2891
                                        g_free(pkt->data);
2892
                                pkt->data = NULL;
2893
                                g_free(pkt);
2894
                                pkt = NULL;
2895
                        }
2896
                        ps = ps->next;
2897
                }
2898
                g_list_free(participants_list);
2899
        }
2900
        if(audiobridge->recording)
2901
                fclose(audiobridge->recording);
2902
        JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %"SCNu64" (%s)...\n", audiobridge->room_id, audiobridge->room_name);
2903

    
2904
        /* We'll let the watchdog worry about free resources */
2905
        old_rooms = g_list_append(old_rooms, audiobridge);
2906

    
2907
        return NULL;
2908
}
2909

    
2910
/* Thread to encode a mixed frame and send it to a specific participant */
2911
static void *janus_audiobridge_participant_thread(void *data) {
2912
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread starting...\n");
2913
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)data;
2914
        if(!participant) {
2915
                JANUS_LOG(LOG_ERR, "Invalid participant!\n");
2916
                g_thread_unref(g_thread_self());
2917
                return NULL;
2918
        }
2919
        JANUS_LOG(LOG_VERB, "Thread is for participant %"SCNu64" (%s)\n", participant->user_id, participant->display ? participant->display : "??");
2920
        janus_audiobridge_session *session = participant->session;
2921

    
2922
        /* Output buffer */
2923
        janus_audiobridge_rtp_relay_packet *outpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
2924
        if(outpkt == NULL) {
2925
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2926
                g_thread_unref(g_thread_self());
2927
                return NULL;
2928
        }
2929
        outpkt->data = (rtp_header *)g_malloc0(1500);
2930
        if(outpkt->data == NULL) {
2931
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2932
                g_free(outpkt);
2933
                g_thread_unref(g_thread_self());
2934
                return NULL;
2935
        }
2936
        outpkt->ssrc = 0;
2937
        outpkt->timestamp = 0;
2938
        outpkt->seq_number = 0;
2939
        unsigned char *payload = (unsigned char *)outpkt->data;
2940
        memset(payload, 0, 1500);
2941

    
2942
        janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
2943

    
2944
        /* Start working: check the outgoing queue for packets, then encode and send them */
2945
        while(!g_atomic_int_get(&stopping) && session->destroyed == 0) {
2946
                if(!participant->active || !participant->encoder) {
2947
                        /* Wait until the participant is in a room */
2948
                        g_usleep(10000);
2949
                        continue;
2950
                }
2951
                if(g_async_queue_length(participant->outbuf) == 0) {
2952
                        /* Nothing to do */
2953
                        g_usleep(5000);
2954
                        continue;
2955
                }
2956
                mixedpkt = g_async_queue_pop(participant->outbuf);
2957
                if(mixedpkt != NULL && session->destroyed == 0) {
2958
                        /* Encode raw frame to Opus */
2959
                        if(participant->active && participant->encoder) {
2960
                                participant->working = TRUE;
2961
                                opus_int16 *outBuffer = (opus_int16 *)mixedpkt->data;
2962
                                outpkt->length = opus_encode(participant->encoder, outBuffer, mixedpkt->length, payload+12, BUFFER_SAMPLES-12);
2963
                                participant->working = FALSE;
2964
                                if(outpkt->length < 0) {
2965
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", outpkt->length, opus_strerror(outpkt->length));
2966
                                } else {
2967
                                        outpkt->length += 12;        /* Take the RTP header into consideration */
2968
                                        /* Update RTP header */
2969
                                        outpkt->data->version = 2;
2970
                                        outpkt->data->markerbit = 0;        /* FIXME Should be 1 for the first packet */
2971
                                        outpkt->data->seq_number = htons(mixedpkt->seq_number);
2972
                                        outpkt->data->timestamp = htonl(mixedpkt->timestamp);
2973
                                        outpkt->data->ssrc = htonl(mixedpkt->ssrc);        /* The gateway will fix this anyway */
2974
                                        /* Backup the actual timestamp and sequence number set by the audiobridge, in case a room is changed */
2975
                                        outpkt->ssrc = mixedpkt->ssrc;
2976
                                        outpkt->timestamp = mixedpkt->timestamp;
2977
                                        outpkt->seq_number = mixedpkt->seq_number;
2978
                                        janus_audiobridge_relay_rtp_packet(participant->session, outpkt);
2979
                                }
2980
                        }
2981
                        if(mixedpkt) {
2982
                                if(mixedpkt->data)
2983
                                        g_free(mixedpkt->data);
2984
                                mixedpkt->data = NULL;
2985
                                g_free(mixedpkt);
2986
                                mixedpkt = NULL;
2987
                        }
2988
                }
2989
        }
2990
        /* We're done, get rid of the resources */
2991
        if(outpkt != NULL) {
2992
                if(outpkt->data != NULL) {
2993
                        g_free(outpkt->data);
2994
                        outpkt->data = NULL;
2995
                }
2996
                g_free(outpkt);
2997
                outpkt = NULL;
2998
        }
2999
        /* Empty the outgoing queue if there was something still in */
3000
        while(g_async_queue_length(participant->outbuf) > 0) {
3001
                janus_audiobridge_rtp_relay_packet *pkt = g_async_queue_pop(participant->outbuf);
3002
                if(pkt == NULL)
3003
                        continue;
3004
                if(pkt->data)
3005
                        g_free(pkt->data);
3006
                pkt->data = NULL;
3007
                g_free(pkt);
3008
                pkt = NULL;
3009
        }
3010
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread leaving...\n");
3011
        return NULL;
3012
}
3013

    
3014
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data) {
3015
        janus_audiobridge_rtp_relay_packet *packet = (janus_audiobridge_rtp_relay_packet *)user_data;
3016
        if(!packet || !packet->data || packet->length < 1) {
3017
                JANUS_LOG(LOG_ERR, "Invalid packet...\n");
3018
                return;
3019
        }
3020
        janus_audiobridge_session *session = (janus_audiobridge_session *)data;
3021
        if(!session || !session->handle) {
3022
                // JANUS_LOG(LOG_ERR, "Invalid session...\n");
3023
                return;
3024
        }
3025
        if(!session->started) {
3026
                // JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
3027
                return;
3028
        }
3029
        janus_audiobridge_participant *participant = session->participant;
3030
        /* Set the payload type */
3031
        packet->data->type = participant->opus_pt;
3032
        /* Fix sequence number and timestamp (room switching may be involved) */
3033
        if(ntohl(packet->data->ssrc) != participant->context.a_last_ssrc) {
3034
                participant->context.a_last_ssrc = ntohl(packet->data->ssrc);
3035
                participant->context.a_base_ts_prev = participant->context.a_last_ts;
3036
                participant->context.a_base_ts = packet->timestamp;
3037
                participant->context.a_base_seq_prev = participant->context.a_last_seq;
3038
                participant->context.a_base_seq = packet->seq_number;
3039
        }
3040
        /* Compute a coherent timestamp and sequence number */
3041
        participant->context.a_last_ts = (packet->timestamp-participant->context.a_base_ts)
3042
                + participant->context.a_base_ts_prev+960;        /* FIXME When switching, we assume Opus and so a 960 ts step */
3043
        participant->context.a_last_seq = (packet->seq_number-participant->context.a_base_seq)+participant->context.a_base_seq_prev+1;
3044
        /* Update the timestamp and sequence number in the RTP packet, and send it */
3045
        packet->data->timestamp = htonl(participant->context.a_last_ts);
3046
        packet->data->seq_number = htons(participant->context.a_last_seq);
3047
        if(gateway != NULL)
3048
                gateway->relay_rtp(session->handle, 0, (char *)packet->data, packet->length);
3049
        /* Restore the timestamp and sequence number to what the publisher set them to */
3050
        packet->data->timestamp = htonl(packet->timestamp);
3051
        packet->data->seq_number = htons(packet->seq_number);
3052
}