Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_audiobridge.c @ 793d18b1

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

    
366
#include "plugin.h"
367

    
368
#include <jansson.h>
369
#include <opus/opus.h>
370
#include <sys/time.h>
371

    
372
#include "../debug.h"
373
#include "../apierror.h"
374
#include "../config.h"
375
#include "../mutex.h"
376
#include "../rtp.h"
377
#include "../rtcp.h"
378
#include "../utils.h"
379

    
380

    
381
/* Plugin information */
382
#define JANUS_AUDIOBRIDGE_VERSION                        8
383
#define JANUS_AUDIOBRIDGE_VERSION_STRING        "0.0.8"
384
#define JANUS_AUDIOBRIDGE_DESCRIPTION                "This is a plugin implementing an audio conference bridge for Janus, mixing Opus streams."
385
#define JANUS_AUDIOBRIDGE_NAME                                "JANUS AudioBridge plugin"
386
#define JANUS_AUDIOBRIDGE_AUTHOR                        "Meetecho s.r.l."
387
#define JANUS_AUDIOBRIDGE_PACKAGE                        "janus.plugin.audiobridge"
388

    
389
/* Plugin methods */
390
janus_plugin *create(void);
391
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path);
392
void janus_audiobridge_destroy(void);
393
int janus_audiobridge_get_api_compatibility(void);
394
int janus_audiobridge_get_version(void);
395
const char *janus_audiobridge_get_version_string(void);
396
const char *janus_audiobridge_get_description(void);
397
const char *janus_audiobridge_get_name(void);
398
const char *janus_audiobridge_get_author(void);
399
const char *janus_audiobridge_get_package(void);
400
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error);
401
struct janus_plugin_result *janus_audiobridge_handle_message(janus_plugin_session *handle, char *transaction, char *message, char *sdp_type, char *sdp);
402
void janus_audiobridge_setup_media(janus_plugin_session *handle);
403
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len);
404
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len);
405
void janus_audiobridge_hangup_media(janus_plugin_session *handle);
406
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error);
407
char *janus_audiobridge_query_session(janus_plugin_session *handle);
408

    
409
/* Plugin setup */
410
static janus_plugin janus_audiobridge_plugin =
411
        JANUS_PLUGIN_INIT (
412
                .init = janus_audiobridge_init,
413
                .destroy = janus_audiobridge_destroy,
414

    
415
                .get_api_compatibility = janus_audiobridge_get_api_compatibility,
416
                .get_version = janus_audiobridge_get_version,
417
                .get_version_string = janus_audiobridge_get_version_string,
418
                .get_description = janus_audiobridge_get_description,
419
                .get_name = janus_audiobridge_get_name,
420
                .get_author = janus_audiobridge_get_author,
421
                .get_package = janus_audiobridge_get_package,
422
                
423
                .create_session = janus_audiobridge_create_session,
424
                .handle_message = janus_audiobridge_handle_message,
425
                .setup_media = janus_audiobridge_setup_media,
426
                .incoming_rtp = janus_audiobridge_incoming_rtp,
427
                .incoming_rtcp = janus_audiobridge_incoming_rtcp,
428
                .hangup_media = janus_audiobridge_hangup_media,
429
                .destroy_session = janus_audiobridge_destroy_session,
430
                .query_session = janus_audiobridge_query_session,
431
        );
432

    
433
/* Plugin creator */
434
janus_plugin *create(void) {
435
        JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_AUDIOBRIDGE_NAME);
436
        return &janus_audiobridge_plugin;
437
}
438

    
439

    
440
/* Useful stuff */
441
static gint initialized = 0, stopping = 0;
442
static janus_callbacks *gateway = NULL;
443
static GThread *handler_thread;
444
static GThread *watchdog;
445
static void *janus_audiobridge_handler(void *data);
446
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data);
447
static void *janus_audiobridge_mixer_thread(void *data);
448
static void *janus_audiobridge_participant_thread(void *data);
449

    
450
typedef struct janus_audiobridge_message {
451
        janus_plugin_session *handle;
452
        char *transaction;
453
        json_t *message;
454
        char *sdp_type;
455
        char *sdp;
456
} janus_audiobridge_message;
457
static GAsyncQueue *messages = NULL;
458

    
459
void janus_audiobridge_message_free(janus_audiobridge_message *msg);
460
void janus_audiobridge_message_free(janus_audiobridge_message *msg) {
461
        if(!msg)
462
                return;
463

    
464
        msg->handle = NULL;
465

    
466
        g_free(msg->transaction);
467
        msg->transaction = NULL;
468
        if(msg->message)
469
                json_decref(msg->message);
470
        msg->message = NULL;
471
        g_free(msg->sdp_type);
472
        msg->sdp_type = NULL;
473
        g_free(msg->sdp);
474
        msg->sdp = NULL;
475

    
476
        g_free(msg);
477
}
478

    
479

    
480
typedef struct janus_audiobridge_room {
481
        guint64 room_id;                        /* Unique room ID */
482
        gchar *room_name;                        /* Room description */
483
        gchar *room_secret;                        /* Secret needed to manipulate (e.g., destroy) this room */
484
        gboolean is_private;                        /* Whether this room is 'private' (as in hidden) or not */
485
        uint32_t sampling_rate;                /* Sampling rate of the mix (e.g., 16000 for wideband; can be 8, 12, 16, 24 or 48kHz) */
486
        gboolean record;                        /* Whether this room has to be recorded or not */
487
        gchar *record_file;                        /* Path of the recording file */
488
        FILE *recording;                        /* File to record the room into */
489
        gboolean destroy;                        /* Value to flag the room for destruction */
490
        GHashTable *participants;        /* Map of participants */
491
        GThread *thread;                        /* Mixer thread for this room */
492
        gint64 destroyed;                        /* When this room has been destroyed */
493
        janus_mutex mutex;                        /* Mutex to lock this room instance */
494
} janus_audiobridge_room;
495
static GHashTable *rooms;
496
static janus_mutex rooms_mutex;
497

    
498
typedef struct janus_audiobridge_session {
499
        janus_plugin_session *handle;
500
        gpointer participant;
501
        gboolean started;
502
        gboolean stopping;
503
        guint64 destroyed;        /* Time at which this session was marked as destroyed */
504
} janus_audiobridge_session;
505
static GHashTable *sessions;
506
static GList *old_sessions;
507
static janus_mutex sessions_mutex;
508

    
509
typedef struct janus_audiobridge_rtp_context {
510
        /* Needed to fix seq and ts in case of publisher switching */
511
        uint32_t a_last_ssrc, a_last_ts, a_base_ts, a_base_ts_prev;
512
        uint16_t a_last_seq, a_base_seq, a_base_seq_prev;
513
} janus_audiobridge_rtp_context;
514

    
515
typedef struct janus_audiobridge_participant {
516
        janus_audiobridge_session *session;
517
        janus_audiobridge_room *room;        /* Room */
518
        guint64 user_id;                /* Unique ID in the room */
519
        gchar *display;                        /* Display name (just for fun) */
520
        gboolean active;                /* Whether this participant can receive media at all */
521
        gboolean working;                /* Whether this participant is currently encoding/decoding */
522
        gboolean muted;                        /* Whether this participant is muted */
523
        int opus_complexity;        /* Complexity to use in the encoder (by default, DEFAULT_COMPLEXITY) */
524
        /* RTP stuff */
525
        GQueue *inbuf;                        /* Incoming audio from this participant */
526
        GAsyncQueue *outbuf;        /* Mixed audio for this participant */
527
        janus_mutex qmutex;                /* Incoming queue mutex */
528
        int opus_pt;                        /* Opus payload type */
529
        janus_audiobridge_rtp_context context;        /* Needed in case the participant changes room */
530
        /* Opus stuff */
531
        OpusEncoder *encoder;                /* Opus encoder instance */
532
        OpusDecoder *decoder;                /* Opus decoder instance */
533
        gboolean reset;                                /* Whether or not the Opus context must be reset, without re-joining the room */
534
        GThread *thread;                        /* Encoding thread for this participant */
535
        gint64 destroyed;                        /* When this participant has been destroyed */
536
} janus_audiobridge_participant;
537

    
538
/* Packets we get from gstreamer and relay */
539
typedef struct janus_audiobridge_rtp_relay_packet {
540
        rtp_header *data;
541
        gint length;
542
        uint32_t ssrc;
543
        uint32_t timestamp;
544
        uint16_t seq_number;
545
} janus_audiobridge_rtp_relay_packet;
546

    
547
/* SDP offer/answer template */
548
#define sdp_template \
549
                "v=0\r\n" \
550
                "o=- %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n"        /* We need current time here */ \
551
                "s=%s\r\n"                                                        /* Audio bridge name */ \
552
                "t=0 0\r\n" \
553
                "m=audio 1 RTP/SAVPF %d\r\n"                /* Opus payload type */ \
554
                "c=IN IP4 1.1.1.1\r\n" \
555
                "a=rtpmap:%d opus/48000/2\r\n"                /* Opus payload type */ \
556
                "a=fmtp:%d maxplaybackrate=%"SCNu32"; stereo=0; sprop-stereo=0; useinbandfec=0\r\n" \
557
                                                                                        /* Opus payload type and room sampling rate */
558

    
559
/* Helper struct to generate and parse WAVE headers */
560
typedef struct wav_header {
561
        char riff[4];
562
        uint32_t len;
563
        char wave[4];
564
        char fmt[4];
565
        uint32_t formatsize;
566
        uint16_t format;
567
        uint16_t channels;
568
        uint32_t samplerate;
569
        uint32_t avgbyterate;
570
        uint16_t samplebytes;
571
        uint16_t channelbits;
572
        char data[4];
573
        uint32_t blocksize;
574
} wav_header;
575

    
576

    
577
/* Opus settings */                
578
#define        BUFFER_SAMPLES        8000
579
#define        OPUS_SAMPLES        160
580
#define USE_FEC                        0
581
#define DEFAULT_COMPLEXITY        4
582

    
583

    
584
/* Error codes */
585
#define JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR        499
586
#define JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE                480
587
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON        481
588
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST        482
589
#define JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT        483
590
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT        484
591
#define JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM        485
592
#define JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS                486
593
#define JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED                487
594
#define JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR        488
595
#define JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED        489
596
#define JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS                490
597
#define JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED        491
598

    
599

    
600
/* AudioBridge watchdog/garbage collector (sort of) */
601
void *janus_audiobridge_watchdog(void *data);
602
void *janus_audiobridge_watchdog(void *data) {
603
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog started\n");
604
        gint64 now = 0;
605
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
606
                janus_mutex_lock(&sessions_mutex);
607
                /* Iterate on all the sessions */
608
                now = janus_get_monotonic_time();
609
                if(old_sessions != NULL) {
610
                        GList *sl = old_sessions;
611
                        JANUS_LOG(LOG_HUGE, "Checking %d old AudioBridge sessions...\n", g_list_length(old_sessions));
612
                        while(sl) {
613
                                janus_audiobridge_session *session = (janus_audiobridge_session *)sl->data;
614
                                if(!session) {
615
                                        sl = sl->next;
616
                                        continue;
617
                                }
618
                                if(now-session->destroyed >= 5*G_USEC_PER_SEC) {
619
                                        /* We're lazy and actually get rid of the stuff only after a few seconds */
620
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge session\n");
621
                                        GList *rm = sl->next;
622
                                        old_sessions = g_list_delete_link(old_sessions, sl);
623
                                        sl = rm;
624
                                        session->handle = NULL;
625
                                        g_free(session);
626
                                        session = NULL;
627
                                        continue;
628
                                }
629
                                sl = sl->next;
630
                        }
631
                }
632
                janus_mutex_unlock(&sessions_mutex);
633
                g_usleep(500000);
634
        }
635
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog stopped\n");
636
        return NULL;
637
}
638

    
639

    
640
/* Plugin implementation */
641
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) {
642
        if(g_atomic_int_get(&stopping)) {
643
                /* Still stopping from before */
644
                return -1;
645
        }
646
        if(callback == NULL || config_path == NULL) {
647
                /* Invalid arguments */
648
                return -1;
649
        }
650

    
651
        /* Read configuration */
652
        char filename[255];
653
        g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_AUDIOBRIDGE_PACKAGE);
654
        JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
655
        janus_config *config = janus_config_parse(filename);
656
        if(config != NULL)
657
                janus_config_print(config);
658
        
659
        rooms = g_hash_table_new(NULL, NULL);
660
        janus_mutex_init(&rooms_mutex);
661
        sessions = g_hash_table_new(NULL, NULL);
662
        janus_mutex_init(&sessions_mutex);
663
        messages = g_async_queue_new_full((GDestroyNotify) janus_audiobridge_message_free);
664
        /* This is the callback we'll need to invoke to contact the gateway */
665
        gateway = callback;
666

    
667
        /* Parse configuration to populate the rooms list */
