Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_audiobridge.c @ 3a3cc054

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 volatile 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
        volatile gint hangingup;
504
        gint64 destroyed;        /* Time at which this session was marked as destroyed */
505
} janus_audiobridge_session;
506
static GHashTable *sessions;
507
static GList *old_sessions;
508
static janus_mutex sessions_mutex;
509

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

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

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

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

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

    
577

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

    
584

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

    
600

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

    
640

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

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

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

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

    
766
        g_atomic_int_set(&initialized, 1);
767

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

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

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

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

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

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

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

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

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

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

    
864
        return;
865
}
866

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

    
889
        return;
890
}
891

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

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

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

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

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

    
1382
                g_async_queue_push(messages, msg);
1383

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

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

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

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

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

    
1434
}
1435

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

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

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

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

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

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

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

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

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

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

    
2455
        /* Timer */
2456
        struct timeval now, before;
2457
        gettimeofday(&before, NULL);
2458
        now.tv_sec = before.tv_sec;
2459
        now.tv_usec = before.tv_usec;
2460
        time_t passed, d_s, d_us;
2461

    
2462
        /* RTP */
2463
        gint16 seq = 0;
2464
        gint32 ts = 0;
2465

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

    
2584
        /* Free resources */
2585
        g_free(audiobridge->room_name);
2586
        g_free(audiobridge->room_secret);
2587
        g_free(audiobridge->record_file);
2588
        g_hash_table_destroy(audiobridge->participants);
2589
        g_free(audiobridge);
2590

    
2591
        return NULL;
2592
}
2593

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

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

    
2626
        janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
2627

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

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