Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_audiobridge.c @ b8237291

History | View | Annotate | Download (113 KB)

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

    
369
#include "plugin.h"
370

    
371
#include <jansson.h>
372
#include <opus/opus.h>
373
#include <sys/time.h>
374

    
375
#include "../debug.h"
376
#include "../apierror.h"
377
#include "../config.h"
378
#include "../mutex.h"
379
#include "../rtp.h"
380
#include "../rtcp.h"
381
#include "../utils.h"
382

    
383

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

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

    
412
/* Plugin setup */
413
static janus_plugin janus_audiobridge_plugin =
414
        JANUS_PLUGIN_INIT (
415
                .init = janus_audiobridge_init,
416
                .destroy = janus_audiobridge_destroy,
417

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

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

    
442

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

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

    
462
void janus_audiobridge_message_free(janus_audiobridge_message *msg);
463
void janus_audiobridge_message_free(janus_audiobridge_message *msg) {
464
        if(!msg)
465
                return;
466

    
467
        msg->handle = NULL;
468

    
469
        g_free(msg->transaction);
470
        msg->transaction = NULL;
471
        if(msg->message)
472
                json_decref(msg->message);
473
        msg->message = NULL;
474
        g_free(msg->sdp_type);
475
        msg->sdp_type = NULL;
476
        g_free(msg->sdp);
477
        msg->sdp = NULL;
478

    
479
        g_free(msg);
480
}
481

    
482

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

    
502
typedef struct janus_audiobridge_session {
503
        janus_plugin_session *handle;
504
        gpointer participant;
505
        gboolean started;
506
        gboolean stopping;
507
        volatile gint hangingup;
508
        gint64 destroyed;        /* Time at which this session was marked as destroyed */
509
} janus_audiobridge_session;
510
static GHashTable *sessions;
511
static GList *old_sessions;
512
static janus_mutex sessions_mutex;
513

    
514
typedef struct janus_audiobridge_rtp_context {
515
        /* Needed to fix seq and ts in case of publisher switching */
516
        uint32_t a_last_ssrc, a_last_ts, a_base_ts, a_base_ts_prev;
517
        uint16_t a_last_seq, a_base_seq, a_base_seq_prev;
518
} janus_audiobridge_rtp_context;
519

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

    
544
/* Packets we get from gstreamer and relay */
545
typedef struct janus_audiobridge_rtp_relay_packet {
546
        rtp_header *data;
547
        gint length;
548
        uint32_t ssrc;
549
        uint32_t timestamp;
550
        uint16_t seq_number;
551
} janus_audiobridge_rtp_relay_packet;
552

    
553
/* Helper to sort incoming RTP packets by sequence numbers */
554
static gint janus_audiobridge_rtp_sort(gconstpointer a, gconstpointer b) {
555
        janus_audiobridge_rtp_relay_packet *pkt1 = (janus_audiobridge_rtp_relay_packet *)a;
556
        janus_audiobridge_rtp_relay_packet *pkt2 = (janus_audiobridge_rtp_relay_packet *)b;
557
        if(pkt1->seq_number < 100 && pkt2->seq_number > 65000) {
558
                /* Sequence number was probably reset, pkt2 is older */
559
                return 1;
560
        } else if(pkt2->seq_number < 100 && pkt1->seq_number > 65000) {
561
                /* Sequence number was probably reset, pkt1 is older */
562
                return -1;
563
        }
564
        /* Simply compare timestamps */
565
        if(pkt1->seq_number < pkt2->seq_number)
566
                return -1;
567
        else if(pkt1->seq_number > pkt2->seq_number)
568
                return 1;
569
        return 0;
570
}
571

    
572
/* SDP offer/answer template */
573
#define sdp_template \
574
                "v=0\r\n" \
575
                "o=- %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n"        /* We need current time here */ \
576
                "s=%s\r\n"                                                        /* Audio bridge name */ \
577
                "t=0 0\r\n" \
578
                "m=audio 1 RTP/SAVPF %d\r\n"                /* Opus payload type */ \
579
                "c=IN IP4 1.1.1.1\r\n" \
580
                "a=rtpmap:%d opus/48000/2\r\n"                /* Opus payload type */ \
581
                "a=fmtp:%d maxplaybackrate=%"SCNu32"; stereo=0; sprop-stereo=0; useinbandfec=0\r\n" \
582
                                                                                        /* Opus payload type and room sampling rate */
583

    
584
/* Helper struct to generate and parse WAVE headers */
585
typedef struct wav_header {
586
        char riff[4];
587
        uint32_t len;
588
        char wave[4];
589
        char fmt[4];
590
        uint32_t formatsize;
591
        uint16_t format;
592
        uint16_t channels;
593
        uint32_t samplerate;
594
        uint32_t avgbyterate;
595
        uint16_t samplebytes;
596
        uint16_t channelbits;
597
        char data[4];
598
        uint32_t blocksize;
599
} wav_header;
600

    
601

    
602
/* Mixer settings */
603
#define DEFAULT_PREBUFFERING        6
604

    
605

    
606
/* Opus settings */                
607
#define        BUFFER_SAMPLES        8000
608
#define        OPUS_SAMPLES        160
609
#define USE_FEC                        0
610
#define DEFAULT_COMPLEXITY        4
611

    
612

    
613
/* Error codes */
614
#define JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR        499
615
#define JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE                480
616
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON        481
617
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST        482
618
#define JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT        483
619
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT        484
620
#define JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM        485
621
#define JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS                486
622
#define JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED                487
623
#define JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR        488
624
#define JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED        489
625
#define JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS                490
626
#define JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED        491
627

    
628

    
629
/* AudioBridge watchdog/garbage collector (sort of) */
630
void *janus_audiobridge_watchdog(void *data);
631
void *janus_audiobridge_watchdog(void *data) {
632
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog started\n");
633
        gint64 now = 0;
634
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
635
                janus_mutex_lock(&sessions_mutex);
636
                /* Iterate on all the sessions */
637
                now = janus_get_monotonic_time();
638
                if(old_sessions != NULL) {
639
                        GList *sl = old_sessions;
640
                        JANUS_LOG(LOG_HUGE, "Checking %d old AudioBridge sessions...\n", g_list_length(old_sessions));
641
                        while(sl) {
642
                                janus_audiobridge_session *session = (janus_audiobridge_session *)sl->data;
643
                                if(!session) {
644
                                        sl = sl->next;
645
                                        continue;
646
                                }
647
                                if(now-session->destroyed >= 5*G_USEC_PER_SEC) {
648
                                        /* We're lazy and actually get rid of the stuff only after a few seconds */
649
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge session\n");
650
                                        GList *rm = sl->next;
651
                                        old_sessions = g_list_delete_link(old_sessions, sl);
652
                                        sl = rm;
653
                                        session->handle = NULL;
654
                                        g_free(session);
655
                                        session = NULL;
656
                                        continue;
657
                                }
658
                                sl = sl->next;
659
                        }
660
                }
661
                janus_mutex_unlock(&sessions_mutex);
662
                g_usleep(500000);
663
        }
664
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog stopped\n");
665
        return NULL;
666
}
667

    
668

    
669
/* Plugin implementation */
670
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) {
671
        if(g_atomic_int_get(&stopping)) {
672
                /* Still stopping from before */
673
                return -1;
674
        }
675
        if(callback == NULL || config_path == NULL) {
676
                /* Invalid arguments */
677
                return -1;
678
        }
679

    
680
        /* Read configuration */
681
        char filename[255];
682
        g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_AUDIOBRIDGE_PACKAGE);