668
        if(config != NULL) {
669
                janus_config_category *cat = janus_config_get_categories(config);
670
                while(cat != NULL) {
671
                        if(cat->name == NULL) {
672
                                cat = cat->next;
673
                                continue;
674
                        }
675
                        JANUS_LOG(LOG_VERB, "Adding audio room '%s'\n", cat->name);
676
                        janus_config_item *desc = janus_config_get_item(cat, "description");
677
                        janus_config_item *priv = janus_config_get_item(cat, "is_private");
678
                        janus_config_item *sampling = janus_config_get_item(cat, "sampling_rate");
679
                        janus_config_item *secret = janus_config_get_item(cat, "secret");
680
                        janus_config_item *record = janus_config_get_item(cat, "record");
681
                        janus_config_item *recfile = janus_config_get_item(cat, "record_file");
682
                        if(sampling == NULL || sampling->value == NULL) {
683
                                JANUS_LOG(LOG_ERR, "Can't add the audio room, missing mandatory information...\n");
684
                                cat = cat->next;
685
                                continue;
686
                        }
687
                        /* Create the audio bridge room */
688
                        janus_audiobridge_room *audiobridge = calloc(1, sizeof(janus_audiobridge_room));
689
                        if(audiobridge == NULL) {
690
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
691
                                cat = cat->next;
692
                                continue;
693
                        }
694
                        audiobridge->room_id = atoi(cat->name);
695
                        char *description = NULL;
696
                        if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0)
697
                                description = g_strdup(desc->value);
698
                        else
699
                                description = g_strdup(cat->name);
700
                        if(description == NULL) {
701
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
702
                                cat = cat->next;
703
                                continue;
704
                        }
705
                        audiobridge->room_name = description;
706
                        audiobridge->is_private = priv && priv->value && janus_is_true(priv->value);
707
                        audiobridge->sampling_rate = atoi(sampling->value);
708
                        switch(audiobridge->sampling_rate) {
709
                                case 8000:
710
                                case 12000:
711
                                case 16000:
712
                                case 24000:
713
                                case 48000:
714
                                        JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
715
                                        break;
716
                                default:
717
                                        JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
718
                                        cat = cat->next;
719
                                        continue;
720
                        }
721
                        if(secret != NULL && secret->value != NULL) {
722
                                audiobridge->room_secret = g_strdup(secret->value);
723
                        }
724
                        audiobridge->record = FALSE;
725
                        if(record && record->value && janus_is_true(record->value))
726
                                audiobridge->record = TRUE;
727
                        if(recfile && recfile->value)
728
                                audiobridge->record_file = g_strdup(recfile->value);
729
                        audiobridge->recording = NULL;
730
                        audiobridge->destroy = 0;
731
                        audiobridge->participants = g_hash_table_new(NULL, NULL);
732
                        audiobridge->destroyed = 0;
733
                        janus_mutex_init(&audiobridge->mutex);
734
                        JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s)\n", audiobridge->room_id, audiobridge->room_name, audiobridge->is_private ? "private" : "public", audiobridge->room_secret ? audiobridge->room_secret : "no secret");
735
                        /* We need a thread for the mix */
736
                        GError *error = NULL;
737
                        audiobridge->thread = g_thread_try_new("audiobridge mixer thread", &janus_audiobridge_mixer_thread, audiobridge, &error);
738
                        if(error != NULL) {
739
                                /* FIXME We should clear some resources... */
740
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
741
                        } else {
742
                                janus_mutex_lock(&rooms_mutex);
743
                                g_hash_table_insert(rooms, GUINT_TO_POINTER(audiobridge->room_id), audiobridge);
744
                                janus_mutex_unlock(&rooms_mutex);
745
                        }
746
                        cat = cat->next;
747
                }
748
                /* Done */
749
                janus_config_destroy(config);
750
                config = NULL;
751
        }
752

    
753
        /* Show available rooms */
754
        janus_mutex_lock(&rooms_mutex);
755
        GHashTableIter iter;
756
        gpointer value;
757
        g_hash_table_iter_init(&iter, rooms);
758
        while (g_hash_table_iter_next(&iter, NULL, &value)) {
759
                janus_audiobridge_room *ar = value;
760
                JANUS_LOG(LOG_VERB, "  ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n",
761
                        ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT");
762
        }
763
        janus_mutex_unlock(&rooms_mutex);
764

    
765
        g_atomic_int_set(&initialized, 1);
766

    
767
        GError *error = NULL;
768
        /* Start the sessions watchdog */
769
        watchdog = g_thread_try_new("abridge watchdog", &janus_audiobridge_watchdog, NULL, &error);
770
        if(error != NULL) {
771
                g_atomic_int_set(&initialized, 0);
772
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge watchdog thread...\n", error->code, error->message ? error->message : "??");
773
                return -1;
774
        }
775
        /* Launch the thread that will handle incoming messages */
776
        handler_thread = g_thread_try_new("janus audiobridge handler", janus_audiobridge_handler, NULL, &error);
777
        if(error != NULL) {
778
                g_atomic_int_set(&initialized, 0);
779
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", error->code, error->message ? error->message : "??");
780
                return -1;
781
        }
782
        JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_AUDIOBRIDGE_NAME);
783
        return 0;
784
}
785

    
786
void janus_audiobridge_destroy(void) {
787
        if(!g_atomic_int_get(&initialized))
788
                return;
789
        g_atomic_int_set(&stopping, 1);
790
        if(handler_thread != NULL) {
791
                g_thread_join(handler_thread);
792
                handler_thread = NULL;
793
        }
794
        if(watchdog != NULL) {
795
                g_thread_join(watchdog);
796
                watchdog = NULL;
797
        }
798
        /* FIXME We should destroy the sessions cleanly */
799
        janus_mutex_lock(&sessions_mutex);
800
        g_hash_table_destroy(sessions);
801
        janus_mutex_unlock(&sessions_mutex);
802
        janus_mutex_lock(&rooms_mutex);
803
        g_hash_table_destroy(rooms);
804
        janus_mutex_unlock(&rooms_mutex);
805
        g_async_queue_unref(messages);
806
        messages = NULL;
807
        sessions = NULL;
808
        g_atomic_int_set(&initialized, 0);
809
        g_atomic_int_set(&stopping, 0);
810
        JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_AUDIOBRIDGE_NAME);
811
}
812

    
813
int janus_audiobridge_get_api_compatibility(void) {
814
        /* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
815
        return JANUS_PLUGIN_API_VERSION;
816
}
817

    
818
int janus_audiobridge_get_version(void) {
819
        return JANUS_AUDIOBRIDGE_VERSION;
820
}
821

    
822
const char *janus_audiobridge_get_version_string(void) {
823
        return JANUS_AUDIOBRIDGE_VERSION_STRING;
824
}
825

    
826
const char *janus_audiobridge_get_description(void) {
827
        return JANUS_AUDIOBRIDGE_DESCRIPTION;
828
}
829

    
830
const char *janus_audiobridge_get_name(void) {
831
        return JANUS_AUDIOBRIDGE_NAME;
832
}
833

    
834
const char *janus_audiobridge_get_author(void) {
835
        return JANUS_AUDIOBRIDGE_AUTHOR;
836
}
837

    
838
const char *janus_audiobridge_get_package(void) {
839
        return JANUS_AUDIOBRIDGE_PACKAGE;
840
}
841

    
842
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error) {
843
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
844
                *error = -1;
845
                return;
846
        }        
847
        janus_audiobridge_session *session = (janus_audiobridge_session *)calloc(1, sizeof(janus_audiobridge_session));
848
        if(session == NULL) {
849
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
850
                *error = -2;
851
                return;
852
        }
853
        session->handle = handle;
854
        session->started = FALSE;
855
        session->stopping = FALSE;
856
        session->destroyed = 0;
857
        handle->plugin_handle = session;
858
        janus_mutex_lock(&sessions_mutex);
859
        g_hash_table_insert(sessions, handle, session);
860
        janus_mutex_unlock(&sessions_mutex);
861

    
862
        return;
863
}
864

    
865
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error) {
866
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
867
                *error = -1;
868
                return;
869
        }        
870
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle; 
871
        if(!session) {
872
                JANUS_LOG(LOG_ERR, "No AudioBridge session associated with this handle...\n");
873
                *error = -2;
874
                return;
875
        }
876
        JANUS_LOG(LOG_VERB, "Removing AudioBridge session...\n");
877
        janus_mutex_lock(&sessions_mutex);
878
        if(!session->destroyed) {
879
                session->destroyed = janus_get_monotonic_time();
880
                g_hash_table_remove(sessions, handle);
881
                janus_audiobridge_hangup_media(handle);
882
                /* Cleaning up and removing the session is done in a lazy way */
883
                old_sessions = g_list_append(old_sessions, session);
884
        }
885
        janus_mutex_unlock(&sessions_mutex);
886

    
887
        return;
888
}
889

    
890
char *janus_audiobridge_query_session(janus_plugin_session *handle) {
891
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
892
                return NULL;
893
        }        
894
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
895
        if(!session) {
896
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
897
                return NULL;
898
        }
899
        /* Show the participant/room info, if any */
900
        json_t *info = json_object();
901
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
902
        json_object_set_new(info, "state", json_string(participant && participant->room ? "inroom" : "idle"));
903
        if(participant) {
904
                janus_audiobridge_room *room = participant->room; 
905
                json_object_set_new(info, "room", room ? json_integer(room->room_id) : NULL);
906
                json_object_set_new(info, "id", json_integer(participant->user_id));
907
                if(participant->display)
908
                        json_object_set_new(info, "display", json_string(participant->display));
909
                json_object_set_new(info, "muted", json_string(participant->muted ? "true" : "false"));
910
                json_object_set_new(info, "active", json_string(participant->active ? "true" : "false"));
911
                if(participant->inbuf)
912
                        json_object_set_new(info, "queue-in", json_integer(g_queue_get_length(participant->inbuf)));
913
                if(participant->outbuf)
914
                        json_object_set_new(info, "queue-out", json_integer(g_async_queue_length(participant->outbuf)));
915
        }
916
        json_object_set_new(info, "started", json_string(session->started ? "true" : "false"));
917
        json_object_set_new(info, "destroyed", json_integer(session->destroyed));
918
        char *info_text = json_dumps(info, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
919
        json_decref(info);
920
        return info_text;
921
}
922

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

    
927
        /* Pre-parse the message */
928
        int error_code = 0;
929
        char error_cause[512];
930
        json_t *root = NULL;
931
        json_t *response = NULL;
932
        
933
        if(message == NULL) {
934
                JANUS_LOG(LOG_ERR, "No message??\n");
935
                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
936
                g_snprintf(error_cause, 512, "%s", "No message??");
937
                goto error;
938
        }
939
        JANUS_LOG(LOG_VERB, "Handling message: %s\n", message);
940

    
941
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
942
        if(!session) {
943
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
944
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
945
                g_snprintf(error_cause, 512, "%s", "session associated with this handle...");
946
                goto error;
947
        }
948
        if(session->destroyed) {
949
                JANUS_LOG(LOG_ERR, "Session has already been marked as destroyed...\n");
950
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
951
                g_snprintf(error_cause, 512, "%s", "Session has already been marked as destroyed...");
952
                goto error;
953
        }
954
        json_error_t error;
955
        root = json_loads(message, 0, &error);
956
        if(!root) {
957
                JANUS_LOG(LOG_ERR, "JSON error: on line %d: %s\n", error.line, error.text);
958
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON;
959
                g_snprintf(error_cause, 512, "JSON error: on line %d: %s", error.line, error.text);
960
                goto error;
961
        }
962
        if(!json_is_object(root)) {
963
                JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
964
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON;
965
                g_snprintf(error_cause, 512, "JSON error: not an object");
966
                goto error;
967
        }
968
        /* Get the request first */
969
        json_t *request = json_object_get(root, "request");
970
        if(!request) {
971
                JANUS_LOG(LOG_ERR, "Missing element (request)\n");
972
                error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
973
                g_snprintf(error_cause, 512, "Missing element (request)");
974
                goto error;
975
        }
976
        if(!json_is_string(request)) {
977
                JANUS_LOG(LOG_ERR, "Invalid element (request should be a string)\n");
978
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
979
                g_snprintf(error_cause, 512, "Invalid element (request should be a string)");
980
                goto error;
981
        }
982
        /* Some requests ('create', 'destroy', 'exists', 'list') can be handled synchronously */
983
        const char *request_text = json_string_value(request);
984
        if(!strcasecmp(request_text, "create")) {
985
                /* Create a new audiobridge */
986
                JANUS_LOG(LOG_VERB, "Creating a new audiobridge\n");
987
                json_t *desc = json_object_get(root, "description");
988
                if(desc && !json_is_string(desc)) {
989
                        JANUS_LOG(LOG_ERR, "Invalid element (description should be a string)\n");
990
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
991
                        g_snprintf(error_cause, 512, "Invalid element (description should be a string)");
992
                        goto error;
993
                }
994
                json_t *secret = json_object_get(root, "secret");
995
                if(secret && !json_is_string(secret)) {
996
                        JANUS_LOG(LOG_ERR, "Invalid element (secret should be a string)\n");
997
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
998
                        g_snprintf(error_cause, 512, "Invalid element (secret should be a string)");
999
                        goto error;
1000
                }
1001
                json_t *is_private = json_object_get(root, "is_private");
1002
                if(is_private && !json_is_boolean(is_private)) {
1003
                        JANUS_LOG(LOG_ERR, "Invalid element (is_private should be a boolean)\n");
1004
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1005
                        g_snprintf(error_cause, 512, "Invalid value (is_private should be a boolean)");
1006
                        goto error;
1007
                }
1008
                json_t *sampling = json_object_get(root, "sampling");
1009
                if(sampling && (!json_is_integer(sampling) || json_integer_value(sampling) < 0)) {
1010
                        JANUS_LOG(LOG_ERR, "Invalid element (sampling should be a positive integer)\n");
1011
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1012
                        g_snprintf(error_cause, 512, "Invalid element (sampling should be a positive integer)");
1013
                        goto error;
1014
                }
1015
                json_t *record = json_object_get(root, "record");
1016
                if(record && !json_is_boolean(record)) {
1017
                        JANUS_LOG(LOG_ERR, "Invalid element (record should be a boolean)\n");
1018
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1019
                        g_snprintf(error_cause, 512, "Invalid value (record should be a boolean)");
1020
                        goto error;
1021
                }
1022
                json_t *recfile = json_object_get(root, "record_file");
1023
                if(recfile && !json_is_string(record)) {
1024
                        JANUS_LOG(LOG_ERR, "Invalid element (record_file should be a string)\n");
1025
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1026
                        g_snprintf(error_cause, 512, "Invalid value (record_file should be a string)");
1027
                        goto error;
1028
                }
1029
                guint64 room_id = 0;
1030
                json_t *room = json_object_get(root, "room");
1031
                if(room && (!json_is_integer(room) || json_integer_value(room) < 0)) {
1032
                        JANUS_LOG(LOG_ERR, "Invalid element (room should be a positive integer)\n");
1033
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1034
                        g_snprintf(error_cause, 512, "Invalid element (room should be a positive integer)");
1035
                        goto error;
1036
                } else {
1037
                        room_id = json_integer_value(room);
1038
                        if(room_id == 0) {
1039
                                JANUS_LOG(LOG_WARN, "Desired room ID is 0, which is not allowed... picking random ID instead\n");
1040
                        }
1041
                }
1042
                janus_mutex_lock(&rooms_mutex);
1043
                if(room_id > 0) {
1044
                        /* Let's make sure the room doesn't exist already */
1045
                        if(g_hash_table_lookup(rooms, GUINT_TO_POINTER(room_id)) != NULL) {
1046
                                /* It does... */
1047
                                janus_mutex_unlock(&rooms_mutex);
1048
                                JANUS_LOG(LOG_ERR, "Room %"SCNu64" already exists!\n", room_id);
1049
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS;
1050
                                g_snprintf(error_cause, 512, "Room %"SCNu64" already exists", room_id);
1051
                                goto error;
1052
                        }
1053
                }
1054
                /* Create the audio bridge room */
1055
                janus_audiobridge_room *audiobridge = calloc(1, sizeof(janus_audiobridge_room));
1056
                if(audiobridge == NULL) {
1057
                        janus_mutex_unlock(&rooms_mutex);
1058
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1059
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1060
                        g_snprintf(error_cause, 512, "Memory error");
1061
                        goto error;
1062
                }
1063
                /* Generate a random ID */
1064
                if(room_id == 0) {
1065
                        while(room_id == 0) {
1066
                                room_id = g_random_int();
1067
                                if(g_hash_table_lookup(rooms, GUINT_TO_POINTER(room_id)) != NULL) {
1068
                                        /* Room ID already taken, try another one */
1069
                                        room_id = 0;
1070
                                }
1071
                        }
1072
                }
1073
                audiobridge->room_id = room_id;
1074
                char *description = NULL;
1075
                if(desc != NULL && strlen(json_string_value(desc)) > 0) {
1076
                        description = g_strdup(json_string_value(desc));
1077
                } else {
1078
                        char roomname[255];
1079
                        g_snprintf(roomname, 255, "Room %"SCNu64"", audiobridge->room_id);
1080
                        description = g_strdup(roomname);
1081
                }
1082
                if(description == NULL) {
1083
                        janus_mutex_unlock(&rooms_mutex);
1084
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1085
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1086
                        g_snprintf(error_cause, 512, "Memory error");
1087
                        goto error;
1088
                }
1089
                audiobridge->room_name = description;
1090
                audiobridge->is_private = is_private ? json_is_true(is_private) : FALSE;
1091
                if(secret)
1092
                        audiobridge->room_secret = g_strdup(json_string_value(secret));
1093
                if(sampling)
1094
                        audiobridge->sampling_rate = json_integer_value(sampling);
1095
                else
1096
                        audiobridge->sampling_rate = 16000;
1097
                switch(audiobridge->sampling_rate) {
1098
                        case 8000:
1099
                        case 12000:
1100
                        case 16000:
1101
                        case 24000:
1102
                        case 48000:
1103
                                JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
1104
                                break;
1105
                        default:
1106
                                janus_mutex_unlock(&rooms_mutex);
1107
                                JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
1108
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1109
                                g_snprintf(error_cause, 512, "We currently only support 16kHz (wideband) as a sampling rate for audio rooms, %"SCNu32" TBD...", audiobridge->sampling_rate);
1110
                                goto error;
1111
                }
1112
                audiobridge->record = FALSE;
1113
                if(record && json_is_true(record))
1114
                        audiobridge->record = TRUE;
1115
                if(recfile)
1116
                        audiobridge->record_file = g_strdup(json_string_value(recfile));
1117
                audiobridge->recording = NULL;
1118
                audiobridge->destroy = 0;
1119
                audiobridge->participants = g_hash_table_new(NULL, NULL);
1120
                audiobridge->destroyed = 0;
1121
                janus_mutex_init(&audiobridge->mutex);
1122
                g_hash_table_insert(rooms, GUINT_TO_POINTER(audiobridge->room_id), audiobridge);
1123
                JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s)\n", audiobridge->room_id, audiobridge->room_name, audiobridge->is_private ? "private" : "public", audiobridge->room_secret ? audiobridge->room_secret : "no secret");
1124
                /* We need a thread for the mix */
1125
                GError *error = NULL;
1126
                audiobridge->thread = g_thread_try_new("audiobridge mixer thread", &janus_audiobridge_mixer_thread, audiobridge, &error);
1127
                if(error != NULL) {
1128
                        janus_mutex_unlock(&rooms_mutex);
1129
                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
1130
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1131
                        g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the mixer thread", error->code, error->message ? error->message : "??");
1132
                        g_free(audiobridge->room_name);
1133
                        g_free(audiobridge->room_secret);
1134
                        g_free(audiobridge->record_file);
1135
                        g_hash_table_destroy(audiobridge->participants);
1136
                        g_free(audiobridge);
1137
                        goto error;
1138
                } else {
1139
                        g_hash_table_insert(rooms, GUINT_TO_POINTER(audiobridge->room_id), audiobridge);
1140
                }
1141
                /* Show updated rooms list */
1142
                GHashTableIter iter;
1143
                gpointer value;
1144
                g_hash_table_iter_init(&iter, rooms);
1145
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1146
                        janus_audiobridge_room *ar = value;
1147
                        JANUS_LOG(LOG_VERB, "  ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n",
1148
                                ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT");
1149
                }
1150
                janus_mutex_unlock(&rooms_mutex);
1151
                /* Send info back */
1152
                response = json_object();
1153
                json_object_set_new(response, "audiobridge", json_string("created"));
1154
                json_object_set_new(response, "room", json_integer(audiobridge->room_id));
1155
                goto plugin_response;
1156
        } else if(!strcasecmp(request_text, "destroy")) {
1157
                JANUS_LOG(LOG_VERB, "Attempt to destroy an existing audiobridge room\n");
1158
                json_t *room = json_object_get(root, "room");
1159
                if(!room) {
1160
                        JANUS_LOG(LOG_ERR, "Missing element (room)\n");
1161
                        error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
1162
                        g_snprintf(error_cause, 512, "Missing element (room)");
1163
                        goto error;
1164
                }
1165
                if(!json_is_integer(room) || json_integer_value(room) < 0) {
1166
                        JANUS_LOG(LOG_ERR, "Invalid element (room should be a positive integer)\n");
1167
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1168
                        g_snprintf(error_cause, 512, "Invalid element (room should be a positive integer)");
1169
                        goto error;
1170
                }
1171
                guint64 room_id = json_integer_value(room);
1172
                janus_mutex_lock(&rooms_mutex);
1173
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, GUINT_TO_POINTER(room_id));
1174
                if(audiobridge == NULL) {
1175
                        janus_mutex_unlock(&rooms_mutex);
1176
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1177
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1178
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1179
                        goto error;
1180
                }
1181
                if(audiobridge->room_secret) {
1182
                        /* A secret is required for this action */
1183
                        json_t *secret = json_object_get(root, "secret");
1184
                        if(!secret) {
1185
                                janus_mutex_unlock(&rooms_mutex);
1186
                                JANUS_LOG(LOG_ERR, "Missing element (secret)\n");
1187
                                error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
1188
                                g_snprintf(error_cause, 512, "Missing element (secret)");
1189
                                goto error;
1190
                        }
1191
                        if(!json_is_string(secret)) {
1192
                                janus_mutex_unlock(&rooms_mutex);
1193
                                JANUS_LOG(LOG_ERR, "Invalid element (secret should be a string)\n");
1194
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1195
                                g_snprintf(error_cause, 512, "Invalid element (secret should be a string)");
1196
                                goto error;
1197
                        }
1198
                        if(!janus_strcmp_const_time(audiobridge->room_secret, json_string_value(secret))) {
1199
                                janus_mutex_unlock(&rooms_mutex);
1200
                                JANUS_LOG(LOG_ERR, "Unauthorized (wrong secret)\n");
1201
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED;
1202
                                g_snprintf(error_cause, 512, "Unauthorized (wrong secret)");
1203
                                goto error;
1204
                        }
1205
                }
1206
                /* Remove room */
1207
                g_hash_table_remove(rooms, GUINT_TO_POINTER(room_id));
1208
                /* Prepare response/notification */
1209
                response = json_object();
1210
                json_object_set_new(response, "audiobridge", json_string("destroyed"));
1211
                json_object_set_new(response, "room", json_integer(room_id));
1212
                char *response_text = json_dumps(response, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1213
                /* Notify all participants that the fun is over, and that they'll be kicked */
1214
                JANUS_LOG(LOG_VERB, "Notifying all participants\n");
1215
                GHashTableIter iter;
1216
                gpointer value;
1217
                g_hash_table_iter_init(&iter, audiobridge->participants);
1218
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1219
                        janus_audiobridge_participant *p = value;
1220
                        if(p && p->session) {
1221
                                p->room = NULL;
1222
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, response_text, NULL, NULL);
1223
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1224
                                /* Get rid of queued packets */
1225
                                janus_mutex_lock(&p->qmutex);
1226
                                p->active = FALSE;
1227
                                while(!g_queue_is_empty(p->inbuf)) {
1228
                                        janus_audiobridge_rtp_relay_packet *pkt = g_queue_pop_head(p->inbuf);
1229
                                        if(pkt == NULL)
1230
                                                continue;
1231
                                        if(pkt->data)
1232
                                                g_free(pkt->data);
1233
                                        pkt->data = NULL;
1234
                                        g_free(pkt);
1235
                                        pkt = NULL;
1236
                                }
1237
                                janus_mutex_unlock(&p->qmutex);
1238
                        }
1239
                }
1240
                g_free(response_text);
1241
                janus_mutex_unlock(&rooms_mutex);
1242
                JANUS_LOG(LOG_VERB, "Waiting for the mixer thread to complete...\n");
1243
                audiobridge->destroyed = janus_get_monotonic_time();
1244
                g_thread_join(audiobridge->thread);
1245
                /* Done */
1246
                JANUS_LOG(LOG_VERB, "Audiobridge room destroyed\n");
1247
                goto plugin_response;