683
        JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
684
        janus_config *config = janus_config_parse(filename);
685
        if(config != NULL)
686
                janus_config_print(config);
687
        
688
        rooms = g_hash_table_new(NULL, NULL);
689
        janus_mutex_init(&rooms_mutex);
690
        sessions = g_hash_table_new(NULL, NULL);
691
        janus_mutex_init(&sessions_mutex);
692
        messages = g_async_queue_new_full((GDestroyNotify) janus_audiobridge_message_free);
693
        /* This is the callback we'll need to invoke to contact the gateway */
694
        gateway = callback;
695

    
696
        /* Parse configuration to populate the rooms list */
697
        if(config != NULL) {
698
                janus_config_category *cat = janus_config_get_categories(config);
699
                while(cat != NULL) {
700
                        if(cat->name == NULL) {
701
                                cat = cat->next;
702
                                continue;
703
                        }
704
                        JANUS_LOG(LOG_VERB, "Adding audio room '%s'\n", cat->name);
705
                        janus_config_item *desc = janus_config_get_item(cat, "description");
706
                        janus_config_item *priv = janus_config_get_item(cat, "is_private");
707
                        janus_config_item *sampling = janus_config_get_item(cat, "sampling_rate");
708
                        janus_config_item *secret = janus_config_get_item(cat, "secret");
709
                        janus_config_item *pin = janus_config_get_item(cat, "pin");
710
                        janus_config_item *record = janus_config_get_item(cat, "record");
711
                        janus_config_item *recfile = janus_config_get_item(cat, "record_file");
712
                        if(sampling == NULL || sampling->value == NULL) {
713
                                JANUS_LOG(LOG_ERR, "Can't add the audio room, missing mandatory information...\n");
714
                                cat = cat->next;
715
                                continue;
716
                        }
717
                        /* Create the audio bridge room */
718
                        janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room));
719
                        if(audiobridge == NULL) {
720
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
721
                                cat = cat->next;
722
                                continue;
723
                        }
724
                        audiobridge->room_id = atoi(cat->name);
725
                        char *description = NULL;
726
                        if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0)
727
                                description = g_strdup(desc->value);
728
                        else
729
                                description = g_strdup(cat->name);
730
                        if(description == NULL) {
731
                                JANUS_LOG(LOG_FATAL, "Memory error!\n");
732
                                cat = cat->next;
733
                                continue;
734
                        }
735
                        audiobridge->room_name = description;
736
                        audiobridge->is_private = priv && priv->value && janus_is_true(priv->value);
737
                        audiobridge->sampling_rate = atoi(sampling->value);
738
                        switch(audiobridge->sampling_rate) {
739
                                case 8000:
740
                                case 12000:
741
                                case 16000:
742
                                case 24000:
743
                                case 48000:
744
                                        JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
745
                                        break;
746
                                default:
747
                                        JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
748
                                        cat = cat->next;
749
                                        continue;
750
                        }
751
                        if(secret != NULL && secret->value != NULL) {
752
                                audiobridge->room_secret = g_strdup(secret->value);
753
                        }
754
                        if(pin != NULL && pin->value != NULL) {
755
                                audiobridge->room_pin = g_strdup(pin->value);
756
                        }
757
                        audiobridge->record = FALSE;
758
                        if(record && record->value && janus_is_true(record->value))
759
                                audiobridge->record = TRUE;
760
                        if(recfile && recfile->value)
761
                                audiobridge->record_file = g_strdup(recfile->value);
762
                        audiobridge->recording = NULL;
763
                        audiobridge->destroy = 0;
764
                        audiobridge->participants = g_hash_table_new(NULL, NULL);
765
                        audiobridge->destroyed = 0;
766
                        janus_mutex_init(&audiobridge->mutex);
767
                        JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
768
                                audiobridge->room_id, audiobridge->room_name,
769
                                audiobridge->is_private ? "private" : "public",
770
                                audiobridge->room_secret ? audiobridge->room_secret : "no secret",
771
                                audiobridge->room_pin ? audiobridge->room_pin : "no pin");
772
                        /* We need a thread for the mix */
773
                        GError *error = NULL;
774
                        audiobridge->thread = g_thread_try_new("audiobridge mixer thread", &janus_audiobridge_mixer_thread, audiobridge, &error);
775
                        if(error != NULL) {
776
                                /* FIXME We should clear some resources... */
777
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
778
                        } else {
779
                                janus_mutex_lock(&rooms_mutex);
780
                                g_hash_table_insert(rooms, GUINT_TO_POINTER(audiobridge->room_id), audiobridge);
781
                                janus_mutex_unlock(&rooms_mutex);
782
                        }
783
                        cat = cat->next;
784
                }
785
                /* Done */
786
                janus_config_destroy(config);
787
                config = NULL;
788
        }
789

    
790
        /* Show available rooms */
791
        janus_mutex_lock(&rooms_mutex);
792
        GHashTableIter iter;
793
        gpointer value;
794
        g_hash_table_iter_init(&iter, rooms);
795
        while (g_hash_table_iter_next(&iter, NULL, &value)) {
796
                janus_audiobridge_room *ar = value;
797
                JANUS_LOG(LOG_VERB, "  ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n",
798
                        ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT");
799
        }
800
        janus_mutex_unlock(&rooms_mutex);
801

    
802
        g_atomic_int_set(&initialized, 1);
803

    
804
        GError *error = NULL;
805
        /* Start the sessions watchdog */
806
        watchdog = g_thread_try_new("abridge watchdog", &janus_audiobridge_watchdog, NULL, &error);
807
        if(error != NULL) {
808
                g_atomic_int_set(&initialized, 0);
809
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge watchdog thread...\n", error->code, error->message ? error->message : "??");
810
                return -1;
811
        }
812
        /* Launch the thread that will handle incoming messages */
813
        handler_thread = g_thread_try_new("janus audiobridge handler", janus_audiobridge_handler, NULL, &error);
814
        if(error != NULL) {
815
                g_atomic_int_set(&initialized, 0);
816
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", error->code, error->message ? error->message : "??");
817
                return -1;
818
        }
819
        JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_AUDIOBRIDGE_NAME);
820
        return 0;
821
}
822

    
823
void janus_audiobridge_destroy(void) {
824
        if(!g_atomic_int_get(&initialized))
825
                return;
826
        g_atomic_int_set(&stopping, 1);
827
        if(handler_thread != NULL) {
828
                g_thread_join(handler_thread);
829
                handler_thread = NULL;
830
        }
831
        if(watchdog != NULL) {
832
                g_thread_join(watchdog);
833
                watchdog = NULL;
834
        }
835
        /* FIXME We should destroy the sessions cleanly */
836
        janus_mutex_lock(&sessions_mutex);
837
        g_hash_table_destroy(sessions);
838
        janus_mutex_unlock(&sessions_mutex);
839
        janus_mutex_lock(&rooms_mutex);
840
        g_hash_table_destroy(rooms);
841
        janus_mutex_unlock(&rooms_mutex);
842
        g_async_queue_unref(messages);
843
        messages = NULL;
844
        sessions = NULL;
845
        g_atomic_int_set(&initialized, 0);
846
        g_atomic_int_set(&stopping, 0);
847
        JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_AUDIOBRIDGE_NAME);
848
}
849

    
850
int janus_audiobridge_get_api_compatibility(void) {
851
        /* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
852
        return JANUS_PLUGIN_API_VERSION;
853
}
854

    
855
int janus_audiobridge_get_version(void) {
856
        return JANUS_AUDIOBRIDGE_VERSION;
857
}
858

    
859
const char *janus_audiobridge_get_version_string(void) {
860
        return JANUS_AUDIOBRIDGE_VERSION_STRING;
861
}
862

    
863
const char *janus_audiobridge_get_description(void) {
864
        return JANUS_AUDIOBRIDGE_DESCRIPTION;
865
}
866

    
867
const char *janus_audiobridge_get_name(void) {
868
        return JANUS_AUDIOBRIDGE_NAME;
869
}
870

    
871
const char *janus_audiobridge_get_author(void) {
872
        return JANUS_AUDIOBRIDGE_AUTHOR;
873
}
874

    
875
const char *janus_audiobridge_get_package(void) {
876
        return JANUS_AUDIOBRIDGE_PACKAGE;
877
}
878

    
879
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error) {
880
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
881
                *error = -1;
882
                return;
883
        }        
884
        janus_audiobridge_session *session = (janus_audiobridge_session *)g_malloc0(sizeof(janus_audiobridge_session));
885
        if(session == NULL) {
886
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
887
                *error = -2;
888
                return;
889
        }
890
        session->handle = handle;
891
        session->started = FALSE;
892
        session->stopping = FALSE;
893
        session->destroyed = 0;
894
        g_atomic_int_set(&session->hangingup, 0);
895
        handle->plugin_handle = session;
896
        janus_mutex_lock(&sessions_mutex);
897
        g_hash_table_insert(sessions, handle, session);
898
        janus_mutex_unlock(&sessions_mutex);
899

    
900
        return;
901
}
902

    
903
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error) {
904
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
905
                *error = -1;
906
                return;
907
        }        
908
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle; 
909
        if(!session) {
910
                JANUS_LOG(LOG_ERR, "No AudioBridge session associated with this handle...\n");
911
                *error = -2;
912
                return;
913
        }
914
        JANUS_LOG(LOG_VERB, "Removing AudioBridge session...\n");
915
        janus_mutex_lock(&sessions_mutex);
916
        if(!session->destroyed) {
917
                g_hash_table_remove(sessions, handle);
918
                janus_audiobridge_hangup_media(handle);
919
                session->destroyed = janus_get_monotonic_time();
920
                /* Cleaning up and removing the session is done in a lazy way */
921
                old_sessions = g_list_append(old_sessions, session);
922
        }
923
        janus_mutex_unlock(&sessions_mutex);
924

    
925
        return;
926
}
927

    
928
char *janus_audiobridge_query_session(janus_plugin_session *handle) {
929
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
930
                return NULL;
931
        }        
932
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
933
        if(!session) {
934
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
935
                return NULL;
936
        }
937
        /* Show the participant/room info, if any */
938
        json_t *info = json_object();
939
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
940
        json_object_set_new(info, "state", json_string(participant && participant->room ? "inroom" : "idle"));
941
        if(participant) {
942
                janus_audiobridge_room *room = participant->room; 
943
                json_object_set_new(info, "room", room ? json_integer(room->room_id) : NULL);
944
                json_object_set_new(info, "id", json_integer(participant->user_id));
945
                if(participant->display)
946
                        json_object_set_new(info, "display", json_string(participant->display));
947
                json_object_set_new(info, "muted", json_string(participant->muted ? "true" : "false"));
948
                json_object_set_new(info, "active", json_string(participant->active ? "true" : "false"));
949
                json_object_set_new(info, "pre-buffering", json_string(participant->prebuffering ? "true" : "false"));
950
                if(participant->inbuf) {
951
                        janus_mutex_lock(&participant->qmutex);
952
                        json_object_set_new(info, "queue-in", json_integer(g_list_length(participant->inbuf)));
953
                        janus_mutex_unlock(&participant->qmutex);
954
                }
955
                if(participant->outbuf)
956
                        json_object_set_new(info, "queue-out", json_integer(g_async_queue_length(participant->outbuf)));
957
        }
958
        json_object_set_new(info, "started", json_string(session->started ? "true" : "false"));
959
        json_object_set_new(info, "destroyed", json_integer(session->destroyed));
960
        char *info_text = json_dumps(info, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
961
        json_decref(info);
962
        return info_text;
963
}
964

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

    
969
        /* Pre-parse the message */