1248
        } else if(!strcasecmp(request_text, "list")) {
1249
                /* List all rooms (but private ones) and their details (except for the secret, of course...) */
1250
                json_t *list = json_array();
1251
                JANUS_LOG(LOG_VERB, "Request for the list for all video rooms\n");
1252
                janus_mutex_lock(&rooms_mutex);
1253
                GHashTableIter iter;
1254
                gpointer value;
1255
                g_hash_table_iter_init(&iter, rooms);
1256
                while(g_hash_table_iter_next(&iter, NULL, &value)) {
1257
                        janus_audiobridge_room *room = value;
1258
                        if(!room)
1259
                                continue;
1260
                        if(room->is_private) {
1261
                                /* Skip private room */
1262
                                JANUS_LOG(LOG_VERB, "Skipping private room '%s'\n", room->room_name);
1263
                                continue;
1264
                        }
1265
                        json_t *rl = json_object();
1266
                        json_object_set_new(rl, "room", json_integer(room->room_id));
1267
                        json_object_set_new(rl, "description", json_string(room->room_name));
1268
                        json_object_set_new(rl, "sampling_rate", json_integer(room->sampling_rate));
1269
                        json_object_set_new(rl, "record", json_string(room->record ? "true" : "false"));
1270
                        /* TODO: Possibly list participant details... or make it a separate API call for a specific room */
1271
                        json_object_set_new(rl, "num_participants", json_integer(g_hash_table_size(room->participants)));
1272
                        json_array_append_new(list, rl);
1273
                }
1274
                janus_mutex_unlock(&rooms_mutex);
1275
                response = json_object();
1276
                json_object_set_new(response, "audiobridge", json_string("success"));
1277
                json_object_set_new(response, "list", list);
1278
                goto plugin_response;
1279
        } else if(!strcasecmp(request_text, "exists")) {
1280
                /* Check whether a given room exists or not, returns true/false */        
1281
                json_t *room = json_object_get(root, "room");
1282
                if(!room) {
1283
                        JANUS_LOG(LOG_ERR, "Missing element (room)\n");
1284
                        error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
1285
                        g_snprintf(error_cause, 512, "Missing element (room)");
1286
                        goto error;
1287
                }
1288
                if(!json_is_integer(room) || json_integer_value(room) < 0) {
1289
                        JANUS_LOG(LOG_ERR, "Invalid element (room should be a positive integer)\n");
1290
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1291
                        g_snprintf(error_cause, 512, "Invalid element (room should be a positive integer)");
1292
                        goto error;
1293
                }
1294
                guint64 room_id = json_integer_value(room);
1295
                janus_mutex_lock(&rooms_mutex);
1296
                gboolean room_exists = g_hash_table_contains(rooms, GUINT_TO_POINTER(room_id));
1297
                janus_mutex_unlock(&rooms_mutex);
1298
                response = json_object();
1299
                json_object_set_new(response, "audiobridge", json_string("success"));
1300
                json_object_set_new(response, "room", json_integer(room_id));
1301
                json_object_set_new(response, "exists", json_string(room_exists ? "true" : "false"));
1302
                goto plugin_response;
1303
        } else if(!strcasecmp(request_text, "listparticipants")) {
1304
                /* List all participants in a room */        
1305
                json_t *room = json_object_get(root, "room");
1306
                if(!room || !json_is_integer(room) || json_integer_value(room) < 0) {
1307
                        JANUS_LOG(LOG_ERR, "Invalid request, room number must be included in request and must be a positive integer\n");
1308
                        error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
1309
                        g_snprintf(error_cause, 512, "Missing element (room)");
1310
                        goto error;
1311
                }
1312
                guint64 room_id = json_integer_value(room);
1313
                janus_mutex_lock(&rooms_mutex);
1314
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, GUINT_TO_POINTER(room_id));
1315
                janus_mutex_unlock(&rooms_mutex);
1316
                if(audiobridge == NULL) {
1317
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1318
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1319
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1320
                        goto error;
1321
                }
1322
                if(audiobridge->destroyed) {
1323
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1324
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1325
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1326
                        goto error;
1327
                }
1328
                /* Return a list of all participants */
1329
                janus_mutex_lock(&audiobridge->mutex);
1330
                json_t *list = json_array();
1331
                GHashTableIter iter;
1332
                gpointer value;
1333
                g_hash_table_iter_init(&iter, audiobridge->participants);
1334
                while (!audiobridge->destroyed && g_hash_table_iter_next(&iter, NULL, &value)) {
1335
                        janus_audiobridge_participant *p = value;
1336
                        json_t *pl = json_object();
1337
                        json_object_set_new(pl, "id", json_integer(p->user_id));
1338
                        if(p->display)
1339
                                json_object_set_new(pl, "display", json_string(p->display));
1340
                        json_object_set_new(pl, "muted", json_string(p->muted ? "true" : "false"));
1341
                        json_array_append_new(list, pl);
1342
                }
1343
                janus_mutex_unlock(&audiobridge->mutex);
1344
                response = json_object();
1345
                json_object_set_new(response, "audiobridge", json_string("participants"));
1346
                json_object_set_new(response, "room", json_integer(room_id));
1347
                json_object_set_new(response, "participants", list);
1348
                goto plugin_response;
1349
        } else if(!strcasecmp(request_text, "resetdecoder")) {
1350
                /* Mark the Opus decoder for the participant invalid and recreate it */        
1351
                janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1352
                if(participant == NULL || participant->room == NULL) {
1353
                        JANUS_LOG(LOG_ERR, "Can't reset (not in a room)\n");
1354
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
1355
                        g_snprintf(error_cause, 512, "Can't reset (not in a room)");
1356
                        goto error;
1357
                }
1358
                participant->reset = TRUE;
1359
                response = json_object();
1360
                json_object_set_new(response, "audiobridge", json_string("success"));
1361
                goto plugin_response;
1362
        } else if(!strcasecmp(request_text, "join") || !strcasecmp(request_text, "configure")
1363
                        || !strcasecmp(request_text, "changeroom") || !strcasecmp(request_text, "leave")) {
1364
                /* These messages are handled asynchronously */
1365
                janus_audiobridge_message *msg = calloc(1, sizeof(janus_audiobridge_message));
1366
                if(msg == NULL) {
1367
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1368
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1369
                        g_snprintf(error_cause, 512, "Memory error");
1370
                        goto error;
1371
                }
1372

    
1373
                g_free(message);
1374
                msg->handle = handle;
1375
                msg->transaction = transaction;
1376
                msg->message = root;
1377
                msg->sdp_type = sdp_type;
1378
                msg->sdp = sdp;
1379

    
1380
                g_async_queue_push(messages, msg);
1381

    
1382
                return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL);
1383
        } else {
1384
                JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
1385
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
1386
                g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
1387
                goto error;
1388
        }
1389

    
1390
plugin_response:
1391
                {
1392
                        if (!response) {
1393
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1394
                                g_snprintf(error_cause, 512, "Invalid response");
1395
                                goto error;
1396
                        }
1397
                        if(root != NULL)
1398
                                json_decref(root);
1399
                        g_free(transaction);
1400
                        g_free(message);
1401
                        g_free(sdp_type);
1402
                        g_free(sdp);
1403

    
1404
                        char *response_text = json_dumps(response, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1405
                        json_decref(response);
1406
                        janus_plugin_result *result = janus_plugin_result_new(JANUS_PLUGIN_OK, response_text);
1407
                        g_free(response_text);
1408
                        return result;
1409
                }
1410

    
1411
error:
1412
                {
1413
                        if(root != NULL)
1414
                                json_decref(root);
1415
                        g_free(transaction);
1416
                        g_free(message);
1417
                        g_free(sdp_type);
1418
                        g_free(sdp);
1419

    
1420
                        /* Prepare JSON error event */
1421
                        json_t *event = json_object();
1422
                        json_object_set_new(event, "audiobridge", json_string("event"));
1423
                        json_object_set_new(event, "error_code", json_integer(error_code));
1424
                        json_object_set_new(event, "error", json_string(error_cause));
1425
                        char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1426
                        json_decref(event);
1427
                        janus_plugin_result *result = janus_plugin_result_new(JANUS_PLUGIN_OK, event_text);
1428
                        g_free(event_text);
1429
                        return result;
1430
                }
1431

    
1432
}
1433

    
1434
void janus_audiobridge_setup_media(janus_plugin_session *handle) {
1435
        JANUS_LOG(LOG_INFO, "WebRTC media is now available\n");
1436
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1437
                return;
1438
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1439
        if(!session) {
1440
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1441
                return;
1442
        }
1443
        if(session->destroyed)
1444
                return;
1445
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1446
        if(!participant)
1447
                return;
1448
        /* FIXME Only send this peer the audio mix when we get this event */
1449
        session->started = TRUE;
1450
}
1451

    
1452
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len) {
1453
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1454
                return;
1455
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1456
        if(!session || session->destroyed || session->stopping || !session->participant)
1457
                return;
1458
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1459
        if(!participant->active || participant->muted || !participant->decoder || !participant->room)
1460
                return;
1461
        if(participant->active && participant->decoder) {
1462
                /* First of all, check if a reset on the decoder is due */
1463
                if(participant->reset) {
1464
                        /* Create a new decoder and get rid of the old one */
1465
                        int error = 0;
1466
                        OpusDecoder *decoder = opus_decoder_create(participant->room->sampling_rate, 1, &error);
1467
                        if(error != OPUS_OK) {
1468
                                JANUS_LOG(LOG_ERR, "Error resetting Opus decoder...\n");
1469
                        } else {
1470
                                if(participant->decoder)
1471
                                        opus_decoder_destroy(participant->decoder);
1472
                                participant->decoder = decoder;
1473
                                JANUS_LOG(LOG_VERB, "Opus decoder reset\n");
1474
                        }
1475
                        participant->reset = FALSE;
1476
                }
1477
                /* Decode frame (Opus -> slinear) */
1478
                janus_audiobridge_rtp_relay_packet *pkt = calloc(1, sizeof(janus_audiobridge_rtp_relay_packet));
1479
                if(pkt == NULL) {
1480
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1481
                        return;
1482
                }
1483
                pkt->data = calloc(BUFFER_SAMPLES, sizeof(opus_int16));
1484
                if(pkt->data == NULL) {
1485
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1486
                        g_free(pkt);
1487
                        return;
1488
                }
1489
                pkt->ssrc = 0;
1490
                pkt->timestamp = 0;
1491
                pkt->seq_number = 0;
1492
                participant->working = TRUE;
1493
                pkt->length = opus_decode(participant->decoder, (const unsigned char *)buf+12, len-12, (opus_int16 *)pkt->data, BUFFER_SAMPLES, USE_FEC);
1494
                participant->working = FALSE;
1495
                if(pkt->length < 0) {
1496
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", pkt->length, opus_strerror(pkt->length));
1497
                        g_free(pkt->data);
1498
                        g_free(pkt);
1499
                        return;
1500
                }
1501
                /* Enqueue the decoded frame */
1502
                janus_mutex_lock(&participant->qmutex);
1503
                g_queue_push_tail(participant->inbuf, pkt);
1504
                /* Keep the queue at max of 150 packets, though */
1505
                if(g_queue_get_length(participant->inbuf) > 150) {
1506
                        /* Remove the oldest packet */
1507
                        janus_audiobridge_rtp_relay_packet *pkt = g_queue_pop_head(participant->inbuf);
1508
                        if(pkt != NULL) {
1509
                                if(pkt->data)
1510
                                        g_free(pkt->data);
1511
                                pkt->data = NULL;
1512
                                g_free(pkt);
1513
                                pkt = NULL;
1514
                        }
1515
                }
1516
                janus_mutex_unlock(&participant->qmutex);
1517
        }
1518
}
1519

    
1520
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len) {
1521
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1522
                return;
1523
        /* FIXME Should we care? */
1524
}
1525

    
1526
void janus_audiobridge_hangup_media(janus_plugin_session *handle) {
1527
        JANUS_LOG(LOG_INFO, "No WebRTC media anymore\n");
1528
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1529
                return;
1530
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1531
        if(!session) {
1532
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1533
                return;
1534
        }
1535
        if(session->destroyed || !session->participant)
1536
                return;
1537
        /* Get rid of participant */
1538
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1539
        janus_audiobridge_room *audiobridge = participant->room;
1540
        if(audiobridge != NULL) {
1541
                janus_mutex_lock(&audiobridge->mutex);
1542
                json_t *event = json_object();
1543
                json_object_set_new(event, "audiobridge", json_string("event"));
1544
                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
1545
                json_object_set_new(event, "leaving", json_integer(participant->user_id));
1546
                char *leaving_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1547
                json_decref(event);
1548
                g_hash_table_remove(audiobridge->participants, GUINT_TO_POINTER(participant->user_id));
1549
                GHashTableIter iter;
1550
                gpointer value;
1551
                g_hash_table_iter_init(&iter, audiobridge->participants);
1552
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1553
                        janus_audiobridge_participant *p = value;
1554
                        if(p == participant) {
1555
                                continue;        /* Skip the leaving participant itself */
1556
                        }
1557
                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
1558
                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, leaving_text, NULL, NULL);
1559
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1560
                }
1561
                g_free(leaving_text);
1562
        }
1563
        /* Free the participant resources */
1564
        janus_mutex_lock(&participant->qmutex);
1565
        session->started = FALSE;
1566
        participant->active = FALSE;
1567
        participant->muted = TRUE;
1568
        if(participant->display)
1569
                g_free(participant->display);
1570
        participant->display = NULL;
1571
        /* Make sure we're not using the encoder/decoder right now, we're going to destroy them */
1572
        while(participant->working)
1573
                g_usleep(5000);
1574
        if(participant->encoder)
1575
                opus_encoder_destroy(participant->encoder);
1576
        participant->encoder = NULL;
1577
        if(participant->decoder)
1578
                opus_decoder_destroy(participant->decoder);
1579
        participant->decoder = NULL;
1580
        participant->reset = FALSE;
1581
        /* Get rid of queued packets */
1582
        while(!g_queue_is_empty(participant->inbuf)) {
1583
                janus_audiobridge_rtp_relay_packet *pkt = g_queue_pop_head(participant->inbuf);
1584
                if(pkt == NULL)
1585
                        continue;
1586
                if(pkt->data)
1587
                        g_free(pkt->data);
1588
                pkt->data = NULL;
1589
                g_free(pkt);
1590
                pkt = NULL;
1591
        }
1592
        janus_mutex_unlock(&participant->qmutex);
1593
        if(audiobridge != NULL) {
1594
                janus_mutex_unlock(&audiobridge->mutex);
1595
        }
1596
}
1597

    
1598
/* Thread to handle incoming messages */
1599
static void *janus_audiobridge_handler(void *data) {
1600
        JANUS_LOG(LOG_VERB, "Joining AudioBridge handler thread\n");
1601
        janus_audiobridge_message *msg = NULL;
1602
        int error_code = 0;
1603
        char *error_cause = calloc(512, sizeof(char));
1604
        if(error_cause == NULL) {
1605
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
1606
                return NULL;
1607
        }
1608
        json_t *root = NULL;
1609
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
1610
                if(!messages || (msg = g_async_queue_try_pop(messages)) == NULL) {
1611
                        usleep(50000);
1612
                        continue;
1613
                }
1614
                janus_audiobridge_session *session = (janus_audiobridge_session *)msg->handle->plugin_handle;        
1615
                if(!session) {
1616
                        JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1617
                        janus_audiobridge_message_free(msg);
1618
                        continue;
1619
                }
1620
                if(session->destroyed) {
1621
                        janus_audiobridge_message_free(msg);
1622
                        continue;
1623
                }
1624
                /* Handle request */
1625
                error_code = 0;
1626
                root = NULL;
1627
                if(msg->message == NULL) {
1628
                        JANUS_LOG(LOG_ERR, "No message??\n");
1629
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
1630
                        g_snprintf(error_cause, 512, "%s", "No message??");
1631
                        goto error;
1632
                }
1633
                root = msg->message;
1634
                /* Get the request first */
1635
                json_t *request = json_object_get(root, "request");
1636
                if(!request) {
1637
                        JANUS_LOG(LOG_ERR, "Missing element (request)\n");
1638
                        error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
1639
                        g_snprintf(error_cause, 512, "Missing element (request)");
1640
                        goto error;
1641
                }
1642
                if(!json_is_string(request)) {
1643
                        JANUS_LOG(LOG_ERR, "Invalid element (request should be a string)\n");
1644
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1645
                        g_snprintf(error_cause, 512, "Invalid element (request should be a string)");
1646
                        goto error;
1647
                }
1648
                const char *request_text = json_string_value(request);
1649
                json_t *event = NULL;
1650
                if(!strcasecmp(request_text, "join")) {
1651
                        JANUS_LOG(LOG_VERB, "Configuring new participant\n");
1652
                        janus_audiobridge_participant *participant = session->participant;
1653
                        if(participant != NULL && participant->room != NULL) {
1654
                                JANUS_LOG(LOG_ERR, "Already in a room (use changeroom to join another one)\n");
1655
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED;
1656
                                g_snprintf(error_cause, 512, "Already in a room (use changeroom to join another one)");
1657
                                goto error;
1658
                        }
1659
                        json_t *room = json_object_get(root, "room");
1660
                        if(!room) {
1661
                                JANUS_LOG(LOG_ERR, "Missing element (room)\n");
1662
                                error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
1663
                                g_snprintf(error_cause, 512, "Missing element (room)");
1664
                                goto error;
1665
                        }
1666
                        if(!json_is_integer(room) || json_integer_value(room) < 0) {
1667
                                JANUS_LOG(LOG_ERR, "Invalid element (room should be a positive integer)\n");
1668
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1669
                                g_snprintf(error_cause, 512, "Invalid element (room should be a positive integer)");
1670
                                goto error;
1671
                        }
1672
                        guint64 room_id = json_integer_value(room);
1673
                        janus_mutex_lock(&rooms_mutex);
1674
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, GUINT_TO_POINTER(room_id));
1675
                        if(audiobridge == NULL) {
1676
                                janus_mutex_unlock(&rooms_mutex);
1677
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1678
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1679
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1680
                                goto error;
1681
                        }
1682
                        janus_mutex_unlock(&rooms_mutex);
1683
                        json_t *display = json_object_get(root, "display");
1684
                        if(display && !json_is_string(display)) {
1685
                                JANUS_LOG(LOG_ERR, "Invalid element (display should be a string)\n");
1686
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1687
                                g_snprintf(error_cause, 512, "Invalid element (display should be a string)");
1688
                                goto error;
1689
                        }
1690
                        const char *display_text = display ? json_string_value(display) : NULL;
1691
                        json_t *muted = json_object_get(root, "muted");
1692
                        if(muted && !json_is_boolean(muted)) {
1693
                                JANUS_LOG(LOG_ERR, "Invalid element (muted should be a boolean)\n");
1694
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1695
                                g_snprintf(error_cause, 512, "Invalid element (muted should be a boolean)");
1696
                                goto error;
1697
                        }
1698
                        json_t *quality = json_object_get(root, "quality");
1699
                        if(quality && (!json_is_integer(quality) || json_integer_value(quality) < 0)) {
1700
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer)\n");
1701
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1702
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer)");
1703
                                goto error;
1704
                        }
1705
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
1706
                        if(complexity < 1 || complexity > 10) {
1707
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
1708
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1709
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
1710
                                goto error;
1711
                        }
1712
                        guint64 user_id = 0;
1713
                        json_t *id = json_object_get(root, "id");
1714
                        if(id) {
1715
                                if(!json_is_integer(id) || json_integer_value(id) < 0) {
1716
                                        JANUS_LOG(LOG_ERR, "Invalid element (id should be a positive integer)\n");
1717
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1718
                                        g_snprintf(error_cause, 512, "Invalid element (id should be a positive integer)");
1719
                                        goto error;
1720
                                }
1721
                                user_id = json_integer_value(id);
1722
                                if(g_hash_table_lookup(audiobridge->participants, GUINT_TO_POINTER(user_id)) != NULL) {
1723
                                        /* User ID already taken */
1724
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
1725
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
1726
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
1727
                                        goto error;
1728
                                }
1729
                        }
1730
                        if(user_id == 0) {
1731
                                /* Generate a random ID */
1732
                                while(user_id == 0) {
1733
                                        user_id = g_random_int();
1734
                                        if(g_hash_table_lookup(audiobridge->participants, GUINT_TO_POINTER(user_id)) != NULL) {
1735
                                                /* User ID already taken, try another one */
1736
                                                user_id = 0;
1737
                                        }
1738
                                }
1739
                        }
1740
                        JANUS_LOG(LOG_VERB, "  -- Participant ID: %"SCNu64"\n", user_id);
1741
                        if(participant == NULL) {
1742
                                participant = calloc(1, sizeof(janus_audiobridge_participant));
1743
                                if(participant == NULL) {
1744
                                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1745
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1746
                                        g_snprintf(error_cause, 512, "Memory error");
1747
                                        goto error;
1748
                                }
1749
                                participant->active = FALSE;
1750
                                participant->display = NULL;
1751
                                participant->inbuf = NULL;
1752
                                participant->outbuf = NULL;
1753
                                participant->encoder = NULL;
1754
                                participant->decoder = NULL;
1755
                                participant->reset = FALSE;
1756
                                janus_mutex_init(&participant->qmutex);
1757
                        }
1758
                        participant->session = session;
1759
                        participant->room = audiobridge;
1760
                        participant->user_id = user_id;
1761
                        if(participant->display != NULL)
1762
                                g_free(participant->display);
1763
                        participant->display = display_text ? g_strdup(display_text) : NULL;
1764
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* By default, everyone's unmuted when joining */
1765
                        participant->opus_complexity = complexity;
1766
                        if(participant->inbuf == NULL)
1767
                                participant->inbuf = g_queue_new();
1768
                        if(participant->outbuf == NULL)
1769
                                participant->outbuf = g_async_queue_new();
1770
                        participant->active = session->started;
1771
                        if(!session->started) {
1772
                                /* Initialize the RTP context only if we're renegotiating */
1773
                                participant->context.a_last_ssrc = 0;
1774
                                participant->context.a_last_ts = 0;
1775
                                participant->context.a_base_ts = 0;
1776
                                participant->context.a_base_ts_prev = 0;
1777
                                participant->context.a_last_seq = 0;
1778
                                participant->context.a_base_seq = 0;
1779
                                participant->context.a_base_seq_prev = 0;
1780
                                participant->opus_pt = 0;
1781
                        }
1782
                        JANUS_LOG(LOG_VERB, "Creating Opus encoder/decoder (sampling rate %d)\n", audiobridge->sampling_rate);
1783
                        /* Opus encoder */
1784
                        int error = 0;
1785
                        if(participant->encoder == NULL) {
1786
                                participant->encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
1787
                                if(error != OPUS_OK) {
1788
                                        if(participant->display)
1789
                                                g_free(participant->display);
1790
                                        g_free(participant);
1791
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
1792
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
1793
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
1794
                                        goto error;
1795
                                }
1796
                                if(audiobridge->sampling_rate == 8000) {
1797
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
1798
                                } else if(audiobridge->sampling_rate == 12000) {
1799
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
1800
                                } else if(audiobridge->sampling_rate == 16000) {
1801
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
1802
                                } else if(audiobridge->sampling_rate == 24000) {
1803
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
1804
                                } else if(audiobridge->sampling_rate == 48000) {
1805
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
1806
                                } else {
1807
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
1808
                                        audiobridge->sampling_rate = 16000;
1809
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
1810
                                }
1811
                                /* FIXME This settings should be configurable */
1812
                                opus_encoder_ctl(participant->encoder, OPUS_SET_INBAND_FEC(USE_FEC));
1813
                        }
1814
                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
1815
                        if(participant->decoder == NULL) {
1816
                                /* Opus decoder */
1817
                                error = 0;
1818
                                participant->decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
1819
                                if(error != OPUS_OK) {
1820
                                        if(participant->display)
1821
                                                g_free(participant->display);
1822
                                        if(participant->encoder)
1823
                                                opus_encoder_destroy(participant->encoder);
1824
                                        participant->encoder = NULL;
1825
                                        if(participant->decoder)
1826
                                                opus_decoder_destroy(participant->decoder);
1827
                                        participant->decoder = NULL;
1828
                                        g_free(participant);
1829
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
1830
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
1831
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
1832
                                        goto error;
1833
                                }
1834
                        }
1835
                        participant->reset = FALSE;
1836
                        /* Finally, start the encoding thread if it hasn't already */
1837
                        if(participant->thread == NULL) {
1838
                                GError *error = NULL;
1839
                                participant->thread = g_thread_try_new("audiobridge participant thread", &janus_audiobridge_participant_thread, participant, &error);
1840
                                if(error != NULL) {
1841
                                        /* FIXME We should fail here... */
1842
                                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the participant thread...\n", error->code, error->message ? error->message : "??");
1843
                                }
1844
                        }
1845
                        
1846
                        /* Done */
1847
                        janus_mutex_lock(&audiobridge->mutex);
1848
                        session->participant = participant;
1849
                        g_hash_table_insert(audiobridge->participants, GUINT_TO_POINTER(user_id), participant);
1850
                        /* Notify the other participants */
1851
                        json_t *newuser = json_object();
1852
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
1853
                        json_object_set_new(newuser, "room", json_integer(audiobridge->room_id));
1854
                        json_t *newuserlist = json_array();
1855
                        json_t *pl = json_object();
1856
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
1857
                        if(participant->display)
1858
                                json_object_set_new(pl, "display", json_string(participant->display));
1859
                        json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
1860
                        json_array_append_new(newuserlist, pl);
1861
                        json_object_set_new(newuser, "participants", newuserlist);
1862
                        char *newuser_text = json_dumps(newuser, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1863
                        json_decref(newuser);
1864
                        GHashTableIter iter;
1865
                        gpointer value;
1866
                        g_hash_table_iter_init(&iter, audiobridge->participants);
1867
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
1868
                                janus_audiobridge_participant *p = value;
1869
                                if(p == participant) {
1870
                                        continue;
1871
                                }
1872
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
1873
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser_text, NULL, NULL);
1874
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1875
                        }
1876
                        g_free(newuser_text);
1877
                        /* Return a list of all available participants for the new participant now */
1878
                        json_t *list = json_array();
1879
                        g_hash_table_iter_init(&iter, audiobridge->participants);
1880
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
1881
                                janus_audiobridge_participant *p = value;
1882
                                if(p == participant) {
1883
                                        continue;
1884
                                }
1885
                                json_t *pl = json_object();
1886
                                json_object_set_new(pl, "id", json_integer(p->user_id));
1887
                                if(p->display)