970
        int error_code = 0;
971
        char error_cause[512];
972
        json_t *root = NULL;
973
        json_t *response = NULL;
974
        
975
        if(message == NULL) {
976
                JANUS_LOG(LOG_ERR, "No message??\n");
977
                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
978
                g_snprintf(error_cause, 512, "%s", "No message??");
979
                goto error;
980
        }
981
        JANUS_LOG(LOG_VERB, "Handling message: %s\n", message);
982

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

    
1431
                g_free(message);
1432
                msg->handle = handle;
1433
                msg->transaction = transaction;
1434
                msg->message = root;
1435
                msg->sdp_type = sdp_type;
1436
                msg->sdp = sdp;
1437

    
1438
                g_async_queue_push(messages, msg);
1439

    
1440
                return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL);
1441
        } else {
1442
                JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
1443
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
1444
                g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
1445
                goto error;
1446
        }
1447

    
1448
plugin_response:
1449
                {
1450
                        if (!response) {
1451
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1452
                                g_snprintf(error_cause, 512, "Invalid response");
1453
                                goto error;
1454
                        }
1455
                        if(root != NULL)
1456
                                json_decref(root);
1457
                        g_free(transaction);
1458
                        g_free(message);
1459
                        g_free(sdp_type);
1460
                        g_free(sdp);
1461

    
1462
                        char *response_text = json_dumps(response, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1463
                        json_decref(response);
1464
                        janus_plugin_result *result = janus_plugin_result_new(JANUS_PLUGIN_OK, response_text);
1465
                        g_free(response_text);
1466
                        return result;
1467
                }
1468

    
1469
error:
1470
                {
1471
                        if(root != NULL)
1472
                                json_decref(root);
1473
                        g_free(transaction);
1474
                        g_free(message);
1475
                        g_free(sdp_type);
1476
                        g_free(sdp);
1477

    
1478
                        /* Prepare JSON error event */
1479
                        json_t *event = json_object();
1480
                        json_object_set_new(event, "audiobridge", json_string("event"));
1481
                        json_object_set_new(event, "error_code", json_integer(error_code));
1482
                        json_object_set_new(event, "error", json_string(error_cause));
1483
                        char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1484
                        json_decref(event);
1485
                        janus_plugin_result *result = janus_plugin_result_new(JANUS_PLUGIN_OK, event_text);
1486
                        g_free(event_text);
1487
                        return result;
1488
                }
1489

    
1490
}
1491

    
1492
void janus_audiobridge_setup_media(janus_plugin_session *handle) {
1493
        JANUS_LOG(LOG_INFO, "WebRTC media is now available\n");
1494
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1495
                return;
1496
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1497
        if(!session) {
1498
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1499
                return;
1500
        }
1501
        if(session->destroyed)
1502
                return;
1503
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1504
        if(!participant)
1505
                return;
1506
        g_atomic_int_set(&session->hangingup, 0);
1507
        /* FIXME Only send this peer the audio mix when we get this event */
1508
        session->started = TRUE;
1509
}
1510

    
1511
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len) {
1512
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1513
                return;
1514
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1515
        if(!session || session->destroyed || session->stopping || !session->participant)
1516
                return;
1517
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1518
        if(!participant->active || participant->muted || !participant->decoder || !participant->room)
1519
                return;
1520
        if(participant->active && participant->decoder) {
1521
                /* First of all, check if a reset on the decoder is due */
1522
                if(participant->reset) {
1523
                        /* Create a new decoder and get rid of the old one */
1524
                        int error = 0;
1525
                        OpusDecoder *decoder = opus_decoder_create(participant->room->sampling_rate, 1, &error);
1526
                        if(error != OPUS_OK) {
1527
                                JANUS_LOG(LOG_ERR, "Error resetting Opus decoder...\n");
1528
                        } else {
1529
                                if(participant->decoder)
1530
                                        opus_decoder_destroy(participant->decoder);
1531
                                participant->decoder = decoder;
1532
                                JANUS_LOG(LOG_VERB, "Opus decoder reset\n");
1533
                        }
1534
                        participant->reset = FALSE;
1535
                }
1536
                /* Decode frame (Opus -> slinear) */
1537
                rtp_header *rtp = (rtp_header *)buf;
1538
                janus_audiobridge_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
1539
                if(pkt == NULL) {
1540
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1541
                        return;
1542
                }
1543
                pkt->data = g_malloc0(BUFFER_SAMPLES*sizeof(opus_int16));
1544
                if(pkt->data == NULL) {
1545
                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
1546
                        g_free(pkt);
1547
                        return;
1548
                }
1549
                pkt->ssrc = 0;
1550
                pkt->timestamp = ntohl(rtp->timestamp);
1551
                pkt->seq_number = ntohs(rtp->seq_number);
1552
                participant->working = TRUE;
1553
                pkt->length = opus_decode(participant->decoder, (const unsigned char *)buf+12, len-12, (opus_int16 *)pkt->data, BUFFER_SAMPLES, USE_FEC);
1554
                participant->working = FALSE;
1555
                if(pkt->length < 0) {
1556
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", pkt->length, opus_strerror(pkt->length));
1557
                        g_free(pkt->data);
1558
                        g_free(pkt);
1559
                        return;
1560
                }
1561
                /* Enqueue the decoded frame */
1562
                janus_mutex_lock(&participant->qmutex);
1563
                /* Insert packets sorting by sequence number */
1564
                participant->inbuf = g_list_insert_sorted(participant->inbuf, pkt, &janus_audiobridge_rtp_sort);
1565
                if(participant->prebuffering) {
1566
                        /* Still pre-buffering: do we have enough packets now? */
1567
                        if(g_list_length(participant->inbuf) == DEFAULT_PREBUFFERING) {
1568
                                participant->prebuffering = FALSE;
1569
                                JANUS_LOG(LOG_VERB, "Prebuffering done! Finally adding the user to the mix\n");
1570
                        } else {
1571
                                JANUS_LOG(LOG_VERB, "Still prebuffering (got %d packets), not adding the user to the mix yet\n", g_list_length(participant->inbuf));
1572
                        }
1573
                } else {
1574
                        /* Make sure we're not queueing too many packets: if so, get rid of the older ones */
1575
                        if(g_list_length(participant->inbuf) >= DEFAULT_PREBUFFERING*2) {
1576
                                JANUS_LOG(LOG_WARN, "Too many packets in queue (%d > %d), removing older ones\n",
1577
                                        g_list_length(participant->inbuf), DEFAULT_PREBUFFERING*2);
1578
                                while(g_list_length(participant->inbuf) > DEFAULT_PREBUFFERING*2) {
1579
                                        /* Remove this packet: it's too old */
1580
                                        GList *first = g_list_first(participant->inbuf);
1581
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1582
                                        participant->inbuf = g_list_remove_link(participant->inbuf, first);
1583
                                        first = NULL;
1584
                                        if(pkt == NULL)
1585
                                                continue;
1586
                                        if(pkt->data)
1587
                                                g_free(pkt->data);
1588
                                        pkt->data = NULL;
1589
                                        g_free(pkt);
1590
                                        pkt = NULL;
1591
                                }
1592
                        }
1593
                }
1594
                janus_mutex_unlock(&participant->qmutex);
1595
        }
1596
}
1597

    
1598
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len) {
1599
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1600
                return;
1601
        /* FIXME Should we care? */
1602
}
1603

    
1604
void janus_audiobridge_hangup_media(janus_plugin_session *handle) {
1605
        JANUS_LOG(LOG_INFO, "No WebRTC media anymore\n");
1606
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1607
                return;
1608
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1609
        if(!session) {
1610
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1611
                return;
1612
        }
1613
        session->started = FALSE;
1614
        if(session->destroyed || !session->participant)
1615
                return;
1616
        if(g_atomic_int_add(&session->hangingup, 1))
1617
                return;
1618
        /* Get rid of participant */
1619
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1620
        janus_audiobridge_room *audiobridge = participant->room;
1621
        if(audiobridge != NULL) {
1622
                janus_mutex_lock(&audiobridge->mutex);
1623
                json_t *event = json_object();
1624
                json_object_set_new(event, "audiobridge", json_string("event"));
1625
                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
1626
                json_object_set_new(event, "leaving", json_integer(participant->user_id));
1627
                char *leaving_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
1628
                json_decref(event);
1629
                g_hash_table_remove(audiobridge->participants, GUINT_TO_POINTER(participant->user_id));
1630
                GHashTableIter iter;
1631
                gpointer value;
1632
                g_hash_table_iter_init(&iter, audiobridge->participants);
1633
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1634
                        janus_audiobridge_participant *p = value;
1635
                        if(p == participant) {
1636
                                continue;        /* Skip the leaving participant itself */
1637
                        }
1638
                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
1639
                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, leaving_text, NULL, NULL);
1640
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1641
                }