1888
                                        json_object_set_new(pl, "display", json_string(p->display));
1889
                                json_object_set_new(pl, "muted", json_string(p->muted ? "true" : "false"));
1890
                                json_array_append_new(list, pl);
1891
                        }
1892
                        event = json_object();
1893
                        json_object_set_new(event, "audiobridge", json_string("joined"));
1894
                        json_object_set_new(event, "room", json_integer(audiobridge->room_id));
1895
                        json_object_set_new(event, "id", json_integer(user_id));
1896
                        json_object_set_new(event, "participants", list);
1897
                        janus_mutex_unlock(&audiobridge->mutex);
1898
                } else if(!strcasecmp(request_text, "configure")) {
1899
                        /* Handle this participant */
1900
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1901
                        if(participant == NULL || participant->room == NULL) {
1902
                                JANUS_LOG(LOG_ERR, "Can't configure (not in a room)\n");
1903
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
1904
                                g_snprintf(error_cause, 512, "Can't configure (not in a room)");
1905
                                goto error;
1906
                        }
1907
                        /* Configure settings for this participant */
1908
                        json_t *muted = json_object_get(root, "muted");
1909
                        if(muted && !json_is_boolean(muted)) {
1910
                                JANUS_LOG(LOG_ERR, "Invalid element (muted should be a boolean)\n");
1911
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1912
                                g_snprintf(error_cause, 512, "Invalid element (muted should be a boolean)");
1913
                                goto error;
1914
                        }
1915
                        json_t *quality = json_object_get(root, "quality");
1916
                        if(quality && (!json_is_integer(quality) || json_integer_value(quality) < 0)) {
1917
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer)\n");
1918
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1919
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer)");
1920
                                goto error;
1921
                        }
1922
                        if(quality) {
1923
                                int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
1924
                                if(complexity < 1 || complexity > 10) {
1925
                                        JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
1926
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1927
                                        g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
1928
                                        goto error;
1929
                                }
1930
                                participant->opus_complexity = complexity;
1931
                                if(participant->encoder)
1932
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
1933
                        }
1934
                        if(muted) {
1935
                                participant->muted = json_is_true(muted);
1936
                                JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %"SCNu64", user %"SCNu64")\n", participant->muted ? "true" : "false", participant->room->room_id, participant->user_id);
1937
                                if(participant->muted) {
1938
                                        /* Clear the queued packets waiting to be handled */
1939
                                        janus_mutex_lock(&participant->qmutex);
1940
                                        while(!g_queue_is_empty(participant->inbuf)) {
1941
                                                janus_audiobridge_rtp_relay_packet *pkt = g_queue_pop_head(participant->inbuf);
1942
                                                if(pkt == NULL)
1943
                                                        continue;
1944
                                                if(pkt->data)
1945
                                                        g_free(pkt->data);
1946
                                                pkt->data = NULL;
1947
                                                g_free(pkt);
1948
                                                pkt = NULL;
1949
                                        }
1950
                                        janus_mutex_unlock(&participant->qmutex);
1951
                                }
1952
                                /* Notify all other participants about the mute/unmute */
1953
                                janus_audiobridge_room *audiobridge = participant->room;
1954
                                janus_mutex_lock(&audiobridge->mutex);
1955
                                json_t *list = json_array();
1956
                                json_t *pl = json_object();
1957
                                json_object_set_new(pl, "id", json_integer(participant->user_id));
1958
                                if(participant->display)
1959
                                        json_object_set_new(pl, "display", json_string(participant->display));
1960
                                json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
1961
                                json_array_append_new(list, pl);
1962
                                json_t *pub = json_object();
1963
                                json_object_set_new(pub, "audiobridge", json_string("event"));
1964
                                json_object_set_new(pub, "room", json_integer(participant->room->room_id));
1965
                                json_object_set_new(pub, "participants", list);
1966
                                char *pub_text = json_dumps(pub, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1967
                                json_decref(pub);
1968
                                GHashTableIter iter;
1969
                                gpointer value;
1970
                                g_hash_table_iter_init(&iter, audiobridge->participants);
1971
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1972
                                        janus_audiobridge_participant *p = value;
1973
                                        if(p == participant) {
1974
                                                continue;        /* Skip the new participant itself */
1975
                                        }
1976
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
1977
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub_text, NULL, NULL);
1978
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1979
                                }
1980
                                g_free(pub_text);
1981
                                janus_mutex_unlock(&audiobridge->mutex);
1982
                        }
1983
                        /* Done */
1984
                        event = json_object();
1985
                        json_object_set_new(event, "audiobridge", json_string("event"));
1986
                        json_object_set_new(event, "room", json_integer(participant->room->room_id));
1987
                        json_object_set_new(event, "result", json_string("ok"));
1988
                } else if(!strcasecmp(request_text, "changeroom")) {
1989
                        /* The participant wants to leave the current room and join another one without reconnecting (e.g., a sidebar) */
1990
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1991
                        if(participant == NULL || participant->room == NULL) {
1992
                                JANUS_LOG(LOG_ERR, "Can't change room (not in a room in the first place)\n");
1993
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
1994
                                g_snprintf(error_cause, 512, "Can't change room (not in a room in the first place");
1995
                                goto error;
1996
                        }
1997
                        json_t *room = json_object_get(root, "room");
1998
                        if(!room) {
1999
                                JANUS_LOG(LOG_ERR, "Missing element (room)\n");
2000
                                error_code = JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT;
2001
                                g_snprintf(error_cause, 512, "Missing element (room)");
2002
                                goto error;
2003
                        }
2004
                        if(!json_is_integer(room) || json_integer_value(room) < 0) {
2005
                                JANUS_LOG(LOG_ERR, "Invalid element (room should be a positive integer)\n");
2006
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2007
                                g_snprintf(error_cause, 512, "Invalid element (room should be a positive integer)");
2008
                                goto error;
2009
                        }
2010
                        guint64 room_id = json_integer_value(room);
2011
                        janus_mutex_lock(&rooms_mutex);
2012
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, GUINT_TO_POINTER(room_id));
2013
                        if(audiobridge == NULL) {
2014
                                janus_mutex_unlock(&rooms_mutex);
2015
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2016
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2017
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2018
                                goto error;
2019
                        }
2020
                        janus_mutex_unlock(&rooms_mutex);
2021
                        json_t *display = json_object_get(root, "display");
2022
                        if(display && !json_is_string(display)) {
2023
                                JANUS_LOG(LOG_ERR, "Invalid element (display should be a string)\n");
2024
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2025
                                g_snprintf(error_cause, 512, "Invalid element (display should be a string)");
2026
                                goto error;
2027
                        }
2028
                        const char *display_text = display ? json_string_value(display) : NULL;
2029
                        json_t *muted = json_object_get(root, "muted");
2030
                        if(muted && !json_is_boolean(muted)) {
2031
                                JANUS_LOG(LOG_ERR, "Invalid element (muted should be a boolean)\n");
2032
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2033
                                g_snprintf(error_cause, 512, "Invalid element (muted should be a boolean)");
2034
                                goto error;
2035
                        }
2036
                        json_t *quality = json_object_get(root, "quality");
2037
                        if(quality && (!json_is_integer(quality) || json_integer_value(quality) < 0)) {
2038
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer)\n");
2039
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2040
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer)");
2041
                                goto error;
2042
                        }
2043
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
2044
                        if(complexity < 1 || complexity > 10) {
2045
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2046
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2047
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2048
                                goto error;
2049
                        }
2050
                        guint64 user_id = 0;
2051
                        json_t *id = json_object_get(root, "id");
2052
                        if(id) {
2053
                                if(!json_is_integer(id) || json_integer_value(id) < 0) {
2054
                                        JANUS_LOG(LOG_ERR, "Invalid element (id should be a positive integer)\n");
2055
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2056
                                        g_snprintf(error_cause, 512, "Invalid element (id should be a positive integer)");
2057
                                        goto error;
2058
                                }
2059
                                user_id = json_integer_value(id);
2060
                                if(g_hash_table_lookup(audiobridge->participants, GUINT_TO_POINTER(user_id)) != NULL) {
2061
                                        /* User ID already taken */
2062
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
2063
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
2064
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
2065
                                        goto error;
2066
                                }
2067
                        }
2068
                        if(user_id == 0) {
2069
                                /* Generate a random ID */
2070
                                while(user_id == 0) {
2071
                                        user_id = g_random_int();
2072
                                        if(g_hash_table_lookup(audiobridge->participants, GUINT_TO_POINTER(user_id)) != NULL) {
2073
                                                /* User ID already taken, try another one */
2074
                                                user_id = 0;
2075
                                        }
2076
                                }
2077
                        }
2078
                        JANUS_LOG(LOG_VERB, "  -- Participant ID in new room %"SCNu64": %"SCNu64"\n", room_id, user_id);
2079
                        /* Is the sampling rate of the new room the same as the one in the old room, or should we update the decoder/encoder? */
2080
                        janus_audiobridge_room *old_audiobridge = participant->room;
2081
                        /* Leave the old room first... */
2082
                        janus_mutex_lock(&old_audiobridge->mutex);
2083
                        g_hash_table_remove(old_audiobridge->participants, GUINT_TO_POINTER(participant->user_id));
2084
                        janus_mutex_unlock(&old_audiobridge->mutex);
2085
                        if(old_audiobridge->sampling_rate != audiobridge->sampling_rate) {
2086
                                /* Create a new one that takes into account the sampling rate we want now */
2087
                                int error = 0;
2088
                                OpusEncoder *new_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
2089
                                if(error != OPUS_OK) {
2090
                                        if(new_encoder)
2091
                                                opus_encoder_destroy(new_encoder);
2092
                                        new_encoder = NULL;
2093
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2094
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2095
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2096
                                        /* Join the old room again... */
2097
                                        janus_mutex_lock(&old_audiobridge->mutex);
2098
                                        g_hash_table_insert(audiobridge->participants, GUINT_TO_POINTER(participant->user_id), participant);
2099
                                        janus_mutex_unlock(&old_audiobridge->mutex);
2100
                                        goto error;
2101
                                }
2102
                                if(audiobridge->sampling_rate == 8000) {
2103
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
2104
                                } else if(audiobridge->sampling_rate == 12000) {
2105
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
2106
                                } else if(audiobridge->sampling_rate == 16000) {
2107
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2108
                                } else if(audiobridge->sampling_rate == 24000) {
2109
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
2110
                                } else if(audiobridge->sampling_rate == 48000) {
2111
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
2112
                                } else {
2113
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
2114
                                        audiobridge->sampling_rate = 16000;
2115
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2116
                                }
2117
                                /* FIXME This settings should be configurable */
2118
                                opus_encoder_ctl(new_encoder, OPUS_SET_INBAND_FEC(USE_FEC));
2119
                                opus_encoder_ctl(new_encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2120
                                /* Opus decoder */
2121
                                error = 0;
2122
                                OpusDecoder *new_decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
2123
                                if(error != OPUS_OK) {
2124
                                        if(new_encoder)
2125
                                                opus_encoder_destroy(new_encoder);
2126
                                        new_encoder = NULL;
2127
                                        if(new_decoder)
2128
                                                opus_decoder_destroy(new_decoder);
2129
                                        new_decoder = NULL;
2130
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2131
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2132
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2133
                                        /* Join the old room again... */
2134
                                        janus_mutex_lock(&old_audiobridge->mutex);
2135
                                        g_hash_table_insert(audiobridge->participants, GUINT_TO_POINTER(participant->user_id), participant);
2136
                                        janus_mutex_unlock(&old_audiobridge->mutex);
2137
                                        goto error;
2138
                                }
2139
                                participant->reset = FALSE;
2140
                                /* Destroy the previous encoder/decoder and update the references */
2141
                                if(participant->encoder)
2142
                                        opus_encoder_destroy(participant->encoder);
2143
                                participant->encoder = new_encoder;
2144
                                if(participant->decoder)
2145
                                        opus_decoder_destroy(participant->decoder);
2146
                                participant->decoder = new_decoder;
2147
                        }
2148
                        /* Everything looks fine, start by telling the folks in the old room this participant is going away */
2149
                        janus_mutex_lock(&old_audiobridge->mutex);
2150
                        event = json_object();
2151
                        json_object_set_new(event, "audiobridge", json_string("event"));
2152
                        json_object_set_new(event, "room", json_integer(old_audiobridge->room_id));
2153
                        json_object_set_new(event, "leaving", json_integer(participant->user_id));
2154
                        char *leaving_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2155
                        GHashTableIter iter;
2156
                        gpointer value;
2157
                        g_hash_table_iter_init(&iter, old_audiobridge->participants);
2158
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2159
                                janus_audiobridge_participant *p = value;
2160
                                if(p == participant) {
2161
                                        continue;        /* Skip the new participant itself */
2162
                                }
2163
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2164
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, leaving_text, NULL, NULL);
2165
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2166
                        }
2167
                        g_free(leaving_text);
2168
                        janus_mutex_unlock(&old_audiobridge->mutex);