1642
                g_free(leaving_text);
1643
        }
1644
        /* Free the participant resources */
1645
        janus_mutex_lock(&participant->qmutex);
1646
        participant->active = FALSE;
1647
        participant->muted = TRUE;
1648
        if(participant->display)
1649
                g_free(participant->display);
1650
        participant->display = NULL;
1651
        participant->prebuffering = TRUE;
1652
        /* Make sure we're not using the encoder/decoder right now, we're going to destroy them */
1653
        while(participant->working)
1654
                g_usleep(5000);
1655
        if(participant->encoder)
1656
                opus_encoder_destroy(participant->encoder);
1657
        participant->encoder = NULL;
1658
        if(participant->decoder)
1659
                opus_decoder_destroy(participant->decoder);
1660
        participant->decoder = NULL;
1661
        participant->reset = FALSE;
1662
        /* Get rid of queued packets */
1663
        while(participant->inbuf) {
1664
                GList *first = g_list_first(participant->inbuf);
1665
                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1666
                participant->inbuf = g_list_remove_link(participant->inbuf, first);
1667
                first = NULL;
1668
                if(pkt == NULL)
1669
                        continue;
1670
                if(pkt->data)
1671
                        g_free(pkt->data);
1672
                pkt->data = NULL;
1673
                g_free(pkt);
1674
                pkt = NULL;
1675
        }
1676
        janus_mutex_unlock(&participant->qmutex);
1677
        if(audiobridge != NULL) {
1678
                janus_mutex_unlock(&audiobridge->mutex);
1679
        }
1680
}
1681

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

    
2427
                /* Prepare JSON event */
2428
                JANUS_LOG(LOG_VERB, "Preparing JSON event as a reply\n");
2429
                char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2430
                json_decref(event);
2431
                /* Any SDP to handle? */
2432
                if(!msg->sdp) {
2433
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, NULL, NULL);
2434
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2435
                } else {
2436
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg->sdp_type, msg->sdp);
2437
                        const char *type = NULL;
2438
                        if(!strcasecmp(msg->sdp_type, "offer"))
2439
                                type = "answer";
2440
                        if(!strcasecmp(msg->sdp_type, "answer"))
2441
                                type = "offer";
2442
                        /* Fill the SDP template and use that as our answer */
2443
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2444
                        char sdp[1024];
2445
                        /* What is the Opus payload type? */
2446
                        participant->opus_pt = janus_get_opus_pt(msg->sdp);
2447
                        JANUS_LOG(LOG_VERB, "Opus payload type is %d\n", participant->opus_pt);
2448
                        g_snprintf(sdp, 1024, sdp_template,
2449
                                janus_get_real_time(),                        /* We need current time here */
2450
                                janus_get_real_time(),                        /* We need current time here */
2451
                                participant->room->room_name,        /* Audio bridge name */
2452
                                participant->opus_pt,                        /* Opus payload type */
2453
                                participant->opus_pt,                        /* Opus payload type */
2454
                                participant->opus_pt,                         /* Opus payload type and room sampling rate */
2455
                                participant->room->sampling_rate);
2456
                        /* Did the peer negotiate video? */
2457
                        if(strstr(msg->sdp, "m=video") != NULL) {
2458
                                /* If so, reject it */
2459
                                g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", 1024);                                
2460
                        }
2461
                        /* How long will the gateway take to push the event? */
2462
                        gint64 start = janus_get_monotonic_time();
2463
                        int res = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, type, sdp);
2464
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (took %"SCNu64" us)\n", res, janus_get_monotonic_time()-start);
2465
                        if(res != JANUS_OK) {
2466
                                /* TODO Failed to negotiate? We should remove this participant */
2467
                        } else {
2468
                                /* Notify all other participants that there's a new boy in town */
2469
                                janus_audiobridge_room *audiobridge = participant->room;
2470
                                janus_mutex_lock(&audiobridge->mutex);
2471
                                json_t *list = json_array();
2472
                                json_t *pl = json_object();
2473
                                json_object_set_new(pl, "id", json_integer(participant->user_id));
2474
                                if(participant->display)
2475
                                        json_object_set_new(pl, "display", json_string(participant->display));
2476
                                json_object_set_new(pl, "muted", json_string(participant->muted ? "true" : "false"));
2477
                                json_array_append_new(list, pl);
2478
                                json_t *pub = json_object();
2479
                                json_object_set_new(pub, "audiobridge", json_string("event"));
2480
                                json_object_set_new(pub, "room", json_integer(participant->room->room_id));
2481
                                json_object_set_new(pub, "participants", list);
2482
                                char *pub_text = json_dumps(pub, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2483
                                json_decref(pub);
2484
                                GHashTableIter iter;
2485
                                gpointer value;
2486
                                g_hash_table_iter_init(&iter, audiobridge->participants);
2487
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2488
                                        janus_audiobridge_participant *p = value;
2489
                                        if(p == participant) {
2490
                                                continue;        /* Skip the new participant itself */
2491
                                        }
2492
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2493
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub_text, NULL, NULL);
2494
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2495
                                }
2496
                                g_free(pub_text);
2497
                                participant->active = TRUE;
2498
                                janus_mutex_unlock(&audiobridge->mutex);
2499
                        }
2500
                }
2501
                if(event_text)
2502
                        g_free(event_text);
2503
                event_text = NULL;
2504
                if(msg)
2505
                        janus_audiobridge_message_free(msg);
2506
                msg = NULL;
2507

    
2508
                continue;
2509
                
2510
error:
2511
                {
2512
                        /* Prepare JSON error event */
2513
                        json_t *event = json_object();
2514
                        json_object_set_new(event, "audiobridge", json_string("event"));
2515
                        json_object_set_new(event, "error_code", json_integer(error_code));
2516
                        json_object_set_new(event, "error", json_string(error_cause));
2517
                        char *event_text = json_dumps(event, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2518
                        json_decref(event);
2519
                        JANUS_LOG(LOG_VERB, "Pushing event: %s\n", event_text);
2520
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event_text, NULL, NULL);
2521
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2522
                        g_free(event_text);
2523
                        janus_audiobridge_message_free(msg);
2524
                }
2525
        }
2526
        g_free(error_cause);
2527
        JANUS_LOG(LOG_VERB, "Leaving AudioBridge handler thread\n");
2528
        return NULL;
2529
}
2530

    
2531
/* Thread to mix the contributions from all participants */
2532
static void *janus_audiobridge_mixer_thread(void *data) {
2533
        JANUS_LOG(LOG_VERB, "Audio bridge thread starting...\n");
2534
        janus_audiobridge_room *audiobridge = (janus_audiobridge_room *)data;
2535
        if(!audiobridge) {
2536
                JANUS_LOG(LOG_ERR, "Invalid room!\n");
2537
                return NULL;
2538
        }
2539
        JANUS_LOG(LOG_VERB, "Thread is for mixing room %"SCNu64" (%s) at rate %"SCNu32"...\n", audiobridge->room_id, audiobridge->room_name, audiobridge->sampling_rate);
2540

    
2541
        /* Do we need to record the mix? */
2542
        if(audiobridge->record) {
2543
                char filename[255];
2544
                if(audiobridge->record_file)
2545
                        g_snprintf(filename, 255, "%s", audiobridge->record_file);
2546
                else
2547
                        g_snprintf(filename, 255, "/tmp/janus-audioroom-%"SCNu64".wav", audiobridge->room_id);
2548
                audiobridge->recording = fopen(filename, "wb");
2549
                if(audiobridge->recording == NULL) {
2550
                        JANUS_LOG(LOG_WARN, "Recording requested, but could NOT open file %s for writing...\n", filename);
2551
                } else {
2552
                        JANUS_LOG(LOG_VERB, "Recording requested, opened file %s for writing\n", filename);
2553
                        /* Write WAV header */
2554
                        wav_header header = {
2555
                                {'R', 'I', 'F', 'F'},
2556
                                0,
2557
                                {'W', 'A', 'V', 'E'},
2558
                                {'f', 'm', 't', ' '},
2559
                                16,
2560
                                1,
2561
                                1,
2562
                                audiobridge->sampling_rate,
2563
                                audiobridge->sampling_rate * 2,
2564
                                2,
2565
                                16,
2566
                                {'d', 'a', 't', 'a'},
2567
                                0
2568
                        };
2569
                        if(fwrite(&header, 1, sizeof(header), audiobridge->recording) != sizeof(header)) {
2570
                                JANUS_LOG(LOG_ERR, "Error writing WAV header...\n");
2571
                        }
2572
                }
2573
        }
2574

    
2575
        /* Buffer (we allocate assuming 48kHz, although we'll likely use less than that) */
2576
        int samples = audiobridge->sampling_rate/50;
2577
        opus_int32 buffer[960], sumBuffer[960];
2578
        opus_int16 outBuffer[960], *curBuffer = NULL;
2579
        memset(buffer, 0, 960*4);
2580
        memset(sumBuffer, 0, 960*4);
2581
        memset(outBuffer, 0, 960*2);
2582

    
2583
        /* Timer */
2584
        struct timeval now, before;
2585
        gettimeofday(&before, NULL);
2586
        now.tv_sec = before.tv_sec;
2587
        now.tv_usec = before.tv_usec;
2588
        time_t passed, d_s, d_us;
2589

    
2590
        /* RTP */
2591
        gint16 seq = 0;
2592
        gint32 ts = 0;
2593

    
2594
        /* Loop */
2595
        int i=0;
2596
        int count = 0, prev_count = 0;
2597
        while(!g_atomic_int_get(&stopping) && audiobridge->destroyed == 0) {        /* FIXME We need a per-room watchdog as well */
2598
                /* See if it's time to prepare a frame */
2599
                gettimeofday(&now, NULL);
2600
                d_s = now.tv_sec - before.tv_sec;
2601
                d_us = now.tv_usec - before.tv_usec;
2602
                if(d_us < 0) {
2603
                        d_us += 1000000;
2604
                        --d_s;
2605
                }
2606
                passed = d_s*1000000 + d_us;
2607
                if(passed < 15000) {        /* Let's wait about 15ms at max */
2608
                        usleep(1000);
2609
                        continue;
2610
                }
2611
                /* Update the reference time */
2612
                before.tv_usec += 20000;
2613
                if(before.tv_usec > 1000000) {
2614
                        before.tv_sec++;
2615
                        before.tv_usec -= 1000000;
2616
                }
2617
                /* Do we need to mix at all? */
2618
                janus_mutex_lock_nodebug(&audiobridge->mutex);
2619
                count = g_hash_table_size(audiobridge->participants);
2620
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
2621
                if(count == 0) {
2622
                        /* No participant, do nothing */
2623
                        if(prev_count > 0) {
2624
                                JANUS_LOG(LOG_VERB, "Last user just left room %"SCNu64", going idle...\n", audiobridge->room_id);
2625
                                prev_count = 0;
2626
                        }
2627
                        continue;
2628
                }
2629
                if(prev_count == 0) {
2630
                        JANUS_LOG(LOG_VERB, "First user just joined room %"SCNu64", waking it up...\n", audiobridge->room_id);
2631
                }
2632
                prev_count = count;
2633
                /* Update RTP header information */
2634
                seq++;
2635
                ts += 960;
2636
                /* Mix all contributions */
2637
                janus_mutex_lock_nodebug(&audiobridge->mutex);
2638
                GList *participants_list = g_hash_table_get_values(audiobridge->participants);
2639
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
2640
                for(i=0; i<samples; i++)
2641
                        buffer[i] = 0;
2642
                GList *ps = participants_list;
2643
                while(ps) {
2644
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
2645
                        janus_mutex_lock(&p->qmutex);
2646
                        if(!p->active || p->muted || p->prebuffering || !p->inbuf) {
2647
                                janus_mutex_unlock(&p->qmutex);
2648
                                ps = ps->next;
2649
                                continue;
2650
                        }
2651
                        GList *peek = g_list_first(p->inbuf);
2652
                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)(peek ? peek->data : NULL);
2653
                        if(pkt != NULL) {
2654
                                curBuffer = (opus_int16 *)pkt->data;
2655
                                for(i=0; i<samples; i++)
2656
                                        buffer[i] += curBuffer[i];
2657
                        }
2658
                        janus_mutex_unlock(&p->qmutex);
2659
                        ps = ps->next;
2660
                }
2661
                /* Are we recording the mix? (only do it if there's someone in, though...) */
2662
                if(audiobridge->recording != NULL && g_list_length(participants_list) > 0) {
2663
                        for(i=0; i<samples; i++) {
2664
                                /* FIXME Smoothen/Normalize instead of truncating? */
2665
                                outBuffer[i] = buffer[i];
2666
                        }
2667
                        fwrite(outBuffer, sizeof(opus_int16), samples, audiobridge->recording);
2668
                }
2669
                /* Send proper packet to each participant (remove own contribution) */
2670
                ps = participants_list;
2671
                while(ps) {
2672
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
2673
                        janus_audiobridge_rtp_relay_packet *pkt = NULL;
2674
                        janus_mutex_lock(&p->qmutex);
2675
                        if(p->active && !p->muted && !p->prebuffering && p->inbuf) {
2676
                                GList *first = g_list_first(p->inbuf);
2677
                                pkt = (janus_audiobridge_rtp_relay_packet *)(first ? first->data : NULL);
2678
                                p->inbuf = g_list_delete_link(p->inbuf, first);
2679
                        }
2680
                        janus_mutex_unlock(&p->qmutex);
2681
                        curBuffer = (opus_int16 *)(pkt ? pkt->data : NULL);
2682
                        for(i=0; i<samples; i++)
2683
                                sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]) : 0);