2169
                        /* Done, join the new one */
2170
                        janus_mutex_lock(&audiobridge->mutex);
2171
                        participant->user_id = user_id;
2172
                        if(display_text) {
2173
                                g_free(participant->display);
2174
                                participant->display = display_text ? g_strdup(display_text) : NULL;
2175
                        }
2176
                        participant->room = audiobridge;
2177
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* When switching to a new room, you're unmuted by default */
2178
                        if(quality) {
2179
                                participant->opus_complexity = complexity;
2180
                                if(participant->encoder)
2181
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2182
                        }
2183
                        g_hash_table_insert(audiobridge->participants, GUINT_TO_POINTER(user_id), participant);
2184
                        /* Notify the other participants */
2185
                        json_t *newuser = json_object();
2186
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
2187
                        json_object_set_new(newuser, "room", json_integer(audiobridge->room_id));
2188
                        json_t *newuserlist = json_array();
2189
                        json_t *pl = json_object();
2190
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2191
                        if(participant->display)
2192
                                json_object_set_new(pl, "display", json_string(participant->display));
2193
                        json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
2194
                        json_array_append_new(newuserlist, pl);
2195
                        json_object_set_new(newuser, "participants", newuserlist);
2196
                        char *newuser_text = json_dumps(newuser, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2197
                        json_decref(newuser);
2198
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2199
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2200
                                janus_audiobridge_participant *p = value;
2201
                                if(p == participant) {
2202
                                        continue;
2203
                                }
2204
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2205
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser_text, NULL, NULL);
2206
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2207
                        }
2208
                        g_free(newuser_text);
2209
                        /* Return a list of all available participants for the new participant now */
2210
                        json_t *list = json_array();
2211
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2212
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2213
                                janus_audiobridge_participant *p = value;
2214
                                if(p == participant) {
2215
                                        continue;
2216
                                }
2217
                                json_t *pl = json_object();
2218
                                json_object_set_new(pl, "id", json_integer(p->user_id));
2219
                                if(p->display)
2220
                                        json_object_set_new(pl, "display", json_string(p->display));
2221
                                json_object_set_new(pl, "muted", json_string(p->muted ? "true" : "false"));
2222
                                json_array_append_new(list, pl);
2223
                        }
2224
                        event = json_object();
2225
                        json_object_set_new(event, "audiobridge", json_string("roomchanged"));
2226
                        json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2227
                        json_object_set_new(event, "id", json_integer(user_id));
2228
                        json_object_set_new(event, "participants", list);
2229
                        janus_mutex_unlock(&audiobridge->mutex);
2230
                } else if(!strcasecmp(request_text, "leave")) {
2231
                        /* This participant is leaving */
2232
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2233
                        if(participant == NULL || participant->room == NULL) {
2234
                                JANUS_LOG(LOG_ERR, "Can't leave (not in a room)\n");
2235
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2236
                                g_snprintf(error_cause, 512, "Can't leave (not in a room)");
2237
                                goto error;
2238
                        }
2239
                        /* Tell everybody */
2240
                        janus_audiobridge_room *audiobridge = participant->room;
2241
                        janus_mutex_lock(&audiobridge->mutex);
2242
                        event = json_object();
2243
                        json_object_set_new(event, "audiobridge", json_string("event"));
2244
                        json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2245
                        json_object_set_new(event, "leaving", json_integer(participant->user_id));
2246
                        char *leaving_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2247
                        GHashTableIter iter;
2248
                        gpointer value;
2249
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2250
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2251
                                janus_audiobridge_participant *p = value;
2252
                                if(p == participant) {
2253
                                        continue;        /* Skip the new participant itself */
2254
                                }
2255
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2256
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, leaving_text, NULL, NULL);
2257
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2258
                        }
2259
                        g_free(leaving_text);
2260
                        /* Actually leave the room... */
2261
                        g_hash_table_remove(audiobridge->participants, GUINT_TO_POINTER(participant->user_id));
2262
                        participant->room = NULL;
2263
                        /* Get rid of queued packets */
2264
                        janus_mutex_lock(&participant->qmutex);
2265
                        participant->active = FALSE;
2266
                        while(!g_queue_is_empty(participant->inbuf)) {
2267
                                janus_audiobridge_rtp_relay_packet *pkt = g_queue_pop_head(participant->inbuf);
2268
                                if(pkt == NULL)
2269
                                        continue;
2270
                                if(pkt->data)
2271
                                        g_free(pkt->data);
2272
                                pkt->data = NULL;
2273
                                g_free(pkt);
2274
                                pkt = NULL;
2275
                        }
2276
                        janus_mutex_unlock(&participant->qmutex);
2277
                        /* Done */
2278
                        janus_mutex_unlock(&audiobridge->mutex);
2279
                } else {
2280
                        JANUS_LOG(LOG_ERR, "Unknown request '%s'\n", request_text);
2281
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
2282
                        g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
2283
                        goto error;
2284
                }
2285

    
2286
                /* Prepare JSON event */
2287
                JANUS_LOG(LOG_VERB, "Preparing JSON event as a reply\n");
2288
                char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2289
                json_decref(event);
2290
                /* Any SDP to handle? */
2291
                if(!msg->sdp) {
2292
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, NULL, NULL);
2293
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2294
                } else {
2295
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg->sdp_type, msg->sdp);
2296
                        const char *type = NULL;
2297
                        if(!strcasecmp(msg->sdp_type, "offer"))
2298
                                type = "answer";
2299
                        if(!strcasecmp(msg->sdp_type, "answer"))
2300
                                type = "offer";
2301
                        /* Fill the SDP template and use that as our answer */
2302
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2303
                        char sdp[1024];
2304
                        /* What is the Opus payload type? */
2305
                        participant->opus_pt = 0;
2306
                        char *fmtp = strstr(msg->sdp, "opus/48000");
2307
                        if(fmtp != NULL) {
2308
                                fmtp -= 5;
2309
                                fmtp = strstr(fmtp, ":");
2310
                                if(fmtp)
2311
                                        fmtp++;
2312
                                participant->opus_pt = atoi(fmtp);
2313
                        }
2314
                        JANUS_LOG(LOG_VERB, "Opus payload type is %d\n", participant->opus_pt);
2315
                        g_snprintf(sdp, 1024, sdp_template,
2316
                                janus_get_monotonic_time(),                /* We need current time here */
2317
                                janus_get_monotonic_time(),                /* We need current time here */
2318
                                participant->room->room_name,        /* Audio bridge name */
2319
                                participant->opus_pt,                        /* Opus payload type */
2320
                                participant->opus_pt,                        /* Opus payload type */
2321
                                participant->opus_pt,                         /* Opus payload type and room sampling rate */
2322
                                participant->room->sampling_rate);
2323
                        /* Did the peer negotiate video? */
2324
                        if(strstr(msg->sdp, "m=video") != NULL) {
2325
                                /* If so, reject it */
2326
                                g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", 1024);                                
2327
                        }
2328
                        /* How long will the gateway take to push the event? */
2329
                        gint64 start = janus_get_monotonic_time();
2330
                        int res = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, type, sdp);
2331
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (took %"SCNu64" us)\n", res, janus_get_monotonic_time()-start);
2332
                        if(res != JANUS_OK) {
2333
                                /* TODO Failed to negotiate? We should remove this participant */
2334
                        } else {
2335
                                /* Notify all other participants that there's a new boy in town */
2336
                                janus_audiobridge_room *audiobridge = participant->room;
2337
                                janus_mutex_lock(&audiobridge->mutex);
2338
                                json_t *list = json_array();
2339
                                json_t *pl = json_object();
2340
                                json_object_set_new(pl, "id", json_integer(participant->user_id));
2341
                                if(participant->display)
2342
                                        json_object_set_new(pl, "display", json_string(participant->display));
2343
                                json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
2344
                                json_array_append_new(list, pl);
2345
                                json_t *pub = json_object();
2346
                                json_object_set_new(pub, "audiobridge", json_string("event"));
2347
                                json_object_set_new(pub, "room", json_integer(participant->room->room_id));
2348
                                json_object_set_new(pub, "participants", list);
2349
                                char *pub_text = json_dumps(pub, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2350
                                json_decref(pub);
2351
                                GHashTableIter iter;
2352
                                gpointer value;
2353
                                g_hash_table_iter_init(&iter, audiobridge->participants);
2354
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2355
                                        janus_audiobridge_participant *p = value;
2356
                                        if(p == participant) {
2357
                                                continue;        /* Skip the new participant itself */
2358
                                        }
2359
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2360
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub_text, NULL, NULL);
2361
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2362
                                }
2363
                                g_free(pub_text);
2364
                                participant->active = TRUE;
2365
                                janus_mutex_unlock(&audiobridge->mutex);
2366
                        }
2367
                }
2368
                if(event_text)
2369
                        g_free(event_text);
2370
                event_text = NULL;
2371
                if(msg)
2372
                        janus_audiobridge_message_free(msg);
2373
                msg = NULL;
2374

    
2375
                continue;
2376
                
2377
error:
2378
                {
2379
                        /* Prepare JSON error event */
2380
                        json_t *event = json_object();
2381
                        json_object_set_new(event, "audiobridge", json_string("event"));
2382
                        json_object_set_new(event, "error_code", json_integer(error_code));
2383
                        json_object_set_new(event, "error", json_string(error_cause));
2384
                        char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2385
                        json_decref(event);
2386
                        JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
2387
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, NULL, NULL);
2388
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2389
                        g_free(event_text);
2390
                        janus_audiobridge_message_free(msg);
2391
                }
2392
        }
2393
        g_free(error_cause);
2394
        JANUS_LOG(LOG_VERB, "Leaving AudioBridge handler thread\n");
2395
        return NULL;