2684
                        for(i=0; i<samples; i++)
2685
                                /* FIXME Smoothen/Normalize instead of truncating? */
2686
                                outBuffer[i] = sumBuffer[i];
2687
                        /* Enqueue this mixed frame for encoding in the participant thread */
2688
                        janus_audiobridge_rtp_relay_packet *mixedpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
2689
                        if(mixedpkt != NULL) {
2690
                                mixedpkt->data = g_malloc0(samples*2);
2691
                                if(mixedpkt->data == NULL) {
2692
                                        JANUS_LOG(LOG_FATAL, "Memory error!\n");
2693
                                        g_free(mixedpkt);
2694
                                } else {
2695
                                        memcpy(mixedpkt->data, outBuffer, samples*2);
2696
                                        mixedpkt->length = samples;        /* We set the number of samples here, not the data length */
2697
                                        mixedpkt->timestamp = ts;
2698
                                        mixedpkt->seq_number = seq;
2699
                                        mixedpkt->ssrc = audiobridge->room_id;
2700
                                        g_async_queue_push(p->outbuf, mixedpkt);
2701
                                }
2702
                        }
2703
                        if(pkt) {
2704
                                if(pkt->data)
2705
                                        g_free(pkt->data);
2706
                                pkt->data = NULL;
2707
                                g_free(pkt);
2708
                                pkt = NULL;
2709
                        }
2710
                        ps = ps->next;
2711
                }
2712
                g_list_free(participants_list);
2713
        }
2714
        if(audiobridge->recording)
2715
                fclose(audiobridge->recording);
2716
        JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %"SCNu64" (%s)...\n", audiobridge->room_id, audiobridge->room_name);
2717

    
2718
        /* Free resources */
2719
        g_free(audiobridge->room_name);
2720
        g_free(audiobridge->room_secret);
2721
        g_free(audiobridge->room_pin);
2722
        g_free(audiobridge->record_file);
2723
        g_hash_table_destroy(audiobridge->participants);
2724
        g_free(audiobridge);
2725

    
2726
        return NULL;
2727
}
2728

    
2729
/* Thread to encode a mixed frame and send it to a specific participant */
2730
static void *janus_audiobridge_participant_thread(void *data) {
2731
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread starting...\n");
2732
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)data;
2733
        if(!participant) {
2734
                JANUS_LOG(LOG_ERR, "Invalid participant!\n");
2735
                g_thread_unref(g_thread_self());
2736
                return NULL;
2737
        }
2738
        JANUS_LOG(LOG_VERB, "Thread is for participant %"SCNu64" (%s)\n", participant->user_id, participant->display ? participant->display : "??");
2739
        janus_audiobridge_session *session = participant->session;
2740

    
2741
        /* Output buffer */
2742
        janus_audiobridge_rtp_relay_packet *outpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
2743
        if(outpkt == NULL) {
2744
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2745
                g_thread_unref(g_thread_self());
2746
                return NULL;
2747
        }
2748
        outpkt->data = (rtp_header *)g_malloc0(1500);
2749
        if(outpkt->data == NULL) {
2750
                JANUS_LOG(LOG_FATAL, "Memory error!\n");
2751
                g_free(outpkt);
2752
                g_thread_unref(g_thread_self());
2753
                return NULL;
2754
        }
2755
        outpkt->ssrc = 0;
2756
        outpkt->timestamp = 0;
2757
        outpkt->seq_number = 0;
2758
        unsigned char *payload = (unsigned char *)outpkt->data;
2759
        memset(payload, 0, 1500);
2760

    
2761
        janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
2762

    
2763
        /* Start working: check the outgoing queue for packets, then encode and send them */
2764
        while(!g_atomic_int_get(&stopping) && session->destroyed == 0) {
2765
                if(!participant->active || !participant->encoder) {
2766
                        /* Wait until the participant is in a room */
2767
                        g_usleep(10000);
2768
                        continue;
2769
                }
2770
                if(g_async_queue_length(participant->outbuf) == 0) {
2771
                        /* Nothing to do */
2772
                        g_usleep(5000);
2773
                        continue;
2774
                }
2775
                mixedpkt = g_async_queue_pop(participant->outbuf);
2776
                if(mixedpkt != NULL && session->destroyed == 0) {
2777
                        /* Encode raw frame to Opus */
2778
                        if(participant->active && participant->encoder) {
2779
                                participant->working = TRUE;
2780
                                opus_int16 *outBuffer = (opus_int16 *)mixedpkt->data;
2781
                                outpkt->length = opus_encode(participant->encoder, outBuffer, mixedpkt->length, payload+12, BUFFER_SAMPLES-12);
2782
                                participant->working = FALSE;
2783
                                if(outpkt->length < 0) {
2784
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", outpkt->length, opus_strerror(outpkt->length));
2785
                                } else {
2786
                                        outpkt->length += 12;        /* Take the RTP header into consideration */
2787
                                        /* Update RTP header */
2788
                                        outpkt->data->version = 2;
2789
                                        outpkt->data->markerbit = 0;        /* FIXME Should be 1 for the first packet */
2790
                                        outpkt->data->seq_number = htons(mixedpkt->seq_number);
2791
                                        outpkt->data->timestamp = htonl(mixedpkt->timestamp);
2792
                                        outpkt->data->ssrc = htonl(mixedpkt->ssrc);        /* The gateway will fix this anyway */
2793
                                        /* Backup the actual timestamp and sequence number set by the audiobridge, in case a room is changed */
2794
                                        outpkt->ssrc = mixedpkt->ssrc;
2795
                                        outpkt->timestamp = mixedpkt->timestamp;
2796
                                        outpkt->seq_number = mixedpkt->seq_number;
2797
                                        janus_audiobridge_relay_rtp_packet(participant->session, outpkt);
2798
                                }
2799
                        }
2800
                        if(mixedpkt) {
2801
                                if(mixedpkt->data)
2802
                                        g_free(mixedpkt->data);
2803
                                mixedpkt->data = NULL;
2804
                                g_free(mixedpkt);
2805
                                mixedpkt = NULL;
2806
                        }
2807
                }
2808
        }
2809
        /* We're done, get rid of the resources */
2810
        if(outpkt != NULL) {
2811
                if(outpkt->data != NULL) {
2812
                        g_free(outpkt->data);
2813
                        outpkt->data = NULL;
2814
                }
2815
                g_free(outpkt);
2816
                outpkt = NULL;
2817
        }
2818
        /* Empty the outgoing queue if there was something still in */
2819
        while(g_async_queue_length(participant->outbuf) > 0) {
2820
                janus_audiobridge_rtp_relay_packet *pkt = g_async_queue_pop(participant->outbuf);
2821
                if(pkt == NULL)
2822
                        continue;
2823
                if(pkt->data)
2824
                        g_free(pkt->data);
2825
                pkt->data = NULL;
2826
                g_free(pkt);
2827
                pkt = NULL;
2828
        }
2829
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread leaving...\n");
2830
        return NULL;
2831
}
2832

    
2833
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data) {
2834
        janus_audiobridge_rtp_relay_packet *packet = (janus_audiobridge_rtp_relay_packet *)user_data;
2835
        if(!packet || !packet->data || packet->length < 1) {
2836
                JANUS_LOG(LOG_ERR, "Invalid packet...\n");
2837
                return;
2838
        }
2839
        janus_audiobridge_session *session = (janus_audiobridge_session *)data;
2840
        if(!session || !session->handle) {
2841
                // JANUS_LOG(LOG_ERR, "Invalid session...\n");
2842
                return;
2843
        }
2844
        if(!session->started) {
2845
                // JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
2846
                return;
2847
        }
2848
        janus_audiobridge_participant *participant = session->participant;
2849
        /* Set the payload type */
2850
        packet->data->type = participant->opus_pt;
2851
        /* Fix sequence number and timestamp (room switching may be involved) */
2852
        if(ntohl(packet->data->ssrc) != participant->context.a_last_ssrc) {
2853
                participant->context.a_last_ssrc = ntohl(packet->data->ssrc);
2854
                participant->context.a_base_ts_prev = participant->context.a_last_ts;
2855
                participant->context.a_base_ts = packet->timestamp;
2856
                participant->context.a_base_seq_prev = participant->context.a_last_seq;
2857
                participant->context.a_base_seq = packet->seq_number;
2858
        }
2859
        /* Compute a coherent timestamp and sequence number */
2860
        participant->context.a_last_ts = (packet->timestamp-participant->context.a_base_ts)
2861
                + participant->context.a_base_ts_prev+960;        /* FIXME When switching, we assume Opus and so a 960 ts step */
2862
        participant->context.a_last_seq = (packet->seq_number-participant->context.a_base_seq)+participant->context.a_base_seq_prev+1;
2863
        /* Update the timestamp and sequence number in the RTP packet, and send it */
2864
        packet->data->timestamp = htonl(participant->context.a_last_ts);
2865
        packet->data->seq_number = htons(participant->context.a_last_seq);
2866
        if(gateway != NULL)
2867
                gateway->relay_rtp(session->handle, 0, (char *)packet->data, packet->length);
2868
        /* Restore the timestamp and sequence number to what the publisher set them to */
2869
        packet->data->timestamp = htonl(packet->timestamp);
2870
        packet->data->seq_number = htons(packet->seq_number);
2871
}