2396
}
2397

    
2398
/* Thread to mix the contributions from all participants */
2399
static void *janus_audiobridge_mixer_thread(void *data) {
2400
        JANUS_LOG(LOG_VERB, "Audio bridge thread starting...\n");
2401
        janus_audiobridge_room *audiobridge = (janus_audiobridge_room *)data;
2402
        if(!audiobridge) {
2403
                JANUS_LOG(LOG_ERR, "Invalid room!\n");
2404
                return NULL;
2405
        }
2406
        JANUS_LOG(LOG_VERB, "Thread is for mixing room %"SCNu64" (%s) at rate %"SCNu32"...\n", audiobridge->room_id, audiobridge->room_name, audiobridge->sampling_rate);
2407

    
2408
        /* Do we need to record the mix? */
2409
        if(audiobridge->record) {
2410
                char filename[255];
2411
                if(audiobridge->record_file)
2412
                        g_snprintf(filename, 255, "%s", audiobridge->record_file);
2413
                else
2414
                        g_snprintf(filename, 255, "/tmp/janus-audioroom-%"SCNu64".wav", audiobridge->room_id);
2415
                audiobridge->recording = fopen(filename, "wb");
2416
                if(audiobridge->recording == NULL) {
2417
                        JANUS_LOG(LOG_WARN, "Recording requested, but could NOT open file %s for writing...\n", filename);
2418
                } else {
2419
                        JANUS_LOG(LOG_VERB, "Recording requested, opened file %s for writing\n", filename);
2420
                        /* Write WAV header */
2421
                        wav_header header = {
2422
                                {'R', 'I', 'F', 'F'},
2423
                                0,
2424
                                {'W', 'A', 'V', 'E'},
2425
                                {'f', 'm', 't', ' '},
2426
                                16,
2427
                                1,
2428
                                1,
2429
                                audiobridge->sampling_rate,
2430
                                audiobridge->sampling_rate * 2,
2431
                                2,
2432
                                16,
2433
                                {'d', 'a', 't', 'a'},
2434
                                0
2435
                        };
2436
                        if(fwrite(&header, 1, sizeof(header), audiobridge->recording) != sizeof(header)) {
2437
                                JANUS_LOG(LOG_ERR, "Error writing WAV header...\n");
2438
                        }
2439
                }
2440
        }
2441

    
2442
        /* Buffer (we allocate assuming 48kHz, although we'll likely use less than that) */
2443
        int samples = audiobridge->sampling_rate/50;
2444
        opus_int32 buffer[960], sumBuffer[960];
2445
        opus_int16 outBuffer[960], *curBuffer = NULL;
2446
        memset(buffer, 0, 960*4);
2447
        memset(sumBuffer, 0, 960*4);
2448
        memset(outBuffer, 0, 960*2);
2449

    
2450
        /* Timer */
2451
        struct timeval now, before;
2452
        gettimeofday(&before, NULL);
2453
        now.tv_sec = before.tv_sec;
2454
        now.tv_usec = before.tv_usec;
2455
        time_t passed, d_s, d_us;
2456

    
2457
        /* RTP */
2458
        gint16 seq = 0;
2459
        gint32 ts = 0;
2460

    
2461
        /* Loop */
2462
        int i=0;
2463
        int count = 0, prev_count = 0;
2464
        while(!g_atomic_int_get(&stopping) && audiobridge->destroyed == 0) {        /* FIXME We need a per-room watchdog as well */
2465
                /* See if it's time to prepare a frame */
2466
                gettimeofday(&now, NULL);
2467
                d_s = now.tv_sec - before.tv_sec;
2468
                d_us = now.tv_usec - before.tv_usec;
2469
                if(d_us < 0) {
2470
                        d_us += 1000000;
2471
                        --d_s;
2472
                }
2473
                passed = d_s*1000000 + d_us;
2474
                if(passed < 15000) {        /* Let's wait about 15ms at max */
2475
                        usleep(1000);
2476
                        continue;
2477
                }
2478
                /* Update the reference time */
2479
                before.tv_usec += 20000;
2480
                if(before.tv_usec > 1000000) {
2481
                        before.tv_sec++;
2482
                        before.tv_usec -= 1000000;
2483
                }
2484
                /* Do we need to mix at all? */
2485
                janus_mutex_lock_nodebug(&audiobridge->mutex);
2486
                count = g_hash_table_size(audiobridge->participants);
2487
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
2488
                if(count == 0) {
2489
                        /* No participant, do nothing */
2490
                        if(prev_count > 0) {
2491
                                JANUS_LOG(LOG_VERB, "Last user just left room %"SCNu64", going idle...\n", audiobridge->room_id);
2492
                                prev_count = 0;
2493
                        }
2494
                        continue;
2495
                }
2496
                if(prev_count == 0) {
2497
                        JANUS_LOG(LOG_VERB, "First user just joined room %"SCNu64", waking it up...\n", audiobridge->room_id);
2498
                }
2499
                prev_count = count;
2500
                /* Update RTP header information */
2501
                seq++;
2502
                ts += 960;
2503
                /* Mix all contributions */
2504
                janus_mutex_lock_nodebug(&audiobridge->mutex);
2505
                GList *participants_list = g_hash_table_get_values(audiobridge->participants);
2506
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
2507
                for(i=0; i<samples; i++)
2508
                        buffer[i] = 0;
2509
                GList *ps = participants_list;
2510
                while(ps) {
2511
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
2512
                        janus_mutex_lock(&p->qmutex);
2513
                        if(!p->active || p->muted || g_queue_is_empty(p->inbuf)) {
2514
                                janus_mutex_unlock(&p->qmutex);
2515
                                ps = ps->next;
2516
                                continue;
2517
                        }
2518
                        janus_audiobridge_rtp_relay_packet *pkt = g_queue_peek_head(p->inbuf);
2519
                        janus_mutex_unlock(&p->qmutex);
2520
                        curBuffer = (opus_int16 *)pkt->data;
2521
                        for(i=0; i<samples; i++)
2522
                                buffer[i] += curBuffer[i];
2523
                        ps = ps->next;
2524
                }
2525
                /* Are we recording the mix? (only do it if there's someone in, though...) */
2526
                if(audiobridge->recording != NULL && g_list_length(participants_list) > 0) {
2527
                        for(i=0; i<samples; i++) {
2528
                                /* FIXME Smoothen/Normalize instead of truncating? */
2529
                                outBuffer[i] = buffer[i];
2530
                        }
2531
                        fwrite(outBuffer, sizeof(opus_int16), samples, audiobridge->recording);
2532
                }
2533
                /* Send proper packet to each participant (remove own contribution) */
2534
                ps = participants_list;
2535
                while(ps) {
2536
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
2537
                        janus_audiobridge_rtp_relay_packet *pkt = NULL;
2538
                        janus_mutex_lock(&p->qmutex);
2539
                        if(p->active && !p->muted && !g_queue_is_empty(p->inbuf))
2540
                                pkt = g_queue_pop_head(p->inbuf);
2541
                        janus_mutex_unlock(&p->qmutex);
2542
                        curBuffer = (opus_int16 *)(pkt ? pkt->data : NULL);
2543
                        for(i=0; i<samples; i++)
2544
                                sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]) : 0);
2545
                        for(i=0; i<samples; i++)
2546
                                /* FIXME Smoothen/Normalize instead of truncating? */
2547
                                outBuffer[i] = sumBuffer[i];
2548
                        /* Enqueue this mixed frame for encoding in the participant thread */
2549
                        janus_audiobridge_rtp_relay_packet *mixedpkt = calloc(1, sizeof(janus_audiobridge_rtp_relay_packet));
2550
                        if(mixedpkt != NULL) {
2551
                                mixedpkt->data = calloc(samples*2, sizeof(char));
2552
                                if(mixedpkt->data == NULL) {
2553
                                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2554
                                        g_free(mixedpkt);
2555
                                } else {
2556
                                        memcpy(mixedpkt->data, outBuffer, samples*2);
2557
                                        mixedpkt->length = samples;        /* We set the number of samples here, not the data length */
2558
                                        mixedpkt->timestamp = ts;
2559
                                        mixedpkt->seq_number = seq;
2560
                                        mixedpkt->ssrc = audiobridge->room_id;
2561
                                        g_async_queue_push(p->outbuf, mixedpkt);
2562
                                }
2563
                        }
2564
                        if(pkt) {
2565
                                if(pkt->data)
2566
                                        g_free(pkt->data);
2567
                                pkt->data = NULL;
2568
                                g_free(pkt);
2569
                                pkt = NULL;
2570
                        }
2571
                        ps = ps->next;
2572
                }
2573
                g_list_free(participants_list);
2574
        }
2575
        if(audiobridge->recording)
2576
                fclose(audiobridge->recording);
2577
        JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %"SCNu64" (%s)...\n", audiobridge->room_id, audiobridge->room_name);
2578

    
2579
        /* Free resources */
2580
        g_free(audiobridge->room_name);
2581
        g_free(audiobridge->room_secret);
2582
        g_free(audiobridge->record_file);
2583
        g_hash_table_destroy(audiobridge->participants);
2584
        g_free(audiobridge);
2585

    
2586
        return NULL;
2587
}
2588

    
2589
/* Thread to encode a mixed frame and send it to a specific participant */
2590
static void *janus_audiobridge_participant_thread(void *data) {
2591
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread starting...\n");
2592
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)data;
2593
        if(!participant) {
2594
                JANUS_LOG(LOG_ERR, "Invalid participant!\n");
2595
                g_thread_unref(g_thread_self());
2596
                return NULL;
2597
        }
2598
        JANUS_LOG(LOG_VERB, "Thread is for participant %"SCNu64" (%s)\n", participant->user_id, participant->display ? participant->display : "??");
2599
        janus_audiobridge_session *session = participant->session;
2600

    
2601
        /* Output buffer */
2602
        janus_audiobridge_rtp_relay_packet *outpkt = calloc(1, sizeof(janus_audiobridge_rtp_relay_packet));
2603
        if(outpkt == NULL) {
2604
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2605
                g_thread_unref(g_thread_self());
2606
                return NULL;
2607
        }
2608
        outpkt->data = (rtp_header *)calloc(1500, sizeof(unsigned char));
2609
        if(outpkt->data == NULL) {
2610
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2611
                g_free(outpkt);
2612
                g_thread_unref(g_thread_self());
2613
                return NULL;
2614
        }
2615
        outpkt->ssrc = 0;
2616
        outpkt->timestamp = 0;
2617
        outpkt->seq_number = 0;
2618
        unsigned char *payload = (unsigned char *)outpkt->data;
2619
        memset(payload, 0, 1500);
2620

    
2621
        janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
2622

    
2623
        /* Start working: check the outgoing queue for packets, then encode and send them */
2624
        while(!g_atomic_int_get(&stopping) && session->destroyed == 0) {
2625
                if(!participant->active || !participant->encoder) {
2626
                        /* Wait until the participant is in a room */
2627
                        g_usleep(10000);
2628
                        continue;
2629
                }
2630
                if(g_async_queue_length(participant->outbuf) == 0) {
2631
                        /* Nothing to do */
2632
                        g_usleep(5000);
2633
                        continue;
2634
                }
2635
                mixedpkt = g_async_queue_pop(participant->outbuf);
2636
                if(mixedpkt != NULL && session->destroyed == 0) {
2637
                        /* Encode raw frame to Opus */
2638
                        if(participant->active && participant->encoder) {
2639
                                participant->working = TRUE;
2640
                                opus_int16 *outBuffer = (opus_int16 *)mixedpkt->data;
2641
                                outpkt->length = opus_encode(participant->encoder, outBuffer, mixedpkt->length, payload+12, BUFFER_SAMPLES-12);
2642
                                participant->working = FALSE;
2643
                                if(outpkt->length < 0) {
2644
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", outpkt->length, opus_strerror(outpkt->length));
2645
                                } else {
2646
                                        outpkt->length += 12;        /* Take the RTP header into consideration */
2647
                                        /* Update RTP header */
2648
                                        outpkt->data->version = 2;
2649
                                        outpkt->data->markerbit = 0;        /* FIXME Should be 1 for the first packet */
2650
                                        outpkt->data->seq_number = htons(mixedpkt->seq_number);
2651
                                        outpkt->data->timestamp = htonl(mixedpkt->timestamp);
2652
                                        outpkt->data->ssrc = htonl(mixedpkt->ssrc);        /* The gateway will fix this anyway */
2653
                                        /* Backup the actual timestamp and sequence number set by the audiobridge, in case a room is changed */
2654
                                        outpkt->ssrc = mixedpkt->ssrc;
2655
                                        outpkt->timestamp = mixedpkt->timestamp;
2656
                                        outpkt->seq_number = mixedpkt->seq_number;
2657
                                        janus_audiobridge_relay_rtp_packet(participant->session, outpkt);
2658
                                }
2659
                        }
2660
                        if(mixedpkt) {
2661
                                if(mixedpkt->data)
2662
                                        g_free(mixedpkt->data);
2663
                                mixedpkt->data = NULL;
2664
                                g_free(mixedpkt);
2665
                                mixedpkt = NULL;
2666
                        }
2667
                }
2668
        }
2669
        /* We're done, get rid of the resources */
2670
        if(outpkt != NULL) {
2671
                if(outpkt->data != NULL) {
2672
                        free(outpkt->data);
2673
                        outpkt->data = NULL;
2674
                }
2675
                free(outpkt);
2676
                outpkt = NULL;
2677
        }
2678
        /* Empty the outgoing queue if there was something still in */
2679
        while(g_async_queue_length(participant->outbuf) > 0) {
2680
                janus_audiobridge_rtp_relay_packet *pkt = g_async_queue_pop(participant->outbuf);
2681
                if(pkt == NULL)
2682
                        continue;
2683
                if(pkt->data)
2684
                        g_free(pkt->data);
2685
                pkt->data = NULL;
2686
                g_free(pkt);
2687
                pkt = NULL;
2688
        }
2689
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread leaving...\n");
2690
        return NULL;
2691
}
2692

    
2693
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data) {
2694
        janus_audiobridge_rtp_relay_packet *packet = (janus_audiobridge_rtp_relay_packet *)user_data;
2695
        if(!packet || !packet->data || packet->length < 1) {
2696
                JANUS_LOG(LOG_ERR, "Invalid packet...\n");
2697
                return;
2698
        }
2699
        janus_audiobridge_session *session = (janus_audiobridge_session *)data;
2700
        if(!session || !session->handle) {
2701
                // JANUS_LOG(LOG_ERR, "Invalid session...\n");
2702
                return;
2703
        }
2704
        if(!session->started) {
2705
                // JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
2706
                return;
2707
        }
2708
        janus_audiobridge_participant *participant = session->participant;
2709
        /* Set the payload type */
2710
        packet->data->type = participant->opus_pt;
2711
        /* Fix sequence number and timestamp (room switching may be involved) */
2712
        if(ntohl(packet->data->ssrc) != participant->context.a_last_ssrc) {
2713
                participant->context.a_last_ssrc = ntohl(packet->data->ssrc);
2714
                participant->context.a_base_ts_prev = participant->context.a_last_ts;
2715
                participant->context.a_base_ts = packet->timestamp;
2716
                participant->context.a_base_seq_prev = participant->context.a_last_seq;
2717
                participant->context.a_base_seq = packet->seq_number;
2718
        }
2719
        /* Compute a coherent timestamp and sequence number */
2720
        participant->context.a_last_ts = (packet->timestamp-participant->context.a_base_ts)
2721
                + participant->context.a_base_ts_prev+960;        /* FIXME When switching, we assume Opus and so a 960 ts step */
2722
        participant->context.a_last_seq = (packet->seq_number-participant->context.a_base_seq)+participant->context.a_base_seq_prev+1;
2723
        /* Update the timestamp and sequence number in the RTP packet, and send it */
2724
        packet->data->timestamp = htonl(participant->context.a_last_ts);
2725
        packet->data->seq_number = htons(participant->context.a_last_seq);
2726
        if(gateway != NULL)
2727
                gateway->relay_rtp(session->handle, 0, (char *)packet->data, packet->length);
2728
        /* Restore the timestamp and sequence number to what the publisher set them to */
2729
        packet->data->timestamp = htonl(packet->timestamp);
2730
        packet->data->seq_number = htons(packet->seq_number);
2731
}