Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_audiobridge.c @ a972337c

History | View | Annotate | Download (133 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
 * The AudioBridge plugin also allows you to forward the mix to an
65
 * external listener, e.g., a gstreamer/ffmpeg pipeline waiting to
66
 * process the mixer audio stream. You can add new RTP forwarders with
67
 * the \c rtp_forward request; a \c stop_rtp_forward request removes an
68
 * existing RTP forwarder; \c listforwarders lists all the current RTP
69
 * forwarders on a specific AudioBridge room instance.
70
 *
71
 * \c create can be used to create a new audio room, and has to be
72
 * formatted as follows:
73
 * 
74
\verbatim
75
{
76
        "request" : "create",
77
        "room" : <unique numeric ID, optional, chosen by plugin if missing>,
78
        "permanent" : <true|false, whether the room should be saved in the config file, default false>,
79
        "description" : "<pretty name of the room, optional>",
80
        "secret" : "<password required to edit/destroy the room, optional>",
81
        "pin" : "<password required to join the room, optional>",
82
        "is_private" : <true|false, whether the room should appear in a list request>,
83
        "sampling" : <sampling rate of the room, optional, 16000 by default>,
84
        "record" : <true|false, whether to record the room or not, default false>,
85
        "record_file" : "</path/to/the/recording.wav, optional>",
86
}
87
\endverbatim
88
 *
89
 * A successful creation procedure will result in a \c created response:
90
 * 
91
\verbatim
92
{
93
        "audiobridge" : "created",
94
        "room" : <unique numeric ID>
95
}
96
\endverbatim
97
 *
98
 * An error instead (and the same applies to all other requests, so this
99
 * won't be repeated) would provide both an error code and a more verbose
100
 * description of the cause of the issue:
101
 * 
102
\verbatim
103
{
104
        "audiobridge" : "event",
105
        "error_code" : <numeric ID, check Macros below>,
106
        "error" : "<error description as a string>"
107
}
108
\endverbatim
109
 * 
110
 * Notice that, in general, all users can create rooms. If you want to
111
 * limit this functionality, you can configure an admin \c admin_key in
112
 * the plugin settings. When configured, only "create" requests that
113
 * include the correct \c admin_key value in an "admin_key" property
114
 * will succeed, and will be rejected otherwise.
115
 * 
116
 * On the other hand, \c destroy can be used to destroy an existing audio
117
 * room, whether created dynamically or statically, and has to be
118
 * formatted as follows:
119
 * 
120
\verbatim
121
{
122
        "request" : "destroy",
123
        "room" : <unique numeric ID of the room to destroy>,
124
        "secret" : "<room secret, mandatory if configured>",
125
        "permanent" : <true|false, whether the room should be also removed from the config file, default false>
126
}
127
\endverbatim
128
 *
129
 * A successful destruction procedure will result in a \c destroyed response:
130
 * 
131
\verbatim
132
{
133
        "audiobridge" : "created",
134
        "room" : <unique numeric ID>
135
}
136
\endverbatim
137
 *
138
 * You can check whether a room exists using the \c exists request,
139
 * which has to be formatted as follows:
140
 * 
141
\verbatim
142
{
143
        "request" : "exists",
144
        "room" : <unique numeric ID of the room to check>
145
}
146
\endverbatim
147
 *
148
 * A successful request will result in a \c success response:
149
 * 
150
\verbatim
151
{
152
        "audiobridge" : "success",
153
        "room" : <unique numeric ID>,
154
        "exists" : <true|false>
155
}
156
\endverbatim
157
 * 
158
 * To get a list of the available rooms (excluded those configured or
159
 * created as private rooms) you can make use of the \c list request,
160
 * which has to be formatted as follows:
161
 * 
162
\verbatim
163
{
164
        "request" : "list"
165
}
166
\endverbatim
167
 *
168
 * A successful request will produce a list of rooms in a \c success response:
169
 * 
170
\verbatim
171
{
172
        "audiobridge" : "success",
173
        "rooms" : [                // Array of room objects
174
                {        // Room #1
175
                        "room" : <unique numeric ID>,
176
                        "description" : "<Name of the room>",
177
                        "sampling_rate" : <sampling rate of the mixer>,
178
                        "record" : <true|false, whether the room is being recorded>,
179
                        "num_participants" : <count of the participants>
180
                },
181
                // Other rooms
182
        ]
183
}
184
\endverbatim
185
 *
186
 * To get a list of the participants in a specific room, instead, you
187
 * can make use of the \c listparticipants request, which has to be
188
 * formatted as follows:
189
 * 
190
\verbatim
191
{
192
        "request" : "listparticipants",
193
        "room" : <unique numeric ID of the room>
194
}
195
\endverbatim
196
 *
197
 * A successful request will produce a list of participants in a
198
 * \c participants response:
199
 * 
200
\verbatim
201
{
202
        "audiobridge" : "participants",
203
        "room" : <unique numeric ID of the room>,
204
        "participants" : [                // Array of participant objects
205
                {        // Participant #1
206
                        "id" : <unique numeric ID of the participant>,
207
                        "display" : "<display name of the participant, if any; optional>",
208
                        "muted" : <true|false, whether user is muted or not>
209
                },
210
                // Other participants
211
        ]
212
}
213
\endverbatim
214
 * 
215
 * To mark the Opus decoder context for the current participant as
216
 * invalid and force it to be recreated, use the \c resetdecoder request:
217
 * 
218
\verbatim
219
{
220
        "request" : "resetdecoder"
221
}
222
\endverbatim
223
 *
224
 * A successful request will produce a \c success response:
225
 * 
226
\verbatim
227
{
228
        "audiobridge" : "success"
229
}
230
\endverbatim
231
 * 
232
 * You can add a new RTP forwarder for an existing room exists using the
233
 * \c rtp_forward request, which has to be formatted as follows:
234
 *
235
\verbatim
236
{
237
        "request" : "rtp_forward",
238
        "room" : <unique numeric ID of the room to add the forwarder to>,
239
        "ptype" : <payload type to use when streaming>,
240
        "host" : "<host address to forward the RTP packets to>",
241
        "port" : <port to forward the RTP packets to>,
242
        "always_on" : <true|false, whether silence should be forwarded when the room is empty>
243
}
244
\endverbatim
245
 *
246
 * A successful request will result in a \c success response:
247
 *
248
\verbatim
249
{
250
        "audiobridge" : "success",
251
        "room" : <unique numeric ID, same as request>,
252
        "stream_id" : <unique numeric ID assigned to the new RTP forwarder>
253
}
254
\endverbatim
255
 *
256
 * To stop a previously created RTP forwarder and stop it, you can use
257
 * the \c stop_rtp_forward request, which has to be formatted as follows:
258
 *
259
\verbatim
260
{
261
        "request" : "stop_rtp_forward",
262
        "room" : <unique numeric ID of the room to remove the forwarder from>,
263
        "stream_id" : <unique numeric ID of the RTP forwarder>
264
}
265
\endverbatim
266
 *
267
 * A successful request will result in a \c success response:
268
 *
269
\verbatim
270
{
271
        "audiobridge" : "success",
272
        "room" : <unique numeric ID, same as request>,
273
        "stream_id" : <unique numeric ID, same as request>
274
}
275
\endverbatim
276
 *
277
 * To get a list of the forwarders in a specific room, instead, you
278
 * can make use of the \c listforwarders request, which has to be
279
 * formatted as follows:
280
 *
281
\verbatim
282
{
283
        "request" : "listforwarders",
284
        "room" : <unique numeric ID of the room>
285
}
286
\endverbatim
287
 *
288
 * A successful request will produce a list of RTP forwarders in a
289
 * \c forwarders response:
290
 *
291
\verbatim
292
{
293
        "audiobridge" : "forwarders",
294
        "room" : <unique numeric ID of the room>,
295
        "rtp_forwarders" : [                // Array of RTP forwarder objects
296
                {        // RTP forwarder #1
297
                        "stream_id" : <unique numeric ID of the forwarder>,
298
                        "ip" : "<IP this forwarder is streaming to>",
299
                        "port" : <port this forwarder is streaming to>,
300
                        "ptype" : <payload type this forwarder is using>
301
                },
302
                // Other forwarders
303
        ]
304
}
305
 *
306
 * That completes the list of synchronous requests you can send to the
307
 * AudioBridge plugin. As anticipated, though, there are also several
308
 * asynchronous requests you can send, specifically those related to
309
 * joining and updating one's presence as a participant in an audio room.
310
 * 
311
 * The way you'd interact with the plugin is usually as follows:
312
 * 
313
 * -# you use a \c join request to join an audio room, and wait for the
314
 * \c joined event; this event will also include a list of the other
315
 * participants, if any;
316
 * -# you send a \c configure request attached to an audio-only JSEP offer
317
 * to start configuring your participation in the room (e.g., join unmuted
318
 * or muted), and wait for a \c configured event, which will be attached
319
 * to a JSEP answer by the plugin to complete the setup of the WebRTC
320
 * PeerConnection;
321
 * -# you send other \c configure requests (without any JSEP-related
322
 * attachment) to mute/unmute yourself during the audio conference;
323
 * -# you intercept events originated by the plugin (\c joined , \c leaving )
324
 * to notify you about users joining/leaving/muting/unmuting;
325
 * -# you eventually send a \c leave request to leave a room; if you leave the
326
 * PeerConnection instance intact, you can subsequently join a different
327
 * room without requiring a new negotiation (and so just use a \c join + JSEP-less \c configure to join).
328
 * 
329
 * Notice that there's also a \c changeroom request available: you can use
330
 * this request to immediately leave the room you're in and join a different
331
 * one, without requiring you to do a \c leave + \c join + \c configure
332
 * round. Of course remember not to pass any JSEP-related payload when
333
 * doing a \c changeroom as the same pre-existing PeerConnection will be
334
 * re-used for the purpose.
335
 * 
336
 * About the syntax of all the above mentioned requests, \c join has
337
 * to be formatted as follows:
338
 * 
339
\verbatim
340
{
341
        "request" : "join",
342
        "room" : <numeric ID of the room to join>,
343
        "id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
344
        "pin" : "<password required to join the room, if any; optional>",
345
        "display" : "<display name to have in the room; optional>",
346
        "muted" : <true|false, whether to start unmuted or muted>,
347
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>
348
}
349
\endverbatim
350
 *
351
 * A successful request will produce a \c joined event:
352
 * 
353
\verbatim
354
{
355
        "audiobridge" : "joined",
356
        "room" : <numeric ID of the room>,
357
        "id" : <unique ID assigned to the participant>,
358
        "display" : "<display name of the new participant>",
359
        "participants" : [
360
                // Array of existing participants in the room
361
        ]
362
}
363
\endverbatim
364
 * 
365
 * The other participants in the room will be notified about the new
366
 * participant by means of a different \c joined event, which will only
367
 * include the \c room and the new participant as the only object in
368
 * a \c participants array.
369
 *
370
 * At this point, the media-related settings of the participant can be
371
 * modified by means of a \c configure request. The \c configure request
372
 * has to be formatted as follows:
373
 *
374
\verbatim
375
{
376
        "request" : "configure",
377
        "muted" : <true|false, whether to unmute or mute>,
378
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>,
379
        "record": <true|false, whether to record this user's contribution to a .mjr file (mixer not involved),
380
        "filename": "<basename of the file to record to, -audio.mjr will be added by the plugin>"
381
}
382
\endverbatim
383
 *
384
 * \c muted instructs the plugin to mute or unmute the participant;
385
 * \c quality changes the complexity of the Opus encoder for the
386
 * participant; \c record can be used to record this participant's contribution
387
 * to a Janus .mjr file, and \c filename to provide a basename for the path to
388
 * save the file to (notice that this is different from the recording of a whole
389
 * room: this feature only records the packets this user is sending, and is not
390
 * related to the mixer stuff). A successful request will result in a \c ok event:
391
 * 
392
\verbatim
393
{
394
        "audiobridge" : "event",
395
        "room" : <numeric ID of the room>,
396
        "result" : "ok"
397
}
398
\endverbatim
399
 *
400
 * In case the \c muted property was modified, the other participants in
401
 * the room will be notified about this by means of a \c event notification,
402
 * which will only include the \c room and the updated participant as the
403
 * only object in a \c participants array.
404
 *
405
 * As anticipated, you can leave an audio room using the \c leave request,
406
 * which has to be formatted as follows:
407
 * 
408
\verbatim
409
{
410
        "request" : "leave"
411
}
412
\endverbatim
413
 * 
414
 * All the participants will receive an \c event notification with the
415
 * ID of the participant who just left:
416
 * 
417
\verbatim
418
{
419
        "audiobridge" : "event",
420
        "room" : <numeric ID of the room>,
421
        "leaving" : <numeric ID of the participant who left>
422
}
423
\endverbatim
424
 *
425
 * For what concerns the \c changeroom request, instead, it's pretty much
426
 * the same as a \c join request and as such has to be formatted as follows:
427
 * 
428
\verbatim
429
{
430
        "request" : "changeroom",
431
        "room" : <numeric ID of the room to move to>,
432
        "id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
433
        "display" : "<display name to have in the room; optional>",
434
        "muted" : <true|false, whether to start unmuted or muted>,
435
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>
436
}
437
\endverbatim
438
 * 
439
 * Such a request will trigger all the above-described leaving/joined
440
 * events to the other participants, as it is indeed wrapping a \c leave
441
 * followed by a \c join and as such the other participants in both rooms
442
 * need to be updated accordingly. The participant who switched room
443
 * instead will be sent a \c roomchanged event which is pretty similar
444
 * to what \c joined looks like:
445
 * 
446
 * A successful request will produce a \c joined event:
447
 * 
448
\verbatim
449
{
450
        "audiobridge" : "roomchanged",
451
        "room" : <numeric ID of the new room>,
452
        "id" : <unique ID assigned to the participant in the new room>,
453
        "display" : "<display name of the new participant>",
454
        "participants" : [
455
                // Array of existing participants in the new room
456
        ]
457
}
458
\endverbatim
459
 *  
460
 * \ingroup plugins
461
 * \ref plugins
462
 */
463

    
464
#include "plugin.h"
465

    
466
#include <jansson.h>
467
#include <opus/opus.h>
468
#include <sys/time.h>
469

    
470
#include "../debug.h"
471
#include "../apierror.h"
472
#include "../config.h"
473
#include "../mutex.h"
474
#include "../rtp.h"
475
#include "../rtcp.h"
476
#include "../record.h"
477
#include "../utils.h"
478

    
479

    
480
/* Plugin information */
481
#define JANUS_AUDIOBRIDGE_VERSION                        9
482
#define JANUS_AUDIOBRIDGE_VERSION_STRING        "0.0.9"
483
#define JANUS_AUDIOBRIDGE_DESCRIPTION                "This is a plugin implementing an audio conference bridge for Janus, mixing Opus streams."
484
#define JANUS_AUDIOBRIDGE_NAME                                "JANUS AudioBridge plugin"
485
#define JANUS_AUDIOBRIDGE_AUTHOR                        "Meetecho s.r.l."
486
#define JANUS_AUDIOBRIDGE_PACKAGE                        "janus.plugin.audiobridge"
487

    
488
/* Plugin methods */
489
janus_plugin *create(void);
490
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path);
491
void janus_audiobridge_destroy(void);
492
int janus_audiobridge_get_api_compatibility(void);
493
int janus_audiobridge_get_version(void);
494
const char *janus_audiobridge_get_version_string(void);
495
const char *janus_audiobridge_get_description(void);
496
const char *janus_audiobridge_get_name(void);
497
const char *janus_audiobridge_get_author(void);
498
const char *janus_audiobridge_get_package(void);
499
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error);
500
struct janus_plugin_result *janus_audiobridge_handle_message(janus_plugin_session *handle, char *transaction, json_t *message, json_t *jsep);
501
void janus_audiobridge_setup_media(janus_plugin_session *handle);
502
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len);
503
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len);
504
void janus_audiobridge_hangup_media(janus_plugin_session *handle);
505
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error);
506
json_t *janus_audiobridge_query_session(janus_plugin_session *handle);
507

    
508
/* Plugin setup */
509
static janus_plugin janus_audiobridge_plugin =
510
        JANUS_PLUGIN_INIT (
511
                .init = janus_audiobridge_init,
512
                .destroy = janus_audiobridge_destroy,
513

    
514
                .get_api_compatibility = janus_audiobridge_get_api_compatibility,
515
                .get_version = janus_audiobridge_get_version,
516
                .get_version_string = janus_audiobridge_get_version_string,
517
                .get_description = janus_audiobridge_get_description,
518
                .get_name = janus_audiobridge_get_name,
519
                .get_author = janus_audiobridge_get_author,
520
                .get_package = janus_audiobridge_get_package,
521
                
522
                .create_session = janus_audiobridge_create_session,
523
                .handle_message = janus_audiobridge_handle_message,
524
                .setup_media = janus_audiobridge_setup_media,
525
                .incoming_rtp = janus_audiobridge_incoming_rtp,
526
                .incoming_rtcp = janus_audiobridge_incoming_rtcp,
527
                .hangup_media = janus_audiobridge_hangup_media,
528
                .destroy_session = janus_audiobridge_destroy_session,
529
                .query_session = janus_audiobridge_query_session,
530
        );
531

    
532
/* Plugin creator */
533
janus_plugin *create(void) {
534
        JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_AUDIOBRIDGE_NAME);
535
        return &janus_audiobridge_plugin;
536
}
537

    
538
/* Parameter validation */
539
static struct janus_json_parameter request_parameters[] = {
540
        {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
541
};
542
static struct janus_json_parameter adminkey_parameters[] = {
543
        {"admin_key", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
544
};
545
static struct janus_json_parameter create_parameters[] = {
546
        {"description", JSON_STRING, 0},
547
        {"secret", JSON_STRING, 0},
548
        {"pin", JSON_STRING, 0},
549
        {"is_private", JANUS_JSON_BOOL, 0},
550
        {"sampling", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
551
        {"record", JANUS_JSON_BOOL, 0},
552
        {"record_file", JSON_STRING, 0},
553
        {"permanent", JANUS_JSON_BOOL, 0},
554
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
555
};
556
static struct janus_json_parameter destroy_parameters[] = {
557
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
558
        {"permanent", JANUS_JSON_BOOL, 0}
559
};
560
static struct janus_json_parameter room_parameters[] = {
561
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
562
};
563
static struct janus_json_parameter join_parameters[] = {
564
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
565
        {"display", JSON_STRING, 0},
566
        {"muted", JANUS_JSON_BOOL, 0},
567
        {"quality", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
568
        {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
569
};
570
static struct janus_json_parameter configure_parameters[] = {
571
        {"muted", JANUS_JSON_BOOL, 0},
572
        {"quality", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
573
        {"record", JANUS_JSON_BOOL, 0},
574
        {"filename", JSON_STRING, 0}
575
};
576
static struct janus_json_parameter rtp_forward_parameters[] = {
577
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
578
        {"ptype", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
579
        {"port", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
580
        {"host", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
581
        {"always_on", JANUS_JSON_BOOL, 0}
582
};
583
static struct janus_json_parameter stop_rtp_forward_parameters[] = {
584
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
585
        {"stream_id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
586
};
587

    
588
/* Static configuration instance */
589
static janus_config *config = NULL;
590
static const char *config_folder = NULL;
591
static janus_mutex config_mutex;
592

    
593
/* Useful stuff */
594
static volatile gint initialized = 0, stopping = 0;
595
static janus_callbacks *gateway = NULL;
596
static GThread *handler_thread;
597
static GThread *watchdog;
598
static void *janus_audiobridge_handler(void *data);
599
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data);
600
static void *janus_audiobridge_mixer_thread(void *data);
601
static void *janus_audiobridge_participant_thread(void *data);
602

    
603
typedef struct janus_audiobridge_message {
604
        janus_plugin_session *handle;
605
        char *transaction;
606
        json_t *message;
607
        json_t *jsep;
608
} janus_audiobridge_message;
609
static GAsyncQueue *messages = NULL;
610
static janus_audiobridge_message exit_message;
611

    
612
static void janus_audiobridge_message_free(janus_audiobridge_message *msg) {
613
        if(!msg || msg == &exit_message)
614
                return;
615

    
616
        msg->handle = NULL;
617

    
618
        g_free(msg->transaction);
619
        msg->transaction = NULL;
620
        if(msg->message)
621
                json_decref(msg->message);
622
        msg->message = NULL;
623
        if(msg->jsep)
624
                json_decref(msg->jsep);
625
        msg->jsep = NULL;
626

    
627
        g_free(msg);
628
}
629

    
630

    
631
typedef struct janus_audiobridge_room {
632
        guint64 room_id;                        /* Unique room ID */
633
        gchar *room_name;                        /* Room description */
634
        gchar *room_secret;                        /* Secret needed to manipulate (e.g., destroy) this room */
635
        gchar *room_pin;                        /* Password needed to join this room, if any */
636
        gboolean is_private;                /* Whether this room is 'private' (as in hidden) or not */
637
        uint32_t sampling_rate;                /* Sampling rate of the mix (e.g., 16000 for wideband; can be 8, 12, 16, 24 or 48kHz) */
638
        gboolean record;                        /* Whether this room has to be recorded or not */
639
        gchar *record_file;                        /* Path of the recording file */
640
        FILE *recording;                        /* File to record the room into */
641
        gint64 record_lastupdate;        /* Time when we last updated the wav header */
642
        gboolean destroy;                        /* Value to flag the room for destruction */
643
        GHashTable *participants;        /* Map of participants */
644
        GThread *thread;                        /* Mixer thread for this room */
645
        gint64 destroyed;                        /* When this room has been destroyed */
646
        janus_mutex mutex;                        /* Mutex to lock this room instance */
647
        /* RTP forwarders for this room's mix */
648
        GHashTable *rtp_forwarders;        /* RTP forwarders list (as a hashmap) */
649
        OpusEncoder *rtp_encoder;        /* Opus encoder instance to use for all RTP forwarders */
650
        janus_mutex rtp_mutex;                /* Mutex to lock the RTP forwarders list */
651
        int rtp_udp_sock;                        /* UDP socket to use to forward RTP packets */
652
} janus_audiobridge_room;
653
static GHashTable *rooms;
654
static janus_mutex rooms_mutex;
655
static GList *old_rooms;
656
static char *admin_key = NULL;
657

    
658
typedef struct janus_audiobridge_session {
659
        janus_plugin_session *handle;
660
        gpointer participant;
661
        gboolean started;
662
        gboolean stopping;
663
        volatile gint hangingup;
664
        gint64 destroyed;        /* Time at which this session was marked as destroyed */
665
} janus_audiobridge_session;
666
static GHashTable *sessions;
667
static GList *old_sessions;
668
static janus_mutex sessions_mutex;
669

    
670
typedef struct janus_audiobridge_rtp_context {
671
        /* Needed to fix seq and ts in case of publisher switching */
672
        uint32_t a_last_ssrc, a_last_ts, a_base_ts, a_base_ts_prev;
673
        uint16_t a_last_seq, a_base_seq, a_base_seq_prev;
674
} janus_audiobridge_rtp_context;
675

    
676
typedef struct janus_audiobridge_participant {
677
        janus_audiobridge_session *session;
678
        janus_audiobridge_room *room;        /* Room */
679
        guint64 user_id;                /* Unique ID in the room */
680
        gchar *display;                        /* Display name (just for fun) */
681
        gboolean prebuffering;        /* Whether this participant needs pre-buffering of a few packets (just joined) */
682
        gboolean active;                /* Whether this participant can receive media at all */
683
        gboolean working;                /* Whether this participant is currently encoding/decoding */
684
        gboolean muted;                        /* Whether this participant is muted */
685
        int opus_complexity;        /* Complexity to use in the encoder (by default, DEFAULT_COMPLEXITY) */
686
        /* RTP stuff */
687
        GList *inbuf;                        /* Incoming audio from this participant, as an ordered list of packets */
688
        GAsyncQueue *outbuf;        /* Mixed audio for this participant */
689
        gint64 last_drop;                /* When we last dropped a packet because the imcoming queue was full */
690
        janus_mutex qmutex;                /* Incoming queue mutex */
691
        int opus_pt;                        /* Opus payload type */
692
        janus_audiobridge_rtp_context context;        /* Needed in case the participant changes room */
693
        /* Opus stuff */
694
        OpusEncoder *encoder;                /* Opus encoder instance */
695
        OpusDecoder *decoder;                /* Opus decoder instance */
696
        gboolean reset;                                /* Whether or not the Opus context must be reset, without re-joining the room */
697
        GThread *thread;                        /* Encoding thread for this participant */
698
        janus_recorder *arc;                /* The Janus recorder instance for this user's audio, if enabled */
699
        janus_mutex rec_mutex;                /* Mutex to protect the recorder from race conditions */
700
        gint64 destroyed;                        /* When this participant has been destroyed */
701
} janus_audiobridge_participant;
702

    
703
/* Packets we get from gstreamer and relay */
704
typedef struct janus_audiobridge_rtp_relay_packet {
705
        rtp_header *data;
706
        gint length;
707
        uint32_t ssrc;
708
        uint32_t timestamp;
709
        uint16_t seq_number;
710
} janus_audiobridge_rtp_relay_packet;
711

    
712
/* RTP forwarder instance: address to send to, and current RTP header info */
713
typedef struct janus_audiobridge_rtp_forwarder {
714
        struct sockaddr_in serv_addr;
715
        int payload_type;
716
        uint16_t seq_number;
717
        uint32_t timestamp;
718
        gboolean always_on;
719
} janus_audiobridge_rtp_forwarder;
720
static guint32 janus_audiobridge_rtp_forwarder_add_helper(janus_audiobridge_room *room, const gchar* host, uint16_t port, int pt, gboolean always_on) {
721
        if(room == NULL || host == NULL)
722
                return 0;
723
        janus_audiobridge_rtp_forwarder *rf = g_malloc0(sizeof(janus_audiobridge_rtp_forwarder));
724
        /* Resolve address */
725
        rf->serv_addr.sin_family = AF_INET;
726
        inet_pton(AF_INET, host, &(rf->serv_addr.sin_addr));
727
        rf->serv_addr.sin_port = htons(port);
728
        /* Setup RTP info (we'll use the stream ID as SSRC) */
729
        rf->payload_type = pt;
730
        rf->seq_number = 0;
731
        rf->timestamp = 0;
732
        rf->always_on = always_on;
733
        janus_mutex_lock(&room->rtp_mutex);
734
        guint32 stream_id = janus_random_uint32();
735
        while(g_hash_table_lookup(room->rtp_forwarders, GUINT_TO_POINTER(stream_id)) != NULL) {
736
                stream_id = janus_random_uint32();
737
        }
738
        g_hash_table_insert(room->rtp_forwarders, GUINT_TO_POINTER(stream_id), rf);
739
        janus_mutex_unlock(&room->rtp_mutex);
740
        JANUS_LOG(LOG_VERB, "Added RTP forwarder to room %"SCNu64": %s:%d (ID: %"SCNu32")\n",
741
                room->room_id, host, port, stream_id);
742
        return stream_id;
743
}
744

    
745

    
746
/* Helper to sort incoming RTP packets by sequence numbers */
747
static gint janus_audiobridge_rtp_sort(gconstpointer a, gconstpointer b) {
748
        janus_audiobridge_rtp_relay_packet *pkt1 = (janus_audiobridge_rtp_relay_packet *)a;
749
        janus_audiobridge_rtp_relay_packet *pkt2 = (janus_audiobridge_rtp_relay_packet *)b;
750
        if(pkt1->seq_number < 100 && pkt2->seq_number > 65000) {
751
                /* Sequence number was probably reset, pkt2 is older */
752
                return 1;
753
        } else if(pkt2->seq_number < 100 && pkt1->seq_number > 65000) {
754
                /* Sequence number was probably reset, pkt1 is older */
755
                return -1;
756
        }
757
        /* Simply compare timestamps */
758
        if(pkt1->seq_number < pkt2->seq_number)
759
                return -1;
760
        else if(pkt1->seq_number > pkt2->seq_number)
761
                return 1;
762
        return 0;
763
}
764

    
765
/* SDP offer/answer template */
766
#define sdp_template \
767
                "v=0\r\n" \
768
                "o=- %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n"        /* We need current time here */ \
769
                "s=%s\r\n"                                                        /* Audio bridge name */ \
770
                "t=0 0\r\n" \
771
                "m=audio 1 RTP/SAVPF %d\r\n"                /* Opus payload type */ \
772
                "c=IN IP4 1.1.1.1\r\n" \
773
                "a=rtpmap:%d opus/48000/2\r\n"                /* Opus payload type */ \
774
                "a=fmtp:%d maxplaybackrate=%"SCNu32"; stereo=0; sprop-stereo=0; useinbandfec=0\r\n" \
775
                                                                                        /* Opus payload type and room sampling rate */
776

    
777
/* Helper struct to generate and parse WAVE headers */
778
typedef struct wav_header {
779
        char riff[4];
780
        uint32_t len;
781
        char wave[4];
782
        char fmt[4];
783
        uint32_t formatsize;
784
        uint16_t format;
785
        uint16_t channels;
786
        uint32_t samplerate;
787
        uint32_t avgbyterate;
788
        uint16_t samplebytes;
789
        uint16_t channelbits;
790
        char data[4];
791
        uint32_t blocksize;
792
} wav_header;
793

    
794

    
795
/* Mixer settings */
796
#define DEFAULT_PREBUFFERING        6
797

    
798

    
799
/* Opus settings */                
800
#define        BUFFER_SAMPLES        8000
801
#define        OPUS_SAMPLES        160
802
#define USE_FEC                        0
803
#define DEFAULT_COMPLEXITY        4
804

    
805

    
806
/* Error codes */
807
#define JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR        499
808
#define JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE                480
809
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON        481
810
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST        482
811
#define JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT        483
812
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT        484
813
#define JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM        485
814
#define JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS                486
815
#define JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED                487
816
#define JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR        488
817
#define JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED        489
818
#define JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS                490
819
#define JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED        491
820

    
821

    
822
/* AudioBridge watchdog/garbage collector (sort of) */
823
void *janus_audiobridge_watchdog(void *data);
824
void *janus_audiobridge_watchdog(void *data) {
825
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog started\n");
826
        gint64 now = 0;
827
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
828
                janus_mutex_lock(&sessions_mutex);
829
                /* Iterate on all the sessions */
830
                now = janus_get_monotonic_time();
831
                if(old_sessions != NULL) {
832
                        GList *sl = old_sessions;
833
                        JANUS_LOG(LOG_HUGE, "Checking %d old AudioBridge sessions...\n", g_list_length(old_sessions));
834
                        while(sl) {
835
                                janus_audiobridge_session *session = (janus_audiobridge_session *)sl->data;
836
                                if(!session) {
837
                                        sl = sl->next;
838
                                        continue;
839
                                }
840
                                if(now-session->destroyed >= 5*G_USEC_PER_SEC) {
841
                                        /* We're lazy and actually get rid of the stuff only after a few seconds */
842
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge session\n");
843
                                        GList *rm = sl->next;
844
                                        old_sessions = g_list_delete_link(old_sessions, sl);
845
                                        sl = rm;
846
                                        session->handle = NULL;
847
                                        g_free(session);
848
                                        session = NULL;
849
                                        continue;
850
                                }
851
                                sl = sl->next;
852
                        }
853
                }
854
                janus_mutex_unlock(&sessions_mutex);
855
                janus_mutex_lock(&rooms_mutex);
856
                if(old_rooms != NULL) {
857
                        GList *rl = old_rooms;
858
                        now = janus_get_monotonic_time();
859
                        while(rl) {
860
                                janus_audiobridge_room *audiobridge = (janus_audiobridge_room*)rl->data;
861
                                if(!initialized || stopping){
862
                                        break;
863
                                }
864
                                if(!audiobridge) {
865
                                        rl = rl->next;
866
                                        continue;
867
                                }
868
                                if(now - audiobridge->destroyed >= 5*G_USEC_PER_SEC) {
869
                                        /* Free resources */
870
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge room %"SCNu64"\n", audiobridge->room_id);
871
                                        g_free(audiobridge->room_name);
872
                                        g_free(audiobridge->room_secret);
873
                                        g_free(audiobridge->room_pin);
874
                                        g_free(audiobridge->record_file);
875
                                        g_hash_table_destroy(audiobridge->participants);
876
                                        janus_mutex_lock(&audiobridge->rtp_mutex);
877
                                        if(audiobridge->rtp_udp_sock > 0)
878
                                                close(audiobridge->rtp_udp_sock);
879
                                        if(audiobridge->rtp_encoder)
880
                                                opus_encoder_destroy(audiobridge->rtp_encoder);
881
                                        g_hash_table_destroy(audiobridge->rtp_forwarders);
882
                                        janus_mutex_unlock(&audiobridge->rtp_mutex);
883
                                        g_free(audiobridge);
884
                                        /* Move on */
885
                                        GList *rm = rl->next;
886
                                        old_rooms = g_list_delete_link(old_rooms, rl);
887
                                        rl = rm;
888
                                        continue;
889
                                }
890
                                rl = rl->next;
891
                        }
892
                }
893
                janus_mutex_unlock(&rooms_mutex);
894
                g_usleep(500000);
895
        }
896
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog stopped\n");
897
        return NULL;
898
}
899

    
900

    
901
/* Plugin implementation */
902
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) {
903
        if(g_atomic_int_get(&stopping)) {
904
                /* Still stopping from before */
905
                return -1;
906
        }
907
        if(callback == NULL || config_path == NULL) {
908
                /* Invalid arguments */
909
                return -1;
910
        }
911

    
912
        /* Read configuration */
913
        char filename[255];
914
        g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_AUDIOBRIDGE_PACKAGE);
915
        JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
916
        config = janus_config_parse(filename);
917
        config_folder = config_path;
918
        if(config != NULL)
919
                janus_config_print(config);
920
        janus_mutex_init(&config_mutex);
921
        
922
        rooms = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
923
        janus_mutex_init(&rooms_mutex);
924
        sessions = g_hash_table_new(NULL, NULL);
925
        janus_mutex_init(&sessions_mutex);
926
        messages = g_async_queue_new_full((GDestroyNotify) janus_audiobridge_message_free);
927
        /* This is the callback we'll need to invoke to contact the gateway */
928
        gateway = callback;
929

    
930
        /* Parse configuration to populate the rooms list */
931
        if(config != NULL) {
932
                /* Any admin key to limit who can "create"? */
933
                janus_config_item *key = janus_config_get_item_drilldown(config, "general", "admin_key");
934
                if(key != NULL && key->value != NULL)
935
                        admin_key = g_strdup(key->value);
936
                /* Iterate on all rooms */
937
                GList *cl = janus_config_get_categories(config);
938
                while(cl != NULL) {
939
                        janus_config_category *cat = (janus_config_category *)cl->data;
940
                        if(cat->name == NULL || !strcasecmp(cat->name, "general")) {
941
                                cl = cl->next;
942
                                continue;
943
                        }
944
                        JANUS_LOG(LOG_VERB, "Adding audio room '%s'\n", cat->name);
945
                        janus_config_item *desc = janus_config_get_item(cat, "description");
946
                        janus_config_item *priv = janus_config_get_item(cat, "is_private");
947
                        janus_config_item *sampling = janus_config_get_item(cat, "sampling_rate");
948
                        janus_config_item *secret = janus_config_get_item(cat, "secret");
949
                        janus_config_item *pin = janus_config_get_item(cat, "pin");
950
                        janus_config_item *record = janus_config_get_item(cat, "record");
951
                        janus_config_item *recfile = janus_config_get_item(cat, "record_file");
952
                        if(sampling == NULL || sampling->value == NULL) {
953
                                JANUS_LOG(LOG_ERR, "Can't add the audio room, missing mandatory information...\n");
954
                                cl = cl->next;
955
                                continue;
956
                        }
957
                        /* Create the audio bridge room */
958
                        janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room));
959
                        audiobridge->room_id = g_ascii_strtoull(cat->name, NULL, 0);
960
                        char *description = NULL;
961
                        if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0)
962
                                description = g_strdup(desc->value);
963
                        else
964
                                description = g_strdup(cat->name);
965
                        audiobridge->room_name = description;
966
                        audiobridge->is_private = priv && priv->value && janus_is_true(priv->value);
967
                        audiobridge->sampling_rate = atol(sampling->value);
968
                        switch(audiobridge->sampling_rate) {
969
                                case 8000:
970
                                case 12000:
971
                                case 16000:
972
                                case 24000:
973
                                case 48000:
974
                                        JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
975
                                        break;
976
                                default:
977
                                        JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
978
                                        cl = cl->next;
979
                                        continue;
980
                        }
981
                        if(secret != NULL && secret->value != NULL) {
982
                                audiobridge->room_secret = g_strdup(secret->value);
983
                        }
984
                        if(pin != NULL && pin->value != NULL) {
985
                                audiobridge->room_pin = g_strdup(pin->value);
986
                        }
987
                        audiobridge->record = FALSE;
988
                        if(record && record->value && janus_is_true(record->value))
989
                                audiobridge->record = TRUE;
990
                        if(recfile && recfile->value)
991
                                audiobridge->record_file = g_strdup(recfile->value);
992
                        audiobridge->recording = NULL;
993
                        audiobridge->destroy = 0;
994
                        audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
995
                        audiobridge->destroyed = 0;
996
                        janus_mutex_init(&audiobridge->mutex);
997
                        audiobridge->rtp_forwarders = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_free);
998
                        audiobridge->rtp_encoder = NULL;
999
                        audiobridge->rtp_udp_sock = -1;
1000
                        janus_mutex_init(&audiobridge->rtp_mutex);
1001
                        JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
1002
                                audiobridge->room_id, audiobridge->room_name,
1003
                                audiobridge->is_private ? "private" : "public",
1004
                                audiobridge->room_secret ? audiobridge->room_secret : "no secret",
1005
                                audiobridge->room_pin ? audiobridge->room_pin : "no pin");
1006
                        /* We need a thread for the mix */
1007
                        GError *error = NULL;
1008
                        char tname[16];
1009
                        g_snprintf(tname, sizeof(tname), "mixer %"SCNu64, audiobridge->room_id);
1010
                        audiobridge->thread = g_thread_try_new(tname, &janus_audiobridge_mixer_thread, audiobridge, &error);
1011
                        if(error != NULL) {
1012
                                /* FIXME We should clear some resources... */
1013
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
1014
                        } else {
1015
                                janus_mutex_lock(&rooms_mutex);
1016
                                g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1017
                                janus_mutex_unlock(&rooms_mutex);
1018
                        }
1019
                        cl = cl->next;
1020
                }
1021
                /* Done: we keep the configuration file open in case we get a "create" or "destroy" with permanent=true */
1022
        }
1023

    
1024
        /* Show available rooms */
1025
        janus_mutex_lock(&rooms_mutex);
1026
        GHashTableIter iter;
1027
        gpointer value;
1028
        g_hash_table_iter_init(&iter, rooms);
1029
        while (g_hash_table_iter_next(&iter, NULL, &value)) {
1030
                janus_audiobridge_room *ar = value;
1031
                JANUS_LOG(LOG_VERB, "  ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n",
1032
                        ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT");
1033
        }
1034
        janus_mutex_unlock(&rooms_mutex);
1035

    
1036
        g_atomic_int_set(&initialized, 1);
1037

    
1038
        GError *error = NULL;
1039
        /* Start the sessions watchdog */
1040
        watchdog = g_thread_try_new("audiobridge watchdog", &janus_audiobridge_watchdog, NULL, &error);
1041
        if(error != NULL) {
1042
                g_atomic_int_set(&initialized, 0);
1043
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge watchdog thread...\n", error->code, error->message ? error->message : "??");
1044
                janus_config_destroy(config);
1045
                return -1;
1046
        }
1047
        /* Launch the thread that will handle incoming messages */
1048
        handler_thread = g_thread_try_new("audiobridge handler", janus_audiobridge_handler, NULL, &error);
1049
        if(error != NULL) {
1050
                g_atomic_int_set(&initialized, 0);
1051
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", error->code, error->message ? error->message : "??");
1052
                janus_config_destroy(config);
1053
                return -1;
1054
        }
1055
        JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_AUDIOBRIDGE_NAME);
1056
        return 0;
1057
}
1058

    
1059
void janus_audiobridge_destroy(void) {
1060
        if(!g_atomic_int_get(&initialized))
1061
                return;
1062
        g_atomic_int_set(&stopping, 1);
1063

    
1064
        g_async_queue_push(messages, &exit_message);
1065
        if(handler_thread != NULL) {
1066
                g_thread_join(handler_thread);
1067
                handler_thread = NULL;
1068
        }
1069
        if(watchdog != NULL) {
1070
                g_thread_join(watchdog);
1071
                watchdog = NULL;
1072
        }
1073
        /* FIXME We should destroy the sessions cleanly */
1074
        janus_mutex_lock(&sessions_mutex);
1075
        g_hash_table_destroy(sessions);
1076
        janus_mutex_unlock(&sessions_mutex);
1077
        janus_mutex_lock(&rooms_mutex);
1078
        g_hash_table_destroy(rooms);
1079
        janus_mutex_unlock(&rooms_mutex);
1080
        g_async_queue_unref(messages);
1081
        messages = NULL;
1082
        sessions = NULL;
1083

    
1084
        janus_config_destroy(config);
1085
        g_free(admin_key);
1086

    
1087
        g_atomic_int_set(&initialized, 0);
1088
        g_atomic_int_set(&stopping, 0);
1089
        JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_AUDIOBRIDGE_NAME);
1090
}
1091

    
1092
int janus_audiobridge_get_api_compatibility(void) {
1093
        /* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
1094
        return JANUS_PLUGIN_API_VERSION;
1095
}
1096

    
1097
int janus_audiobridge_get_version(void) {
1098
        return JANUS_AUDIOBRIDGE_VERSION;
1099
}
1100

    
1101
const char *janus_audiobridge_get_version_string(void) {
1102
        return JANUS_AUDIOBRIDGE_VERSION_STRING;
1103
}
1104

    
1105
const char *janus_audiobridge_get_description(void) {
1106
        return JANUS_AUDIOBRIDGE_DESCRIPTION;
1107
}
1108

    
1109
const char *janus_audiobridge_get_name(void) {
1110
        return JANUS_AUDIOBRIDGE_NAME;
1111
}
1112

    
1113
const char *janus_audiobridge_get_author(void) {
1114
        return JANUS_AUDIOBRIDGE_AUTHOR;
1115
}
1116

    
1117
const char *janus_audiobridge_get_package(void) {
1118
        return JANUS_AUDIOBRIDGE_PACKAGE;
1119
}
1120

    
1121
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error) {
1122
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1123
                *error = -1;
1124
                return;
1125
        }        
1126
        janus_audiobridge_session *session = (janus_audiobridge_session *)g_malloc0(sizeof(janus_audiobridge_session));
1127
        session->handle = handle;
1128
        session->started = FALSE;
1129
        session->stopping = FALSE;
1130
        session->destroyed = 0;
1131
        g_atomic_int_set(&session->hangingup, 0);
1132
        handle->plugin_handle = session;
1133
        janus_mutex_lock(&sessions_mutex);
1134
        g_hash_table_insert(sessions, handle, session);
1135
        janus_mutex_unlock(&sessions_mutex);
1136

    
1137
        return;
1138
}
1139

    
1140
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error) {
1141
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1142
                *error = -1;
1143
                return;
1144
        }        
1145
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle; 
1146
        if(!session) {
1147
                JANUS_LOG(LOG_ERR, "No AudioBridge session associated with this handle...\n");
1148
                *error = -2;
1149
                return;
1150
        }
1151
        JANUS_LOG(LOG_VERB, "Removing AudioBridge session...\n");
1152
        janus_mutex_lock(&sessions_mutex);
1153
        if(!session->destroyed) {
1154
                g_hash_table_remove(sessions, handle);
1155
                janus_audiobridge_hangup_media(handle);
1156
                session->destroyed = janus_get_monotonic_time();
1157
                /* Cleaning up and removing the session is done in a lazy way */
1158
                old_sessions = g_list_append(old_sessions, session);
1159
        }
1160
        janus_mutex_unlock(&sessions_mutex);
1161

    
1162
        return;
1163
}
1164

    
1165
json_t *janus_audiobridge_query_session(janus_plugin_session *handle) {
1166
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1167
                return NULL;
1168
        }        
1169
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1170
        if(!session) {
1171
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1172
                return NULL;
1173
        }
1174
        /* Show the participant/room info, if any */
1175
        json_t *info = json_object();
1176
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1177
        json_object_set_new(info, "state", json_string(participant && participant->room ? "inroom" : "idle"));
1178
        if(participant) {
1179
                janus_mutex_lock(&rooms_mutex);
1180
                janus_audiobridge_room *room = participant->room;
1181
                if(room != NULL)
1182
                        json_object_set_new(info, "room", json_integer(room->room_id));
1183
                janus_mutex_unlock(&rooms_mutex);
1184
                json_object_set_new(info, "id", json_integer(participant->user_id));
1185
                if(participant->display)
1186
                        json_object_set_new(info, "display", json_string(participant->display));
1187
                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
1188
                json_object_set_new(info, "active", participant->active ? json_true() : json_false());
1189
                json_object_set_new(info, "pre-buffering", participant->prebuffering ? json_true() : json_false());
1190
                if(participant->inbuf) {
1191
                        janus_mutex_lock(&participant->qmutex);
1192
                        json_object_set_new(info, "queue-in", json_integer(g_list_length(participant->inbuf)));
1193
                        janus_mutex_unlock(&participant->qmutex);
1194
                }
1195
                if(participant->outbuf)
1196
                        json_object_set_new(info, "queue-out", json_integer(g_async_queue_length(participant->outbuf)));
1197
                if(participant->last_drop > 0)
1198
                        json_object_set_new(info, "last-drop", json_integer(participant->last_drop));
1199
                if(participant->arc && participant->arc->filename)
1200
                        json_object_set_new(info, "audio-recording", json_string(participant->arc->filename));
1201
        }
1202
        json_object_set_new(info, "started", session->started ? json_true() : json_false());
1203
        json_object_set_new(info, "destroyed", json_integer(session->destroyed));
1204
        return info;
1205
}
1206

    
1207
struct janus_plugin_result *janus_audiobridge_handle_message(janus_plugin_session *handle, char *transaction, json_t *message, json_t *jsep) {
1208
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1209
                return janus_plugin_result_new(JANUS_PLUGIN_ERROR, g_atomic_int_get(&stopping) ? "Shutting down" : "Plugin not initialized", NULL);
1210

    
1211
        /* Pre-parse the message */
1212
        int error_code = 0;
1213
        char error_cause[512];
1214
        json_t *root = message;
1215
        json_t *response = NULL;
1216
        
1217
        if(message == NULL) {
1218
                JANUS_LOG(LOG_ERR, "No message??\n");
1219
                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
1220
                g_snprintf(error_cause, 512, "%s", "No message??");
1221
                goto plugin_response;
1222
        }
1223

    
1224
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1225
        if(!session) {
1226
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1227
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1228
                g_snprintf(error_cause, 512, "%s", "session associated with this handle...");
1229
                goto plugin_response;
1230
        }
1231
        if(session->destroyed) {
1232
                JANUS_LOG(LOG_ERR, "Session has already been marked as destroyed...\n");
1233
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1234
                g_snprintf(error_cause, 512, "%s", "Session has already been marked as destroyed...");
1235
                goto plugin_response;
1236
        }
1237
        if(!json_is_object(root)) {
1238
                JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
1239
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON;
1240
                g_snprintf(error_cause, 512, "JSON error: not an object");
1241
                goto plugin_response;
1242
        }
1243
        /* Get the request first */
1244
        JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
1245
                error_code, error_cause, TRUE,
1246
                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1247
        if(error_code != 0)
1248
                goto plugin_response;
1249
        json_t *request = json_object_get(root, "request");
1250
        /* Some requests ('create', 'destroy', 'exists', 'list') can be handled synchronously */
1251
        const char *request_text = json_string_value(request);
1252
        if(!strcasecmp(request_text, "create")) {
1253
                /* Create a new audiobridge */
1254
                JANUS_LOG(LOG_VERB, "Creating a new audiobridge\n");
1255
                JANUS_VALIDATE_JSON_OBJECT(root, create_parameters,
1256
                        error_code, error_cause, TRUE,
1257
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1258
                if(error_code != 0)
1259
                        goto plugin_response;
1260
                if(admin_key != NULL) {
1261
                        /* An admin key was specified: make sure it was provided, and that it's valid */
1262
                        JANUS_VALIDATE_JSON_OBJECT(root, adminkey_parameters,
1263
                                error_code, error_cause, TRUE,
1264
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1265
                        if(error_code != 0)
1266
                                goto plugin_response;
1267
                        JANUS_CHECK_SECRET(admin_key, root, "admin_key", error_code, error_cause,
1268
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1269
                        if(error_code != 0)
1270
                                goto plugin_response;
1271
                }
1272
                json_t *desc = json_object_get(root, "description");
1273
                json_t *secret = json_object_get(root, "secret");
1274
                json_t *pin = json_object_get(root, "pin");
1275
                json_t *is_private = json_object_get(root, "is_private");
1276
                json_t *sampling = json_object_get(root, "sampling");
1277
                json_t *record = json_object_get(root, "record");
1278
                json_t *recfile = json_object_get(root, "record_file");
1279
                json_t *permanent = json_object_get(root, "permanent");
1280
                gboolean save = permanent ? json_is_true(permanent) : FALSE;
1281
                if(save && config == NULL) {
1282
                        JANUS_LOG(LOG_ERR, "No configuration file, can't create permanent room\n");
1283
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1284
                        g_snprintf(error_cause, 512, "No configuration file, can't create permanent room");
1285
                        goto plugin_response;
1286
                }
1287
                guint64 room_id = 0;
1288
                json_t *room = json_object_get(root, "room");
1289
                room_id = json_integer_value(room);
1290
                if(room_id == 0) {
1291
                        JANUS_LOG(LOG_WARN, "Desired room ID is 0, which is not allowed... picking random ID instead\n");
1292
                }
1293
                janus_mutex_lock(&rooms_mutex);
1294
                if(room_id > 0) {
1295
                        /* Let's make sure the room doesn't exist already */
1296
                        if(g_hash_table_lookup(rooms, &room_id) != NULL) {
1297
                                /* It does... */
1298
                                janus_mutex_unlock(&rooms_mutex);
1299
                                JANUS_LOG(LOG_ERR, "Room %"SCNu64" already exists!\n", room_id);
1300
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS;
1301
                                g_snprintf(error_cause, 512, "Room %"SCNu64" already exists", room_id);
1302
                                goto plugin_response;
1303
                        }
1304
                }
1305
                /* Create the audio bridge room */
1306
                janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room));
1307
                /* Generate a random ID */
1308
                if(room_id == 0) {
1309
                        while(room_id == 0) {
1310
                                room_id = janus_random_uint64();
1311
                                if(g_hash_table_lookup(rooms, &room_id) != NULL) {
1312
                                        /* Room ID already taken, try another one */
1313
                                        room_id = 0;
1314
                                }
1315
                        }
1316
                }
1317
                audiobridge->room_id = room_id;
1318
                char *description = NULL;
1319
                if(desc != NULL && strlen(json_string_value(desc)) > 0) {
1320
                        description = g_strdup(json_string_value(desc));
1321
                } else {
1322
                        char roomname[255];
1323
                        g_snprintf(roomname, 255, "Room %"SCNu64"", audiobridge->room_id);
1324
                        description = g_strdup(roomname);
1325
                }
1326
                audiobridge->room_name = description;
1327
                audiobridge->is_private = is_private ? json_is_true(is_private) : FALSE;
1328
                if(secret)
1329
                        audiobridge->room_secret = g_strdup(json_string_value(secret));
1330
                if(pin)
1331
                        audiobridge->room_pin = g_strdup(json_string_value(pin));
1332
                if(sampling)
1333
                        audiobridge->sampling_rate = json_integer_value(sampling);
1334
                else
1335
                        audiobridge->sampling_rate = 16000;
1336
                switch(audiobridge->sampling_rate) {
1337
                        case 8000:
1338
                        case 12000:
1339
                        case 16000:
1340
                        case 24000:
1341
                        case 48000:
1342
                                JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
1343
                                break;
1344
                        default:
1345
                                janus_mutex_unlock(&rooms_mutex);
1346
                                JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
1347
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1348
                                g_snprintf(error_cause, 512, "We currently only support 16kHz (wideband) as a sampling rate for audio rooms, %"SCNu32" TBD...", audiobridge->sampling_rate);
1349
                                goto plugin_response;
1350
                }
1351
                audiobridge->record = FALSE;
1352
                if(record && json_is_true(record))
1353
                        audiobridge->record = TRUE;
1354
                if(recfile)
1355
                        audiobridge->record_file = g_strdup(json_string_value(recfile));
1356
                audiobridge->recording = NULL;
1357
                audiobridge->destroy = 0;
1358
                audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
1359
                audiobridge->destroyed = 0;
1360
                janus_mutex_init(&audiobridge->mutex);
1361
                audiobridge->rtp_forwarders = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_free);
1362
                audiobridge->rtp_encoder = NULL;
1363
                audiobridge->rtp_udp_sock = -1;
1364
                janus_mutex_init(&audiobridge->rtp_mutex);
1365
                g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1366
                JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
1367
                        audiobridge->room_id, audiobridge->room_name,
1368
                        audiobridge->is_private ? "private" : "public",
1369
                        audiobridge->room_secret ? audiobridge->room_secret : "no secret",
1370
                        audiobridge->room_pin ? audiobridge->room_pin : "no pin");
1371
                /* We need a thread for the mix */
1372
                GError *error = NULL;
1373
                char tname[16];
1374
                g_snprintf(tname, sizeof(tname), "mixer %"SCNu64, audiobridge->room_id);
1375
                audiobridge->thread = g_thread_try_new(tname, &janus_audiobridge_mixer_thread, audiobridge, &error);
1376
                if(error != NULL) {
1377
                        janus_mutex_unlock(&rooms_mutex);
1378
                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
1379
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1380
                        g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the mixer thread", error->code, error->message ? error->message : "??");
1381
                        g_free(audiobridge->room_name);
1382
                        g_free(audiobridge->room_secret);
1383
                        g_free(audiobridge->record_file);
1384
                        g_hash_table_destroy(audiobridge->participants);
1385
                        g_free(audiobridge);
1386
                        goto plugin_response;
1387
                } else {
1388
                        g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1389
                }
1390
                if(save) {
1391
                        /* This room is permanent: save to the configuration file too
1392
                         * FIXME: We should check if anything fails... */
1393
                        JANUS_LOG(LOG_VERB, "Saving room %"SCNu64" permanently in config file\n", audiobridge->room_id);
1394
                        janus_mutex_lock(&config_mutex);
1395
                        char cat[BUFSIZ], value[BUFSIZ];
1396
                        /* The room ID is the category */
1397
                        g_snprintf(cat, BUFSIZ, "%"SCNu64, audiobridge->room_id);
1398
                        janus_config_add_category(config, cat);
1399
                        /* Now for the values */
1400
                        janus_config_add_item(config, cat, "description", audiobridge->room_name);
1401
                        if(audiobridge->is_private)
1402
                                janus_config_add_item(config, cat, "is_private", "yes");
1403
                        g_snprintf(value, BUFSIZ, "%"SCNu32, audiobridge->sampling_rate);
1404
                        janus_config_add_item(config, cat, "sampling_rate", value);
1405
                        if(audiobridge->room_secret)
1406
                                janus_config_add_item(config, cat, "secret", audiobridge->room_secret);
1407
                        if(audiobridge->room_pin)
1408
                                janus_config_add_item(config, cat, "pin", audiobridge->room_pin);
1409
                        if(audiobridge->record_file) {
1410
                                janus_config_add_item(config, cat, "record", "yes");
1411
                                janus_config_add_item(config, cat, "record_file", audiobridge->record_file);
1412
                        }
1413
                        /* Save modified configuration */
1414
                        janus_config_save(config, config_folder, JANUS_AUDIOBRIDGE_PACKAGE);
1415
                        janus_mutex_unlock(&config_mutex);
1416
                }
1417
                /* Send info back */
1418
                response = json_object();
1419
                json_object_set_new(response, "audiobridge", json_string("created"));
1420
                json_object_set_new(response, "room", json_integer(audiobridge->room_id));
1421
                janus_mutex_unlock(&rooms_mutex);
1422
                goto plugin_response;
1423
        } else if(!strcasecmp(request_text, "destroy")) {
1424
                JANUS_LOG(LOG_VERB, "Attempt to destroy an existing audiobridge room\n");
1425
                JANUS_VALIDATE_JSON_OBJECT(root, destroy_parameters,
1426
                        error_code, error_cause, TRUE,
1427
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1428
                if(error_code != 0)
1429
                        goto plugin_response;
1430
                json_t *room = json_object_get(root, "room");
1431
                json_t *permanent = json_object_get(root, "permanent");
1432
                gboolean save = permanent ? json_is_true(permanent) : FALSE;
1433
                if(save && config == NULL) {
1434
                        JANUS_LOG(LOG_ERR, "No configuration file, can't destroy room permanently\n");
1435
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1436
                        g_snprintf(error_cause, 512, "No configuration file, can't destroy room permanently");
1437
                        goto plugin_response;
1438
                }
1439
                guint64 room_id = json_integer_value(room);
1440
                janus_mutex_lock(&rooms_mutex);
1441
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1442
                if(audiobridge == NULL) {
1443
                        janus_mutex_unlock(&rooms_mutex);
1444
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1445
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1446
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1447
                        goto plugin_response;
1448
                }
1449
                janus_mutex_lock(&audiobridge->mutex);
1450
                /* A secret may be required for this action */
1451
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1452
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1453
                if(error_code != 0) {
1454
                        janus_mutex_unlock(&audiobridge->mutex);
1455
                        janus_mutex_unlock(&rooms_mutex);
1456
                        goto plugin_response;
1457
                }
1458
                /* Remove room */
1459
                g_hash_table_remove(rooms, &room_id);
1460
                if(save) {
1461
                        /* This change is permanent: save to the configuration file too
1462
                         * FIXME: We should check if anything fails... */
1463
                        JANUS_LOG(LOG_VERB, "Destroying room %"SCNu64" permanently in config file\n", room_id);
1464
                        janus_mutex_lock(&config_mutex);
1465
                        char cat[BUFSIZ];
1466
                        /* The room ID is the category */
1467
                        g_snprintf(cat, BUFSIZ, "%"SCNu64, room_id);
1468
                        janus_config_remove_category(config, cat);
1469
                        /* Save modified configuration */
1470
                        janus_config_save(config, config_folder, JANUS_AUDIOBRIDGE_PACKAGE);
1471
                        janus_mutex_unlock(&config_mutex);
1472
                }
1473
                /* Prepare response/notification */
1474
                response = json_object();
1475
                json_object_set_new(response, "audiobridge", json_string("destroyed"));
1476
                json_object_set_new(response, "room", json_integer(room_id));
1477
                /* Notify all participants that the fun is over, and that they'll be kicked */
1478
                JANUS_LOG(LOG_VERB, "Notifying all participants\n");
1479
                GHashTableIter iter;
1480
                gpointer value;
1481
                g_hash_table_iter_init(&iter, audiobridge->participants);
1482
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1483
                        janus_audiobridge_participant *p = value;
1484
                        if(p && p->session) {
1485
                                p->room = NULL;
1486
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, response, NULL);
1487
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1488
                                /* Get rid of queued packets */
1489
                                janus_mutex_lock(&p->qmutex);
1490
                                p->active = FALSE;
1491
                                while(p->inbuf) {
1492
                                        GList *first = g_list_first(p->inbuf);
1493
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1494
                                        p->inbuf = g_list_remove_link(p->inbuf, first);
1495
                                        first = NULL;
1496
                                        if(pkt == NULL)
1497
                                                continue;
1498
                                        if(pkt->data)
1499
                                                g_free(pkt->data);
1500
                                        pkt->data = NULL;
1501
                                        g_free(pkt);
1502
                                        pkt = NULL;
1503
                                }
1504
                                janus_mutex_unlock(&p->qmutex);
1505
                        }
1506
                }
1507
                JANUS_LOG(LOG_VERB, "Waiting for the mixer thread to complete...\n");
1508
                audiobridge->destroyed = janus_get_monotonic_time();
1509
                janus_mutex_unlock(&audiobridge->mutex);
1510
                janus_mutex_unlock(&rooms_mutex);
1511
                g_thread_join(audiobridge->thread);
1512
                /* Done */
1513
                JANUS_LOG(LOG_VERB, "Audiobridge room destroyed\n");
1514
                goto plugin_response;
1515
        } else if(!strcasecmp(request_text, "list")) {
1516
                /* List all rooms (but private ones) and their details (except for the secret, of course...) */
1517
                json_t *list = json_array();
1518
                JANUS_LOG(LOG_VERB, "Request for the list for all video rooms\n");
1519
                janus_mutex_lock(&rooms_mutex);
1520
                GHashTableIter iter;
1521
                gpointer value;
1522
                g_hash_table_iter_init(&iter, rooms);
1523
                while(g_hash_table_iter_next(&iter, NULL, &value)) {
1524
                        janus_audiobridge_room *room = value;
1525
                        if(!room)
1526
                                continue;
1527
                        janus_mutex_lock(&room->mutex);
1528
                        if(room->is_private) {
1529
                                /* Skip private room */
1530
                                janus_mutex_unlock(&room->mutex);
1531
                                JANUS_LOG(LOG_VERB, "Skipping private room '%s'\n", room->room_name);
1532
                                continue;
1533
                        }
1534
                        json_t *rl = json_object();
1535
                        json_object_set_new(rl, "room", json_integer(room->room_id));
1536
                        json_object_set_new(rl, "description", json_string(room->room_name));
1537
                        json_object_set_new(rl, "sampling_rate", json_integer(room->sampling_rate));
1538
                        json_object_set_new(rl, "record", room->record ? json_true() : json_false());
1539
                        /* TODO: Possibly list participant details... or make it a separate API call for a specific room */
1540
                        json_object_set_new(rl, "num_participants", json_integer(g_hash_table_size(room->participants)));
1541
                        json_array_append_new(list, rl);
1542
                        janus_mutex_unlock(&room->mutex);
1543
                }
1544
                janus_mutex_unlock(&rooms_mutex);
1545
                response = json_object();
1546
                json_object_set_new(response, "audiobridge", json_string("success"));
1547
                json_object_set_new(response, "list", list);
1548
                goto plugin_response;
1549
        } else if(!strcasecmp(request_text, "exists")) {
1550
                /* Check whether a given room exists or not, returns true/false */        
1551
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
1552
                        error_code, error_cause, TRUE,
1553
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1554
                if(error_code != 0)
1555
                        goto plugin_response;
1556
                json_t *room = json_object_get(root, "room");
1557
                guint64 room_id = json_integer_value(room);
1558
                janus_mutex_lock(&rooms_mutex);
1559
                gboolean room_exists = g_hash_table_contains(rooms, &room_id);
1560
                janus_mutex_unlock(&rooms_mutex);
1561
                response = json_object();
1562
                json_object_set_new(response, "audiobridge", json_string("success"));
1563
                json_object_set_new(response, "room", json_integer(room_id));
1564
                json_object_set_new(response, "exists", room_exists ? json_true() : json_false());
1565
                goto plugin_response;
1566
        } else if(!strcasecmp(request_text, "listparticipants")) {
1567
                /* List all participants in a room */        
1568
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
1569
                        error_code, error_cause, TRUE,
1570
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1571
                if(error_code != 0)
1572
                        goto plugin_response;
1573
                json_t *room = json_object_get(root, "room");
1574
                guint64 room_id = json_integer_value(room);
1575
                janus_mutex_lock(&rooms_mutex);
1576
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1577
                if(audiobridge == NULL) {
1578
                        janus_mutex_unlock(&rooms_mutex);
1579
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1580
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1581
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1582
                        goto plugin_response;
1583
                }
1584
                janus_mutex_lock(&audiobridge->mutex);
1585
                if(audiobridge->destroyed) {
1586
                        janus_mutex_unlock(&audiobridge->mutex);
1587
                        janus_mutex_unlock(&rooms_mutex);
1588
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1589
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1590
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1591
                        goto plugin_response;
1592
                }
1593
                /* Return a list of all participants */
1594
                json_t *list = json_array();
1595
                GHashTableIter iter;
1596
                gpointer value;
1597
                g_hash_table_iter_init(&iter, audiobridge->participants);
1598
                while (!audiobridge->destroyed && g_hash_table_iter_next(&iter, NULL, &value)) {
1599
                        janus_audiobridge_participant *p = value;
1600
                        json_t *pl = json_object();
1601
                        json_object_set_new(pl, "id", json_integer(p->user_id));
1602
                        if(p->display)
1603
                                json_object_set_new(pl, "display", json_string(p->display));
1604
                        json_object_set_new(pl, "muted", p->muted ? json_true() : json_false());
1605
                        json_array_append_new(list, pl);
1606
                }
1607
                janus_mutex_unlock(&audiobridge->mutex);
1608
                janus_mutex_unlock(&rooms_mutex);
1609
                response = json_object();
1610
                json_object_set_new(response, "audiobridge", json_string("participants"));
1611
                json_object_set_new(response, "room", json_integer(room_id));
1612
                json_object_set_new(response, "participants", list);
1613
                goto plugin_response;
1614
        } else if(!strcasecmp(request_text, "resetdecoder")) {
1615
                /* Mark the Opus decoder for the participant invalid and recreate it */        
1616
                janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1617
                if(participant == NULL || participant->room == NULL) {
1618
                        JANUS_LOG(LOG_ERR, "Can't reset (not in a room)\n");
1619
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
1620
                        g_snprintf(error_cause, 512, "Can't reset (not in a room)");
1621
                        goto plugin_response;
1622
                }
1623
                participant->reset = TRUE;
1624
                response = json_object();
1625
                json_object_set_new(response, "audiobridge", json_string("success"));
1626
                goto plugin_response;
1627
        } else if(!strcasecmp(request_text, "rtp_forward")) {
1628
                JANUS_VALIDATE_JSON_OBJECT(root, rtp_forward_parameters,
1629
                        error_code, error_cause, TRUE,
1630
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1631
                if(error_code != 0)
1632
                        goto plugin_response;
1633
                /* Parse arguments */
1634
                guint64 room_id = json_integer_value(json_object_get(root, "room"));
1635
                int ptype = 100;
1636
                json_t *pt = json_object_get(root, "ptype");
1637
                if(pt)
1638
                        ptype = json_integer_value(pt);
1639
                uint16_t port = json_integer_value(json_object_get(root, "port"));
1640
                json_t *json_host = json_object_get(root, "host");
1641
                const gchar* host = json_string_value(json_host);
1642
                json_t *always = json_object_get(root, "always_on");
1643
                gboolean always_on = always ? json_is_true(always) : FALSE;
1644
                /* Update room */
1645
                janus_mutex_lock(&rooms_mutex);
1646
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1647
                if(audiobridge == NULL) {
1648
                        janus_mutex_unlock(&rooms_mutex);
1649
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1650
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1651
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1652
                        goto plugin_response;
1653
                }
1654
                /* A secret may be required for this action */
1655
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1656
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1657
                if(error_code != 0) {
1658
                        janus_mutex_unlock(&rooms_mutex);
1659
                        goto plugin_response;
1660
                }
1661
                janus_mutex_lock(&audiobridge->mutex);
1662
                if(audiobridge->destroyed) {
1663
                        janus_mutex_unlock(&audiobridge->mutex);
1664
                        janus_mutex_unlock(&rooms_mutex);
1665
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1666
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1667
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1668
                        goto plugin_response;
1669
                }
1670
                /* Create UDP socket, if needed */
1671
                if(audiobridge->rtp_udp_sock <= 0) {
1672
                        audiobridge->rtp_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1673
                        if(audiobridge->rtp_udp_sock <= 0) {
1674
                                janus_mutex_unlock(&audiobridge->mutex);
1675
                                janus_mutex_unlock(&rooms_mutex);
1676
                                JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP forwarder (room %"SCNu64")\n", room_id);
1677
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1678
                                g_snprintf(error_cause, 512, "Could not open UDP socket for RTP forwarder");
1679
                                goto plugin_response;
1680
                        }
1681
                }
1682
                /* Create Opus encoder, if needed */
1683
                if(audiobridge->rtp_encoder == NULL) {
1684
                        int error = 0;
1685
                        audiobridge->rtp_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
1686
                        if(error != OPUS_OK) {
1687
                                janus_mutex_unlock(&audiobridge->mutex);
1688
                                janus_mutex_unlock(&rooms_mutex);
1689
                                JANUS_LOG(LOG_ERR, "Error creating Opus encoder for RTP forwarder (room %"SCNu64")\n", room_id);
1690
                                error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
1691
                                g_snprintf(error_cause, 512, "Error creating Opus decoder for RTP forwarder");
1692
                                goto plugin_response;
1693
                        }
1694
                        if(audiobridge->sampling_rate == 8000) {
1695
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
1696
                        } else if(audiobridge->sampling_rate == 12000) {
1697
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
1698
                        } else if(audiobridge->sampling_rate == 16000) {
1699
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
1700
                        } else if(audiobridge->sampling_rate == 24000) {
1701
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
1702
                        } else if(audiobridge->sampling_rate == 48000) {
1703
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
1704
                        } else {
1705
                                JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
1706
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
1707
                        }
1708
                }
1709
                guint32 stream_id = janus_audiobridge_rtp_forwarder_add_helper(audiobridge, host, port, ptype, always_on);
1710
                janus_mutex_unlock(&audiobridge->mutex);
1711
                janus_mutex_unlock(&rooms_mutex);
1712
                /* Done, prepare response */
1713
                response = json_object();
1714
                json_object_set_new(response, "audiobridge", json_string("success"));
1715
                json_object_set_new(response, "room", json_integer(room_id));
1716
                json_object_set_new(response, "stream_id", json_integer(stream_id));
1717
                goto plugin_response;
1718
        } else if(!strcasecmp(request_text, "stop_rtp_forward")) {
1719
                JANUS_VALIDATE_JSON_OBJECT(root, stop_rtp_forward_parameters,
1720
                        error_code, error_cause, TRUE,
1721
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1722
                if(error_code != 0)
1723
                        goto plugin_response;
1724
                /* Parse parameters */
1725
                guint64 room_id = json_integer_value(json_object_get(root, "room"));
1726
                guint32 stream_id = json_integer_value(json_object_get(root, "stream_id"));
1727
                /* Update room */
1728
                /* Update room */
1729
                janus_mutex_lock(&rooms_mutex);
1730
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1731
                if(audiobridge == NULL) {
1732
                        janus_mutex_unlock(&rooms_mutex);
1733
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1734
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1735
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1736
                        goto plugin_response;
1737
                }
1738
                /* A secret may be required for this action */
1739
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1740
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1741
                if(error_code != 0) {
1742
                        janus_mutex_unlock(&rooms_mutex);
1743
                        goto plugin_response;
1744
                }
1745
                janus_mutex_lock(&audiobridge->mutex);
1746
                if(audiobridge->destroyed) {
1747
                        janus_mutex_unlock(&audiobridge->mutex);
1748
                        janus_mutex_unlock(&rooms_mutex);
1749
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1750
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1751
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1752
                        goto plugin_response;
1753
                }
1754
                janus_mutex_lock(&audiobridge->rtp_mutex);
1755
                g_hash_table_remove(audiobridge->rtp_forwarders, GUINT_TO_POINTER(stream_id));
1756
                janus_mutex_unlock(&audiobridge->rtp_mutex);
1757
                janus_mutex_unlock(&audiobridge->mutex);
1758
                janus_mutex_unlock(&rooms_mutex);
1759
                response = json_object();
1760
                json_object_set_new(response, "audiobridge", json_string("success"));
1761
                json_object_set_new(response, "room", json_integer(room_id));
1762
                json_object_set_new(response, "stream_id", json_integer(stream_id));
1763
                goto plugin_response;
1764
        } else if(!strcasecmp(request_text, "listforwarders")) {
1765
                /* List all forwarders in a room */
1766
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
1767
                        error_code, error_cause, TRUE,
1768
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1769
                if(error_code != 0)
1770
                        goto plugin_response;
1771
                json_t *room = json_object_get(root, "room");
1772
                guint64 room_id = json_integer_value(room);
1773
                janus_mutex_lock(&rooms_mutex);
1774
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1775
                if(audiobridge == NULL) {
1776
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1777
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1778
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1779
                        janus_mutex_unlock(&rooms_mutex);
1780
                        goto plugin_response;
1781
                }
1782
                if(audiobridge->destroyed) {
1783
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1784
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1785
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1786
                        janus_mutex_unlock(&rooms_mutex);
1787
                        goto plugin_response;
1788
                }
1789
                /* A secret may be required for this action */
1790
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1791
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1792
                if(error_code != 0) {
1793
                        janus_mutex_unlock(&rooms_mutex);
1794
                        goto plugin_response;
1795
                }
1796
                /* Return a list of all forwarders */
1797
                json_t *list = json_array();
1798
                GHashTableIter iter;
1799
                gpointer key, value;
1800
                janus_mutex_lock(&audiobridge->rtp_mutex);
1801
                g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
1802
                while(g_hash_table_iter_next(&iter, &key, &value)) {
1803
                        guint32 stream_id = GPOINTER_TO_UINT(key);
1804
                        janus_audiobridge_rtp_forwarder *rf = (janus_audiobridge_rtp_forwarder *)value;
1805
                        json_t *fl = json_object();
1806
                        json_object_set_new(fl, "stream_id", json_integer(stream_id));
1807
                        json_object_set_new(fl, "ip", json_string(inet_ntoa(rf->serv_addr.sin_addr)));
1808
                        json_object_set_new(fl, "port", json_integer(ntohs(rf->serv_addr.sin_port)));
1809
                        json_object_set_new(fl, "ptype", json_integer(rf->payload_type));
1810
                        json_object_set_new(fl, "always_on", rf->always_on ? json_true() : json_false());
1811
                        json_array_append_new(list, fl);
1812
                }
1813
                janus_mutex_unlock(&audiobridge->rtp_mutex);
1814
                janus_mutex_unlock(&rooms_mutex);
1815
                response = json_object();
1816
                json_object_set_new(response, "audiobridge", json_string("forwarders"));
1817
                json_object_set_new(response, "room", json_integer(room_id));
1818
                json_object_set_new(response, "rtp_forwarders", list);
1819
                goto plugin_response;
1820
        } else if(!strcasecmp(request_text, "join") || !strcasecmp(request_text, "configure")
1821
                        || !strcasecmp(request_text, "changeroom") || !strcasecmp(request_text, "leave")) {
1822
                /* These messages are handled asynchronously */
1823
                janus_audiobridge_message *msg = g_malloc0(sizeof(janus_audiobridge_message));
1824
                msg->handle = handle;
1825
                msg->transaction = transaction;
1826
                msg->message = root;
1827
                msg->jsep = jsep;
1828

    
1829
                g_async_queue_push(messages, msg);
1830

    
1831
                return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL, NULL);
1832
        } else {
1833
                JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
1834
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
1835
                g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
1836
        }
1837

    
1838
plugin_response:
1839
                {
1840
                        if(error_code == 0 && !response) {
1841
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1842
                                g_snprintf(error_cause, 512, "Invalid response");
1843
                        }
1844
                        if(error_code != 0) {
1845
                                /* Prepare JSON error event */
1846
                                json_t *event = json_object();
1847
                                json_object_set_new(event, "audiobridge", json_string("event"));
1848
                                json_object_set_new(event, "error_code", json_integer(error_code));
1849
                                json_object_set_new(event, "error", json_string(error_cause));
1850
                                response = event;
1851
                        }
1852
                        if(root != NULL)
1853
                                json_decref(root);
1854
                        if(jsep != NULL)
1855
                                json_decref(jsep);
1856
                        g_free(transaction);
1857

    
1858
                        return janus_plugin_result_new(JANUS_PLUGIN_OK, NULL, response);
1859
                }
1860

    
1861
}
1862

    
1863
void janus_audiobridge_setup_media(janus_plugin_session *handle) {
1864
        JANUS_LOG(LOG_INFO, "WebRTC media is now available\n");
1865
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1866
                return;
1867
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1868
        if(!session) {
1869
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1870
                return;
1871
        }
1872
        if(session->destroyed)
1873
                return;
1874
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1875
        if(!participant)
1876
                return;
1877
        g_atomic_int_set(&session->hangingup, 0);
1878
        /* FIXME Only send this peer the audio mix when we get this event */
1879
        session->started = TRUE;
1880
}
1881

    
1882
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len) {
1883
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1884
                return;
1885
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1886
        if(!session || session->destroyed || session->stopping || !session->participant)
1887
                return;
1888
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1889
        if(!participant->active || participant->muted || !participant->decoder || !participant->room)
1890
                return;
1891
        /* Save the frame if we're recording this leg */
1892
        janus_recorder_save_frame(participant->arc, buf, len);
1893
        if(participant->active && participant->decoder) {
1894
                /* First of all, check if a reset on the decoder is due */
1895
                if(participant->reset) {
1896
                        /* Create a new decoder and get rid of the old one */
1897
                        int error = 0;
1898
                        OpusDecoder *decoder = opus_decoder_create(participant->room->sampling_rate, 1, &error);
1899
                        if(error != OPUS_OK) {
1900
                                JANUS_LOG(LOG_ERR, "Error resetting Opus decoder...\n");
1901
                        } else {
1902
                                if(participant->decoder)
1903
                                        opus_decoder_destroy(participant->decoder);
1904
                                participant->decoder = decoder;
1905
                                JANUS_LOG(LOG_VERB, "Opus decoder reset\n");
1906
                        }
1907
                        participant->reset = FALSE;
1908
                }
1909
                /* Decode frame (Opus -> slinear) */
1910
                rtp_header *rtp = (rtp_header *)buf;
1911
                janus_audiobridge_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
1912
                pkt->data = g_malloc0(BUFFER_SAMPLES*sizeof(opus_int16));
1913
                pkt->ssrc = 0;
1914
                pkt->timestamp = ntohl(rtp->timestamp);
1915
                pkt->seq_number = ntohs(rtp->seq_number);
1916
                participant->working = TRUE;
1917
                pkt->length = opus_decode(participant->decoder, (const unsigned char *)buf+12, len-12, (opus_int16 *)pkt->data, BUFFER_SAMPLES, USE_FEC);
1918
                participant->working = FALSE;
1919
                if(pkt->length < 0) {
1920
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", pkt->length, opus_strerror(pkt->length));
1921
                        g_free(pkt->data);
1922
                        g_free(pkt);
1923
                        return;
1924
                }
1925
                /* Enqueue the decoded frame */
1926
                janus_mutex_lock(&participant->qmutex);
1927
                /* Insert packets sorting by sequence number */
1928
                participant->inbuf = g_list_insert_sorted(participant->inbuf, pkt, &janus_audiobridge_rtp_sort);
1929
                if(participant->prebuffering) {
1930
                        /* Still pre-buffering: do we have enough packets now? */
1931
                        if(g_list_length(participant->inbuf) == DEFAULT_PREBUFFERING) {
1932
                                participant->prebuffering = FALSE;
1933
                                JANUS_LOG(LOG_VERB, "Prebuffering done! Finally adding the user to the mix\n");
1934
                        } else {
1935
                                JANUS_LOG(LOG_VERB, "Still prebuffering (got %d packets), not adding the user to the mix yet\n", g_list_length(participant->inbuf));
1936
                        }
1937
                } else {
1938
                        /* Make sure we're not queueing too many packets: if so, get rid of the older ones */
1939
                        if(g_list_length(participant->inbuf) >= DEFAULT_PREBUFFERING*2) {
1940
                                gint64 now = janus_get_monotonic_time();
1941
                                if(now - participant->last_drop > 5*G_USEC_PER_SEC) {
1942
                                        JANUS_LOG(LOG_WARN, "Too many packets in queue (%d > %d), removing older ones\n",
1943
                                                g_list_length(participant->inbuf), DEFAULT_PREBUFFERING*2);
1944
                                        participant->last_drop = now;
1945
                                }
1946
                                while(g_list_length(participant->inbuf) > DEFAULT_PREBUFFERING*2) {
1947
                                        /* Remove this packet: it's too old */
1948
                                        GList *first = g_list_first(participant->inbuf);
1949
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1950
                                        participant->inbuf = g_list_remove_link(participant->inbuf, first);
1951
                                        first = NULL;
1952
                                        if(pkt == NULL)
1953
                                                continue;
1954
                                        if(pkt->data)
1955
                                                g_free(pkt->data);
1956
                                        pkt->data = NULL;
1957
                                        g_free(pkt);
1958
                                        pkt = NULL;
1959
                                }
1960
                        }
1961
                }
1962
                janus_mutex_unlock(&participant->qmutex);
1963
        }
1964
}
1965

    
1966
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len) {
1967
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1968
                return;
1969
        /* FIXME Should we care? */
1970
}
1971

    
1972
void janus_audiobridge_hangup_media(janus_plugin_session *handle) {
1973
        JANUS_LOG(LOG_INFO, "No WebRTC media anymore\n");
1974
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
1975
                return;
1976
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1977
        if(!session) {
1978
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1979
                return;
1980
        }
1981
        session->started = FALSE;
1982
        if(session->destroyed || !session->participant)
1983
                return;
1984
        if(g_atomic_int_add(&session->hangingup, 1))
1985
                return;
1986
        /* Get rid of participant */
1987
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1988
        janus_mutex_lock(&rooms_mutex);
1989
        janus_audiobridge_room *audiobridge = participant->room;
1990
        if(audiobridge != NULL) {
1991
                janus_mutex_lock(&audiobridge->mutex);
1992
                json_t *event = json_object();
1993
                json_object_set_new(event, "audiobridge", json_string("event"));
1994
                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
1995
                json_object_set_new(event, "leaving", json_integer(participant->user_id));
1996
                g_hash_table_remove(audiobridge->participants, &participant->user_id);
1997
                GHashTableIter iter;
1998
                gpointer value;
1999
                g_hash_table_iter_init(&iter, audiobridge->participants);
2000
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2001
                        janus_audiobridge_participant *p = value;
2002
                        if(p == participant) {
2003
                                continue;        /* Skip the leaving participant itself */
2004
                        }
2005
                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2006
                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL);
2007
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2008
                }
2009
                json_decref(event);
2010
                janus_mutex_unlock(&audiobridge->mutex);
2011
        }
2012
        /* Get rid of the recorders, if available */
2013
        janus_mutex_lock(&participant->rec_mutex);
2014
        if(participant->arc) {
2015
                janus_recorder_close(participant->arc);
2016
                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2017
                janus_recorder_free(participant->arc);
2018
        }
2019
        participant->arc = NULL;
2020
        janus_mutex_unlock(&participant->rec_mutex);
2021
        /* Free the participant resources */
2022
        janus_mutex_lock(&participant->qmutex);
2023
        participant->active = FALSE;
2024
        participant->muted = TRUE;
2025
        if(participant->display)
2026
                g_free(participant->display);
2027
        participant->display = NULL;
2028
        participant->prebuffering = TRUE;
2029
        /* Make sure we're not using the encoder/decoder right now, we're going to destroy them */
2030
        while(participant->working)
2031
                g_usleep(5000);
2032
        if(participant->encoder)
2033
                opus_encoder_destroy(participant->encoder);
2034
        participant->encoder = NULL;
2035
        if(participant->decoder)
2036
                opus_decoder_destroy(participant->decoder);
2037
        participant->decoder = NULL;
2038
        participant->reset = FALSE;
2039
        /* Get rid of queued packets */
2040
        while(participant->inbuf) {
2041
                GList *first = g_list_first(participant->inbuf);
2042
                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2043
                participant->inbuf = g_list_remove_link(participant->inbuf, first);
2044
                first = NULL;
2045
                if(pkt == NULL)
2046
                        continue;
2047
                if(pkt->data)
2048
                        g_free(pkt->data);
2049
                pkt->data = NULL;
2050
                g_free(pkt);
2051
                pkt = NULL;
2052
        }
2053
        participant->last_drop = 0;
2054
        janus_mutex_unlock(&participant->qmutex);
2055
        if(audiobridge != NULL) {
2056
                janus_mutex_unlock(&audiobridge->mutex);
2057
        }
2058
        janus_mutex_unlock(&rooms_mutex);
2059
}
2060

    
2061
/* Thread to handle incoming messages */
2062
static void *janus_audiobridge_handler(void *data) {
2063
        JANUS_LOG(LOG_VERB, "Joining AudioBridge handler thread\n");
2064
        janus_audiobridge_message *msg = NULL;
2065
        int error_code = 0;
2066
        char error_cause[512];
2067
        json_t *root = NULL;
2068
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
2069
                msg = g_async_queue_pop(messages);
2070
                if(msg == NULL)
2071
                        continue;
2072
                if(msg == &exit_message)
2073
                        break;
2074
                if(msg->handle == NULL) {
2075
                        janus_audiobridge_message_free(msg);
2076
                        continue;
2077
                }
2078
                janus_audiobridge_session *session = NULL;
2079
                janus_mutex_lock(&sessions_mutex);
2080
                if(g_hash_table_lookup(sessions, msg->handle) != NULL) {
2081
                        session = (janus_audiobridge_session *)msg->handle->plugin_handle;
2082
                }
2083
                janus_mutex_unlock(&sessions_mutex);
2084
                if(!session) {
2085
                        JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2086
                        janus_audiobridge_message_free(msg);
2087
                        continue;
2088
                }
2089
                if(session->destroyed) {
2090
                        janus_audiobridge_message_free(msg);
2091
                        continue;
2092
                }
2093
                /* Handle request */
2094
                error_code = 0;
2095
                root = NULL;
2096
                if(msg->message == NULL) {
2097
                        JANUS_LOG(LOG_ERR, "No message??\n");
2098
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
2099
                        g_snprintf(error_cause, 512, "%s", "No message??");
2100
                        goto error;
2101
                }
2102
                root = msg->message;
2103
                /* Get the request first */
2104
                JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
2105
                        error_code, error_cause, TRUE,
2106
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2107
                if(error_code != 0)
2108
                        goto error;
2109
                json_t *request = json_object_get(root, "request");
2110
                const char *request_text = json_string_value(request);
2111
                json_t *event = NULL;
2112
                if(!strcasecmp(request_text, "join")) {
2113
                        JANUS_LOG(LOG_VERB, "Configuring new participant\n");
2114
                        janus_audiobridge_participant *participant = session->participant;
2115
                        if(participant != NULL && participant->room != NULL) {
2116
                                JANUS_LOG(LOG_ERR, "Already in a room (use changeroom to join another one)\n");
2117
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED;
2118
                                g_snprintf(error_cause, 512, "Already in a room (use changeroom to join another one)");
2119
                                goto error;
2120
                        }
2121
                        JANUS_VALIDATE_JSON_OBJECT(root, join_parameters,
2122
                                error_code, error_cause, TRUE,
2123
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2124
                        if(error_code != 0)
2125
                                goto error;
2126
                        json_t *room = json_object_get(root, "room");
2127
                        guint64 room_id = json_integer_value(room);
2128
                        janus_mutex_lock(&rooms_mutex);
2129
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2130
                        if(audiobridge == NULL) {
2131
                                janus_mutex_unlock(&rooms_mutex);
2132
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2133
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2134
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2135
                                goto error;
2136
                        }
2137
                        janus_mutex_lock(&audiobridge->mutex);
2138
                        /* A pin may be required for this action */
2139
                        JANUS_CHECK_SECRET(audiobridge->room_pin, root, "pin", error_code, error_cause,
2140
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2141
                        if(error_code != 0) {
2142
                                janus_mutex_unlock(&audiobridge->mutex);
2143
                                janus_mutex_unlock(&rooms_mutex);
2144
                                goto error;
2145
                        }
2146
                        json_t *display = json_object_get(root, "display");
2147
                        const char *display_text = display ? json_string_value(display) : NULL;
2148
                        json_t *muted = json_object_get(root, "muted");
2149
                        json_t *quality = json_object_get(root, "quality");
2150
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
2151
                        if(complexity < 1 || complexity > 10) {
2152
                                janus_mutex_unlock(&audiobridge->mutex);
2153
                                janus_mutex_unlock(&rooms_mutex);
2154
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2155
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2156
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2157
                                goto error;
2158
                        }
2159
                        guint64 user_id = 0;
2160
                        json_t *id = json_object_get(root, "id");
2161
                        if(id) {
2162
                                user_id = json_integer_value(id);
2163
                                if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2164
                                        /* User ID already taken */
2165
                                        janus_mutex_unlock(&audiobridge->mutex);
2166
                                        janus_mutex_unlock(&rooms_mutex);
2167
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
2168
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
2169
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
2170
                                        goto error;
2171
                                }
2172
                        }
2173
                        if(user_id == 0) {
2174
                                /* Generate a random ID */
2175
                                while(user_id == 0) {
2176
                                        user_id = janus_random_uint64();
2177
                                        if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2178
                                                /* User ID already taken, try another one */
2179
                                                user_id = 0;
2180
                                        }
2181
                                }
2182
                        }
2183
                        JANUS_LOG(LOG_VERB, "  -- Participant ID: %"SCNu64"\n", user_id);
2184
                        if(participant == NULL) {
2185
                                participant = g_malloc0(sizeof(janus_audiobridge_participant));
2186
                                participant->active = FALSE;
2187
                                participant->prebuffering = TRUE;
2188
                                participant->display = NULL;
2189
                                participant->inbuf = NULL;
2190
                                participant->outbuf = NULL;
2191
                                participant->last_drop = 0;
2192
                                participant->encoder = NULL;
2193
                                participant->decoder = NULL;
2194
                                participant->reset = FALSE;
2195
                                janus_mutex_init(&participant->qmutex);
2196
                                participant->arc = NULL;
2197
                                janus_mutex_init(&participant->rec_mutex);
2198
                        }
2199
                        participant->session = session;
2200
                        participant->room = audiobridge;
2201
                        participant->user_id = user_id;
2202
                        if(participant->display != NULL)
2203
                                g_free(participant->display);
2204
                        participant->display = display_text ? g_strdup(display_text) : NULL;
2205
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* By default, everyone's unmuted when joining */
2206
                        participant->opus_complexity = complexity;
2207
                        if(participant->outbuf == NULL)
2208
                                participant->outbuf = g_async_queue_new();
2209
                        participant->active = session->started;
2210
                        if(!session->started) {
2211
                                /* Initialize the RTP context only if we're renegotiating */
2212
                                participant->context.a_last_ssrc = 0;
2213
                                participant->context.a_last_ts = 0;
2214
                                participant->context.a_base_ts = 0;
2215
                                participant->context.a_base_ts_prev = 0;
2216
                                participant->context.a_last_seq = 0;
2217
                                participant->context.a_base_seq = 0;
2218
                                participant->context.a_base_seq_prev = 0;
2219
                                participant->opus_pt = 0;
2220
                        }
2221
                        JANUS_LOG(LOG_VERB, "Creating Opus encoder/decoder (sampling rate %d)\n", audiobridge->sampling_rate);
2222
                        /* Opus encoder */
2223
                        int error = 0;
2224
                        if(participant->encoder == NULL) {
2225
                                participant->encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
2226
                                if(error != OPUS_OK) {
2227
                                        janus_mutex_unlock(&audiobridge->mutex);
2228
                                        janus_mutex_unlock(&rooms_mutex);
2229
                                        if(participant->display)
2230
                                                g_free(participant->display);
2231
                                        g_free(participant);
2232
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2233
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2234
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2235
                                        goto error;
2236
                                }
2237
                                if(audiobridge->sampling_rate == 8000) {
2238
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
2239
                                } else if(audiobridge->sampling_rate == 12000) {
2240
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
2241
                                } else if(audiobridge->sampling_rate == 16000) {
2242
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2243
                                } else if(audiobridge->sampling_rate == 24000) {
2244
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
2245
                                } else if(audiobridge->sampling_rate == 48000) {
2246
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
2247
                                } else {
2248
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
2249
                                        audiobridge->sampling_rate = 16000;
2250
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2251
                                }
2252
                                /* FIXME This settings should be configurable */
2253
                                opus_encoder_ctl(participant->encoder, OPUS_SET_INBAND_FEC(USE_FEC));
2254
                        }
2255
                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2256
                        if(participant->decoder == NULL) {
2257
                                /* Opus decoder */
2258
                                error = 0;
2259
                                participant->decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
2260
                                if(error != OPUS_OK) {
2261
                                        janus_mutex_unlock(&audiobridge->mutex);
2262
                                        janus_mutex_unlock(&rooms_mutex);
2263
                                        if(participant->display)
2264
                                                g_free(participant->display);
2265
                                        if(participant->encoder)
2266
                                                opus_encoder_destroy(participant->encoder);
2267
                                        participant->encoder = NULL;
2268
                                        if(participant->decoder)
2269
                                                opus_decoder_destroy(participant->decoder);
2270
                                        participant->decoder = NULL;
2271
                                        g_free(participant);
2272
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2273
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2274
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2275
                                        goto error;
2276
                                }
2277
                        }
2278
                        participant->reset = FALSE;
2279
                        /* Finally, start the encoding thread if it hasn't already */
2280
                        if(participant->thread == NULL) {
2281
                                GError *error = NULL;
2282
                                char roomtrunc[5], parttrunc[5];
2283
                                g_snprintf(roomtrunc, sizeof(roomtrunc), "%"SCNu64, audiobridge->room_id);
2284
                                g_snprintf(parttrunc, sizeof(parttrunc), "%"SCNu64, participant->user_id);
2285
                                char tname[16];
2286
                                g_snprintf(tname, sizeof(tname), "mixer %s %s", roomtrunc, parttrunc);
2287
                                participant->thread = g_thread_try_new(tname, &janus_audiobridge_participant_thread, participant, &error);
2288
                                if(error != NULL) {
2289
                                        /* FIXME We should fail here... */
2290
                                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the participant thread...\n", error->code, error->message ? error->message : "??");
2291
                                }
2292
                        }
2293
                        
2294
                        /* Done */
2295
                        session->participant = participant;
2296
                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2297
                        /* Notify the other participants */
2298
                        json_t *newuser = json_object();
2299
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
2300
                        json_object_set_new(newuser, "room", json_integer(room_id));
2301
                        json_t *newuserlist = json_array();
2302
                        json_t *pl = json_object();
2303
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2304
                        if(participant->display)
2305
                                json_object_set_new(pl, "display", json_string(participant->display));
2306
                        json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
2307
                        json_array_append_new(newuserlist, pl);
2308
                        json_object_set_new(newuser, "participants", newuserlist);
2309
                        GHashTableIter iter;
2310
                        gpointer value;
2311
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2312
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2313
                                janus_audiobridge_participant *p = value;
2314
                                if(p == participant) {
2315
                                        continue;
2316
                                }
2317
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2318
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser, NULL);
2319
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2320
                        }
2321
                        json_decref(newuser);
2322
                        /* Return a list of all available participants for the new participant now */
2323
                        json_t *list = json_array();
2324
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2325
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2326
                                janus_audiobridge_participant *p = value;
2327
                                if(p == participant) {
2328
                                        continue;
2329
                                }
2330
                                json_t *pl = json_object();
2331
                                json_object_set_new(pl, "id", json_integer(p->user_id));
2332
                                if(p->display)
2333
                                        json_object_set_new(pl, "display", json_string(p->display));
2334
                                json_object_set_new(pl, "muted", p->muted ? json_true() : json_false());
2335
                                json_array_append_new(list, pl);
2336
                        }
2337
                        janus_mutex_unlock(&audiobridge->mutex);
2338
                        janus_mutex_unlock(&rooms_mutex);
2339
                        event = json_object();
2340
                        json_object_set_new(event, "audiobridge", json_string("joined"));
2341
                        json_object_set_new(event, "room", json_integer(room_id));
2342
                        json_object_set_new(event, "id", json_integer(user_id));
2343
                        json_object_set_new(event, "participants", list);
2344
                } else if(!strcasecmp(request_text, "configure")) {
2345
                        /* Handle this participant */
2346
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2347
                        if(participant == NULL || participant->room == NULL) {
2348
                                JANUS_LOG(LOG_ERR, "Can't configure (not in a room)\n");
2349
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2350
                                g_snprintf(error_cause, 512, "Can't configure (not in a room)");
2351
                                goto error;
2352
                        }
2353
                        /* Configure settings for this participant */
2354
                        JANUS_VALIDATE_JSON_OBJECT(root, configure_parameters,
2355
                                error_code, error_cause, TRUE,
2356
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2357
                        if(error_code != 0)
2358
                                goto error;
2359
                        json_t *muted = json_object_get(root, "muted");
2360
                        json_t *quality = json_object_get(root, "quality");
2361
                        json_t *record = json_object_get(root, "record");
2362
                        json_t *recfile = json_object_get(root, "filename");
2363
                        if(quality) {
2364
                                int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
2365
                                if(complexity < 1 || complexity > 10) {
2366
                                        JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2367
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2368
                                        g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2369
                                        goto error;
2370
                                }
2371
                                participant->opus_complexity = complexity;
2372
                                if(participant->encoder)
2373
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2374
                        }
2375
                        if(muted) {
2376
                                participant->muted = json_is_true(muted);
2377
                                JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %"SCNu64", user %"SCNu64")\n", participant->muted ? "true" : "false", participant->room->room_id, participant->user_id);
2378
                                if(participant->muted) {
2379
                                        /* Clear the queued packets waiting to be handled */
2380
                                        janus_mutex_lock(&participant->qmutex);
2381
                                        while(participant->inbuf) {
2382
                                                GList *first = g_list_first(participant->inbuf);
2383
                                                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2384
                                                participant->inbuf = g_list_remove_link(participant->inbuf, first);
2385
                                                first = NULL;
2386
                                                if(pkt == NULL)
2387
                                                        continue;
2388
                                                if(pkt->data)
2389
                                                        g_free(pkt->data);
2390
                                                pkt->data = NULL;
2391
                                                g_free(pkt);
2392
                                                pkt = NULL;
2393
                                        }
2394
                                        janus_mutex_unlock(&participant->qmutex);
2395
                                }
2396
                                /* Notify all other participants about the mute/unmute */
2397
                                janus_mutex_lock(&rooms_mutex);
2398
                                janus_audiobridge_room *audiobridge = participant->room;
2399
                                if(audiobridge != NULL) {
2400
                                        janus_mutex_lock(&audiobridge->mutex);
2401
                                        json_t *list = json_array();
2402
                                        json_t *pl = json_object();
2403
                                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2404
                                        if(participant->display)
2405
                                                json_object_set_new(pl, "display", json_string(participant->display));
2406
                                        json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
2407
                                        json_array_append_new(list, pl);
2408
                                        json_t *pub = json_object();
2409
                                        json_object_set_new(pub, "audiobridge", json_string("event"));
2410
                                        json_object_set_new(pub, "room", json_integer(participant->room->room_id));
2411
                                        json_object_set_new(pub, "participants", list);
2412
                                        GHashTableIter iter;
2413
                                        gpointer value;
2414
                                        g_hash_table_iter_init(&iter, audiobridge->participants);
2415
                                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2416
                                                janus_audiobridge_participant *p = value;
2417
                                                if(p == participant) {
2418
                                                        continue;        /* Skip the new participant itself */
2419
                                                }
2420
                                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2421
                                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL);
2422
                                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2423
                                        }
2424
                                        json_decref(pub);
2425
                                        janus_mutex_unlock(&audiobridge->mutex);
2426
                                }
2427
                                janus_mutex_unlock(&rooms_mutex);
2428
                        }
2429
                        if(record) {
2430
                                janus_mutex_lock(&participant->rec_mutex);
2431
                                if(json_is_true(record)) {
2432
                                        /* Start recording (ignore if recording already) */
2433
                                        if(participant->arc != NULL) {
2434
                                                JANUS_LOG(LOG_WARN, "Already recording participant's audio (room %"SCNu64", user %"SCNu64")\n",
2435
                                                        participant->user_id, participant->room->room_id);
2436
                                        } else {
2437
                                                JANUS_LOG(LOG_INFO, "Starting recording of participant's audio (room %"SCNu64", user %"SCNu64")\n",
2438
                                                        participant->user_id, participant->room->room_id);
2439
                                                char filename[255];
2440
                                                gint64 now = janus_get_real_time();
2441
                                                memset(filename, 0, 255);
2442
                                                const char *recording_base = json_string_value(recfile);
2443
                                                if(recording_base) {
2444
                                                        /* Use the filename and path we have been provided */
2445
                                                        g_snprintf(filename, 255, "%s-audio", recording_base);
2446
                                                        participant->arc = janus_recorder_create(NULL, "opus", filename);
2447
                                                        if(participant->arc == NULL) {
2448
                                                                /* FIXME We should notify the fact the recorder could not be created */
2449
                                                                JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this participant!\n");
2450
                                                        }
2451
                                                } else {
2452
                                                        /* Build a filename */
2453
                                                        g_snprintf(filename, 255, "audiobridge-%"SCNu64"-%"SCNu64"-%"SCNi64"-audio",
2454
                                                                participant->user_id, participant->room->room_id, now);
2455
                                                        participant->arc = janus_recorder_create(NULL, "opus", filename);
2456
                                                        if(participant->arc == NULL) {
2457
                                                                /* FIXME We should notify the fact the recorder could not be created */
2458
                                                                JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this participant!\n");
2459
                                                        }
2460
                                                }
2461
                                        }
2462
                                } else {
2463
                                        /* Stop recording (ignore if not recording) */
2464
                                        if(participant->arc) {
2465
                                                janus_recorder_close(participant->arc);
2466
                                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2467
                                                janus_recorder_free(participant->arc);
2468
                                        }
2469
                                        participant->arc = NULL;
2470
                                }
2471
                                janus_mutex_unlock(&participant->rec_mutex);
2472
                        }
2473
                        /* Done */
2474
                        event = json_object();
2475
                        json_object_set_new(event, "audiobridge", json_string("event"));
2476
                        json_object_set_new(event, "result", json_string("ok"));
2477
                } else if(!strcasecmp(request_text, "changeroom")) {
2478
                        /* The participant wants to leave the current room and join another one without reconnecting (e.g., a sidebar) */
2479
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2480
                        if(participant == NULL || participant->room == NULL) {
2481
                                JANUS_LOG(LOG_ERR, "Can't change room (not in a room in the first place)\n");
2482
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2483
                                g_snprintf(error_cause, 512, "Can't change room (not in a room in the first place)");
2484
                                goto error;
2485
                        }
2486
                        JANUS_VALIDATE_JSON_OBJECT(root, join_parameters,
2487
                                error_code, error_cause, TRUE,
2488
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2489
                        if(error_code != 0)
2490
                                goto error;
2491
                        json_t *room = json_object_get(root, "room");
2492
                        guint64 room_id = json_integer_value(room);
2493
                        janus_mutex_lock(&rooms_mutex);
2494
                        /* Is this the same room we're in? */
2495
                        if(participant->room && participant->room->room_id == room_id) {
2496
                                janus_mutex_unlock(&rooms_mutex);
2497
                                JANUS_LOG(LOG_ERR, "Already in this room\n");
2498
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED;
2499
                                g_snprintf(error_cause, 512, "Already in this room");
2500
                                goto error;
2501
                        }
2502
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2503
                        if(audiobridge == NULL) {
2504
                                janus_mutex_unlock(&rooms_mutex);
2505
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2506
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2507
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2508
                                goto error;
2509
                        }
2510
                        janus_mutex_lock(&audiobridge->mutex);
2511
                        /* A pin may be required for this action */
2512
                        JANUS_CHECK_SECRET(audiobridge->room_pin, root, "pin", error_code, error_cause,
2513
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2514
                        if(error_code != 0) {
2515
                                janus_mutex_unlock(&audiobridge->mutex);
2516
                                janus_mutex_unlock(&rooms_mutex);
2517
                                goto error;
2518
                        }
2519
                        json_t *display = json_object_get(root, "display");
2520
                        const char *display_text = display ? json_string_value(display) : NULL;
2521
                        json_t *muted = json_object_get(root, "muted");
2522
                        json_t *quality = json_object_get(root, "quality");
2523
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
2524
                        if(complexity < 1 || complexity > 10) {
2525
                                janus_mutex_unlock(&audiobridge->mutex);
2526
                                janus_mutex_unlock(&rooms_mutex);
2527
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2528
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2529
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2530
                                goto error;
2531
                        }
2532
                        guint64 user_id = 0;
2533
                        json_t *id = json_object_get(root, "id");
2534
                        if(id) {
2535
                                user_id = json_integer_value(id);
2536
                                if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2537
                                        /* User ID already taken */
2538
                                        janus_mutex_unlock(&audiobridge->mutex);
2539
                                        janus_mutex_unlock(&rooms_mutex);
2540
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
2541
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
2542
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
2543
                                        goto error;
2544
                                }
2545
                        }
2546
                        if(user_id == 0) {
2547
                                /* Generate a random ID */
2548
                                while(user_id == 0) {
2549
                                        user_id = janus_random_uint64();
2550
                                        if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2551
                                                /* User ID already taken, try another one */
2552
                                                user_id = 0;
2553
                                        }
2554
                                }
2555
                        }
2556
                        JANUS_LOG(LOG_VERB, "  -- Participant ID in new room %"SCNu64": %"SCNu64"\n", room_id, user_id);
2557
                        participant->prebuffering = TRUE;
2558
                        /* Is the sampling rate of the new room the same as the one in the old room, or should we update the decoder/encoder? */
2559
                        janus_audiobridge_room *old_audiobridge = participant->room;
2560
                        /* Leave the old room first... */
2561
                        janus_mutex_lock(&old_audiobridge->mutex);
2562
                        g_hash_table_remove(old_audiobridge->participants, &participant->user_id);
2563
                        if(old_audiobridge->sampling_rate != audiobridge->sampling_rate) {
2564
                                /* Create a new one that takes into account the sampling rate we want now */
2565
                                int error = 0;
2566
                                OpusEncoder *new_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
2567
                                if(error != OPUS_OK) {
2568
                                        if(new_encoder)
2569
                                                opus_encoder_destroy(new_encoder);
2570
                                        new_encoder = NULL;
2571
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2572
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2573
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2574
                                        /* Join the old room again... */
2575
                                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2576
                                        janus_mutex_unlock(&old_audiobridge->mutex);
2577
                                        janus_mutex_unlock(&audiobridge->mutex);
2578
                                        janus_mutex_unlock(&rooms_mutex);
2579
                                        goto error;
2580
                                }
2581
                                if(audiobridge->sampling_rate == 8000) {
2582
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
2583
                                } else if(audiobridge->sampling_rate == 12000) {
2584
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
2585
                                } else if(audiobridge->sampling_rate == 16000) {
2586
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2587
                                } else if(audiobridge->sampling_rate == 24000) {
2588
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
2589
                                } else if(audiobridge->sampling_rate == 48000) {
2590
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
2591
                                } else {
2592
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
2593
                                        audiobridge->sampling_rate = 16000;
2594
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2595
                                }
2596
                                /* FIXME This settings should be configurable */
2597
                                opus_encoder_ctl(new_encoder, OPUS_SET_INBAND_FEC(USE_FEC));
2598
                                opus_encoder_ctl(new_encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2599
                                /* Opus decoder */
2600
                                error = 0;
2601
                                OpusDecoder *new_decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
2602
                                if(error != OPUS_OK) {
2603
                                        if(new_encoder)
2604
                                                opus_encoder_destroy(new_encoder);
2605
                                        new_encoder = NULL;
2606
                                        if(new_decoder)
2607
                                                opus_decoder_destroy(new_decoder);
2608
                                        new_decoder = NULL;
2609
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2610
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2611
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2612
                                        /* Join the old room again... */
2613
                                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2614
                                        janus_mutex_unlock(&old_audiobridge->mutex);
2615
                                        janus_mutex_unlock(&audiobridge->mutex);
2616
                                        janus_mutex_unlock(&rooms_mutex);
2617
                                        goto error;
2618
                                }
2619
                                participant->reset = FALSE;
2620
                                /* Destroy the previous encoder/decoder and update the references */
2621
                                if(participant->encoder)
2622
                                        opus_encoder_destroy(participant->encoder);
2623
                                participant->encoder = new_encoder;
2624
                                if(participant->decoder)
2625
                                        opus_decoder_destroy(participant->decoder);
2626
                                participant->decoder = new_decoder;
2627
                        }
2628
                        /* Everything looks fine, start by telling the folks in the old room this participant is going away */
2629
                        event = json_object();
2630
                        json_object_set_new(event, "audiobridge", json_string("event"));
2631
                        json_object_set_new(event, "room", json_integer(old_audiobridge->room_id));
2632
                        json_object_set_new(event, "leaving", json_integer(participant->user_id));
2633
                        GHashTableIter iter;
2634
                        gpointer value;
2635
                        g_hash_table_iter_init(&iter, old_audiobridge->participants);
2636
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2637
                                janus_audiobridge_participant *p = value;
2638
                                if(p == participant) {
2639
                                        continue;        /* Skip the new participant itself */
2640
                                }
2641
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2642
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL);
2643
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2644
                        }
2645
                        json_decref(event);
2646
                        janus_mutex_unlock(&old_audiobridge->mutex);
2647
                        /* Stop recording, if we were (since this is a new room, a new recording would be required, so a new configure) */
2648
                        janus_mutex_lock(&participant->rec_mutex);
2649
                        if(participant->arc) {
2650
                                janus_recorder_close(participant->arc);
2651
                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2652
                                janus_recorder_free(participant->arc);
2653
                        }
2654
                        participant->arc = NULL;
2655
                        janus_mutex_unlock(&participant->rec_mutex);
2656
                        /* Done, join the new one */
2657
                        participant->user_id = user_id;
2658
                        if(display_text) {
2659
                                g_free(participant->display);
2660
                                participant->display = display_text ? g_strdup(display_text) : NULL;
2661
                        }
2662
                        participant->room = audiobridge;
2663
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* When switching to a new room, you're unmuted by default */
2664
                        if(quality) {
2665
                                participant->opus_complexity = complexity;
2666
                                if(participant->encoder)
2667
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2668
                        }
2669
                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2670
                        /* Notify the other participants */
2671
                        json_t *newuser = json_object();
2672
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
2673
                        json_object_set_new(newuser, "room", json_integer(audiobridge->room_id));
2674
                        json_t *newuserlist = json_array();
2675
                        json_t *pl = json_object();
2676
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2677
                        if(participant->display)
2678
                                json_object_set_new(pl, "display", json_string(participant->display));
2679
                        json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
2680
                        json_array_append_new(newuserlist, pl);
2681
                        json_object_set_new(newuser, "participants", newuserlist);
2682
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2683
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2684
                                janus_audiobridge_participant *p = value;
2685
                                if(p == participant) {
2686
                                        continue;
2687
                                }
2688
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2689
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser, NULL);
2690
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2691
                        }
2692
                        json_decref(newuser);
2693
                        /* Return a list of all available participants for the new participant now */
2694
                        json_t *list = json_array();
2695
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2696
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2697
                                janus_audiobridge_participant *p = value;
2698
                                if(p == participant) {
2699
                                        continue;
2700
                                }
2701
                                json_t *pl = json_object();
2702
                                json_object_set_new(pl, "id", json_integer(p->user_id));
2703
                                if(p->display)
2704
                                        json_object_set_new(pl, "display", json_string(p->display));
2705
                                json_object_set_new(pl, "muted", p->muted ? json_true() : json_false());
2706
                                json_array_append_new(list, pl);
2707
                        }
2708
                        event = json_object();
2709
                        json_object_set_new(event, "audiobridge", json_string("roomchanged"));
2710
                        json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2711
                        json_object_set_new(event, "id", json_integer(user_id));
2712
                        json_object_set_new(event, "participants", list);
2713
                        janus_mutex_unlock(&audiobridge->mutex);
2714
                        janus_mutex_unlock(&rooms_mutex);
2715
                } else if(!strcasecmp(request_text, "leave")) {
2716
                        /* This participant is leaving */
2717
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2718
                        if(participant == NULL || participant->room == NULL) {
2719
                                JANUS_LOG(LOG_ERR, "Can't leave (not in a room)\n");
2720
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2721
                                g_snprintf(error_cause, 512, "Can't leave (not in a room)");
2722
                                goto error;
2723
                        }
2724
                        /* Tell everybody */
2725
                        janus_mutex_lock(&rooms_mutex);
2726
                        janus_audiobridge_room *audiobridge = participant->room;
2727
                        if(audiobridge != NULL) {
2728
                                janus_mutex_lock(&audiobridge->mutex);
2729
                                event = json_object();
2730
                                json_object_set_new(event, "audiobridge", json_string("event"));
2731
                                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2732
                                json_object_set_new(event, "leaving", json_integer(participant->user_id));
2733
                                GHashTableIter iter;
2734
                                gpointer value;
2735
                                g_hash_table_iter_init(&iter, audiobridge->participants);
2736
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2737
                                        janus_audiobridge_participant *p = value;
2738
                                        if(p == participant) {
2739
                                                continue;        /* Skip the new participant itself */
2740
                                        }
2741
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2742
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL);
2743
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2744
                                }
2745
                                json_decref(event);
2746
                                /* Actually leave the room... */
2747
                                g_hash_table_remove(audiobridge->participants, &participant->user_id);
2748
                                participant->room = NULL;
2749
                        }
2750
                        /* Get rid of queued packets */
2751
                        janus_mutex_lock(&participant->qmutex);
2752
                        participant->active = FALSE;
2753
                        participant->prebuffering = TRUE;
2754
                        while(participant->inbuf) {
2755
                                GList *first = g_list_first(participant->inbuf);
2756
                                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2757
                                participant->inbuf = g_list_remove_link(participant->inbuf, first);
2758
                                first = NULL;
2759
                                if(pkt == NULL)
2760
                                        continue;
2761
                                if(pkt->data)
2762
                                        g_free(pkt->data);
2763
                                pkt->data = NULL;
2764
                                g_free(pkt);
2765
                                pkt = NULL;
2766
                        }
2767
                        janus_mutex_unlock(&participant->qmutex);
2768
                        /* Stop recording, if we were */
2769
                        janus_mutex_lock(&participant->rec_mutex);
2770
                        if(participant->arc) {
2771
                                janus_recorder_close(participant->arc);
2772
                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2773
                                janus_recorder_free(participant->arc);
2774
                        }
2775
                        participant->arc = NULL;
2776
                        janus_mutex_unlock(&participant->rec_mutex);
2777
                        /* Done */
2778
                        if(audiobridge != NULL)
2779
                                janus_mutex_unlock(&audiobridge->mutex);
2780
                        janus_mutex_unlock(&rooms_mutex);
2781
                } else {
2782
                        JANUS_LOG(LOG_ERR, "Unknown request '%s'\n", request_text);
2783
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
2784
                        g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
2785
                        goto error;
2786
                }
2787

    
2788
                /* Prepare JSON event */
2789
                JANUS_LOG(LOG_VERB, "Preparing JSON event as a reply\n");
2790
                /* Any SDP to handle? */
2791
                const char *msg_sdp_type = json_string_value(json_object_get(msg->jsep, "type"));
2792
                const char *msg_sdp = json_string_value(json_object_get(msg->jsep, "sdp"));
2793
                if(!msg_sdp) {
2794
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, NULL);
2795
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2796
                        json_decref(event);
2797
                } else {
2798
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg_sdp_type, msg_sdp);
2799
                        const char *type = NULL;
2800
                        if(!strcasecmp(msg_sdp_type, "offer"))
2801
                                type = "answer";
2802
                        if(!strcasecmp(msg_sdp_type, "answer"))
2803
                                type = "offer";
2804
                        /* Fill the SDP template and use that as our answer */
2805
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2806
                        char sdp[1024];
2807
                        /* What is the Opus payload type? */
2808
                        participant->opus_pt = janus_get_codec_pt(msg_sdp, "opus");
2809
                        JANUS_LOG(LOG_VERB, "Opus payload type is %d\n", participant->opus_pt);
2810
                        g_snprintf(sdp, 1024, sdp_template,
2811
                                janus_get_real_time(),                        /* We need current time here */
2812
                                janus_get_real_time(),                        /* We need current time here */
2813
                                participant->room->room_name,        /* Audio bridge name */
2814
                                participant->opus_pt,                        /* Opus payload type */
2815
                                participant->opus_pt,                        /* Opus payload type */
2816
                                participant->opus_pt,                         /* Opus payload type and room sampling rate */
2817
                                participant->room->sampling_rate);
2818
                        /* Is the peer recvonly? */
2819
                        if(strstr(msg_sdp, "a=recvonly") != NULL) {
2820
                                /* If so, use sendonly here */
2821
                                g_strlcat(sdp, "a=sendonly\r\n", 1024);
2822
                        }
2823
                        /* Did the peer negotiate video? */
2824
                        if(strstr(msg_sdp, "m=video") != NULL) {
2825
                                /* If so, reject it */
2826
                                g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", 1024);                                
2827
                        }
2828
                        /* Did the peer negotiate data channels? */
2829
                        if(strstr(msg_sdp, "DTLS/SCTP") != NULL) {
2830
                                /* If so, reject them */
2831
                                g_strlcat(sdp, "m=application 0 DTLS/SCTP 0\r\n", 1024);
2832
                        }
2833
                        json_t *jsep = json_pack("{ssss}", "type", type, "sdp", sdp);
2834
                        /* How long will the gateway take to push the event? */
2835
                        g_atomic_int_set(&session->hangingup, 0);
2836
                        gint64 start = janus_get_monotonic_time();
2837
                        int res = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, jsep);
2838
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (took %"SCNu64" us)\n", res, janus_get_monotonic_time()-start);
2839
                        json_decref(event);
2840
                        json_decref(jsep);
2841
                        if(res != JANUS_OK) {
2842
                                /* TODO Failed to negotiate? We should remove this participant */
2843
                        } else {
2844
                                /* Notify all other participants that there's a new boy in town */
2845
                                janus_mutex_lock(&rooms_mutex);
2846
                                janus_audiobridge_room *audiobridge = participant->room;
2847
                                janus_mutex_lock(&audiobridge->mutex);
2848
                                json_t *list = json_array();
2849
                                json_t *pl = json_object();
2850
                                json_object_set_new(pl, "id", json_integer(participant->user_id));
2851
                                if(participant->display)
2852
                                        json_object_set_new(pl, "display", json_string(participant->display));
2853
                                json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
2854
                                json_array_append_new(list, pl);
2855
                                json_t *pub = json_object();
2856
                                json_object_set_new(pub, "audiobridge", json_string("event"));
2857
                                json_object_set_new(pub, "room", json_integer(participant->room->room_id));
2858
                                json_object_set_new(pub, "participants", list);
2859
                                GHashTableIter iter;
2860
                                gpointer value;
2861
                                g_hash_table_iter_init(&iter, audiobridge->participants);
2862
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2863
                                        janus_audiobridge_participant *p = value;
2864
                                        if(p == participant) {
2865
                                                continue;        /* Skip the new participant itself */
2866
                                        }
2867
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2868
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL);
2869
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2870
                                }
2871
                                json_decref(pub);
2872
                                participant->active = TRUE;
2873
                                janus_mutex_unlock(&audiobridge->mutex);
2874
                                janus_mutex_unlock(&rooms_mutex);
2875
                        }
2876
                }
2877
                if(msg)
2878
                        janus_audiobridge_message_free(msg);
2879
                msg = NULL;
2880

    
2881
                continue;
2882
                
2883
error:
2884
                {
2885
                        /* Prepare JSON error event */
2886
                        json_t *event = json_object();
2887
                        json_object_set_new(event, "audiobridge", json_string("event"));
2888
                        json_object_set_new(event, "error_code", json_integer(error_code));
2889
                        json_object_set_new(event, "error", json_string(error_cause));
2890
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, NULL);
2891
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
2892
                        json_decref(event);
2893
                        janus_audiobridge_message_free(msg);
2894
                }
2895
        }
2896
        JANUS_LOG(LOG_VERB, "Leaving AudioBridge handler thread\n");
2897
        return NULL;
2898
}
2899

    
2900
/* Thread to mix the contributions from all participants */
2901
static void *janus_audiobridge_mixer_thread(void *data) {
2902
        JANUS_LOG(LOG_VERB, "Audio bridge thread starting...\n");
2903
        janus_audiobridge_room *audiobridge = (janus_audiobridge_room *)data;
2904
        if(!audiobridge) {
2905
                JANUS_LOG(LOG_ERR, "Invalid room!\n");
2906
                return NULL;
2907
        }
2908
        JANUS_LOG(LOG_VERB, "Thread is for mixing room %"SCNu64" (%s) at rate %"SCNu32"...\n", audiobridge->room_id, audiobridge->room_name, audiobridge->sampling_rate);
2909

    
2910
        /* Do we need to record the mix? */
2911
        if(audiobridge->record) {
2912
                char filename[255];
2913
                if(audiobridge->record_file)
2914
                        g_snprintf(filename, 255, "%s", audiobridge->record_file);
2915
                else
2916
                        g_snprintf(filename, 255, "/tmp/janus-audioroom-%"SCNu64".wav", audiobridge->room_id);
2917
                audiobridge->recording = fopen(filename, "wb");
2918
                if(audiobridge->recording == NULL) {
2919
                        JANUS_LOG(LOG_WARN, "Recording requested, but could NOT open file %s for writing...\n", filename);
2920
                } else {
2921
                        JANUS_LOG(LOG_VERB, "Recording requested, opened file %s for writing\n", filename);
2922
                        /* Write WAV header */
2923
                        wav_header header = {
2924
                                {'R', 'I', 'F', 'F'},
2925
                                0,
2926
                                {'W', 'A', 'V', 'E'},
2927
                                {'f', 'm', 't', ' '},
2928
                                16,
2929
                                1,
2930
                                1,
2931
                                audiobridge->sampling_rate,
2932
                                audiobridge->sampling_rate * 2,
2933
                                2,
2934
                                16,
2935
                                {'d', 'a', 't', 'a'},
2936
                                0
2937
                        };
2938
                        if(fwrite(&header, 1, sizeof(header), audiobridge->recording) != sizeof(header)) {
2939
                                JANUS_LOG(LOG_ERR, "Error writing WAV header...\n");
2940
                        }
2941
                        fflush(audiobridge->recording);
2942
                        audiobridge->record_lastupdate = janus_get_monotonic_time();
2943
                }
2944
        }
2945

    
2946
        /* Buffer (we allocate assuming 48kHz, although we'll likely use less than that) */
2947
        int samples = audiobridge->sampling_rate/50;
2948
        opus_int32 buffer[960], sumBuffer[960];
2949
        opus_int16 outBuffer[960], *curBuffer = NULL;
2950
        memset(buffer, 0, 960*4);
2951
        memset(sumBuffer, 0, 960*4);
2952
        memset(outBuffer, 0, 960*2);
2953

    
2954
        /* Base RTP packet, in case there are forwarders involved */
2955
        unsigned char *rtpbuffer = g_malloc0(1500);
2956
        rtp_header *rtph = (rtp_header *)rtpbuffer;
2957
        rtph->version = 2;
2958

    
2959
        /* Timer */
2960
        struct timeval now, before;
2961
        gettimeofday(&before, NULL);
2962
        now.tv_sec = before.tv_sec;
2963
        now.tv_usec = before.tv_usec;
2964
        time_t passed, d_s, d_us;
2965

    
2966
        /* RTP */
2967
        gint16 seq = 0;
2968
        gint32 ts = 0;
2969

    
2970
        /* Loop */
2971
        int i=0;
2972
        int count = 0, rf_count = 0, prev_count = 0;
2973
        while(!g_atomic_int_get(&stopping) && audiobridge->destroyed == 0) {        /* FIXME We need a per-room watchdog as well */
2974
                /* See if it's time to prepare a frame */
2975
                gettimeofday(&now, NULL);
2976
                d_s = now.tv_sec - before.tv_sec;
2977
                d_us = now.tv_usec - before.tv_usec;
2978
                if(d_us < 0) {
2979
                        d_us += 1000000;
2980
                        --d_s;
2981
                }
2982
                passed = d_s*1000000 + d_us;
2983
                if(passed < 15000) {        /* Let's wait about 15ms at max */
2984
                        usleep(1000);
2985
                        continue;
2986
                }
2987
                /* Update the reference time */
2988
                before.tv_usec += 20000;
2989
                if(before.tv_usec > 1000000) {
2990
                        before.tv_sec++;
2991
                        before.tv_usec -= 1000000;
2992
                }
2993
                /* Do we need to mix at all? */
2994
                janus_mutex_lock_nodebug(&audiobridge->mutex);
2995
                count = g_hash_table_size(audiobridge->participants);
2996
                rf_count = g_hash_table_size(audiobridge->rtp_forwarders);
2997
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
2998
                if((count+rf_count) == 0) {
2999
                        /* No participant and RTP forwarders, do nothing */
3000
                        if(prev_count > 0) {
3001
                                JANUS_LOG(LOG_VERB, "Last user/forwarder just left room %"SCNu64", going idle...\n", audiobridge->room_id);
3002
                                prev_count = 0;
3003
                        }
3004
                        continue;
3005
                }
3006
                if(prev_count == 0) {
3007
                        JANUS_LOG(LOG_VERB, "First user/forwarder just joined room %"SCNu64", waking it up...\n", audiobridge->room_id);
3008
                }
3009
                prev_count = count+rf_count;
3010
                /* Update RTP header information */
3011
                seq++;
3012
                ts += 960;
3013
                /* Mix all contributions */
3014
                janus_mutex_lock_nodebug(&audiobridge->mutex);
3015
                GList *participants_list = g_hash_table_get_values(audiobridge->participants);
3016
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
3017
                for(i=0; i<samples; i++)
3018
                        buffer[i] = 0;
3019
                GList *ps = participants_list;
3020
                while(ps) {
3021
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
3022
                        janus_mutex_lock(&p->qmutex);
3023
                        if(!p->active || p->muted || p->prebuffering || !p->inbuf) {
3024
                                janus_mutex_unlock(&p->qmutex);
3025
                                ps = ps->next;
3026
                                continue;
3027
                        }
3028
                        GList *peek = g_list_first(p->inbuf);
3029
                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)(peek ? peek->data : NULL);
3030
                        if(pkt != NULL) {
3031
                                curBuffer = (opus_int16 *)pkt->data;
3032
                                for(i=0; i<samples; i++)
3033
                                        buffer[i] += curBuffer[i];
3034
                        }
3035
                        janus_mutex_unlock(&p->qmutex);
3036
                        ps = ps->next;
3037
                }
3038
                /* Are we recording the mix? (only do it if there's someone in, though...) */
3039
                if(audiobridge->recording != NULL && g_list_length(participants_list) > 0) {
3040
                        for(i=0; i<samples; i++) {
3041
                                /* FIXME Smoothen/Normalize instead of truncating? */
3042
                                outBuffer[i] = buffer[i];
3043
                        }
3044
                        fwrite(outBuffer, sizeof(opus_int16), samples, audiobridge->recording);
3045
                        /* Every 5 seconds we update the wav header */
3046
                        gint64 now = janus_get_monotonic_time();
3047
                        if(now - audiobridge->record_lastupdate >= 5*G_USEC_PER_SEC) {
3048
                                audiobridge->record_lastupdate = now;
3049
                                /* Update the length in the header */
3050
                                fseek(audiobridge->recording, 0, SEEK_END);
3051
                                long int size = ftell(audiobridge->recording);
3052
                                if(size >= 8) {
3053
                                        size -= 8;
3054
                                        fseek(audiobridge->recording, 4, SEEK_SET);
3055
                                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3056
                                        size += 8;
3057
                                        fseek(audiobridge->recording, 40, SEEK_SET);
3058
                                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3059
                                        fflush(audiobridge->recording);
3060
                                        fseek(audiobridge->recording, 0, SEEK_END);
3061
                                }
3062
                        }
3063
                }
3064
                /* Send proper packet to each participant (remove own contribution) */
3065
                ps = participants_list;
3066
                while(ps) {
3067
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
3068
                        janus_audiobridge_rtp_relay_packet *pkt = NULL;
3069
                        janus_mutex_lock(&p->qmutex);
3070
                        if(p->active && !p->muted && !p->prebuffering && p->inbuf) {
3071
                                GList *first = g_list_first(p->inbuf);
3072
                                pkt = (janus_audiobridge_rtp_relay_packet *)(first ? first->data : NULL);
3073
                                p->inbuf = g_list_delete_link(p->inbuf, first);
3074
                        }
3075
                        janus_mutex_unlock(&p->qmutex);
3076
                        curBuffer = (opus_int16 *)(pkt ? pkt->data : NULL);
3077
                        for(i=0; i<samples; i++)
3078
                                sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]) : 0);
3079
                        for(i=0; i<samples; i++)
3080
                                /* FIXME Smoothen/Normalize instead of truncating? */
3081
                                outBuffer[i] = sumBuffer[i];
3082
                        /* Enqueue this mixed frame for encoding in the participant thread */
3083
                        janus_audiobridge_rtp_relay_packet *mixedpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
3084
                        if(mixedpkt != NULL) {
3085
                                mixedpkt->data = g_malloc0(samples*2);
3086
                                memcpy(mixedpkt->data, outBuffer, samples*2);
3087
                                mixedpkt->length = samples;        /* We set the number of samples here, not the data length */
3088
                                mixedpkt->timestamp = ts;
3089
                                mixedpkt->seq_number = seq;
3090
                                mixedpkt->ssrc = audiobridge->room_id;
3091
                                g_async_queue_push(p->outbuf, mixedpkt);
3092
                        }
3093
                        if(pkt) {
3094
                                if(pkt->data)
3095
                                        g_free(pkt->data);
3096
                                pkt->data = NULL;
3097
                                g_free(pkt);
3098
                                pkt = NULL;
3099
                        }
3100
                        ps = ps->next;
3101
                }
3102
                g_list_free(participants_list);
3103
                /* Forward the mixed packet as RTP to any RTP forwarder that may be listening */
3104
                janus_mutex_lock(&audiobridge->rtp_mutex);
3105
                if(g_hash_table_size(audiobridge->rtp_forwarders) > 0 && audiobridge->rtp_encoder) {
3106
                        /* If the room is empty, check if there's any RTP forwarder with an "always on" option */
3107
                        gboolean go_on = FALSE;
3108
                        if(count == 0) {
3109
                                GHashTableIter iter;
3110
                                gpointer value;
3111
                                g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
3112
                                while(g_hash_table_iter_next(&iter, NULL, &value)) {
3113
                                        janus_audiobridge_rtp_forwarder* forwarder = (janus_audiobridge_rtp_forwarder *)value;
3114
                                        if(forwarder->always_on) {
3115
                                                go_on = TRUE;
3116
                                                break;
3117
                                        }
3118
                                }
3119
                        } else {
3120
                                go_on = TRUE;
3121
                        }
3122
                        if(go_on) {
3123
                                /* Encode the mixed frame first*/
3124
                                for(i=0; i<samples; i++)
3125
                                        outBuffer[i] = buffer[i];
3126
                                opus_int32 length = opus_encode(audiobridge->rtp_encoder, outBuffer, samples, rtpbuffer+12, 1500-12);
3127
                                if(length < 0) {
3128
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", length, opus_strerror(length));
3129
                                } else {
3130
                                        /* Then send it to everybody */
3131
                                        GHashTableIter iter;
3132
                                        gpointer key, value;
3133
                                        g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
3134
                                        while(audiobridge->rtp_udp_sock > 0 && g_hash_table_iter_next(&iter, &key, &value)) {
3135
                                                guint32 stream_id = GPOINTER_TO_UINT(key);
3136
                                                janus_audiobridge_rtp_forwarder* forwarder = (janus_audiobridge_rtp_forwarder *)value;
3137
                                                if(count == 0 && !forwarder->always_on)
3138
                                                        continue;
3139
                                                /* Update header */
3140
                                                rtph->type = forwarder->payload_type;
3141
                                                rtph->ssrc = htonl(stream_id);
3142
                                                forwarder->seq_number++;
3143
                                                rtph->seq_number = htons(forwarder->seq_number);
3144
                                                forwarder->timestamp += 960;
3145
                                                rtph->timestamp = htonl(forwarder->timestamp);
3146
                                                /* Send RTP packet */
3147
                                                sendto(audiobridge->rtp_udp_sock, rtpbuffer, length+12, 0, (struct sockaddr*)&forwarder->serv_addr, sizeof(forwarder->serv_addr));
3148
                                        }
3149
                                }
3150
                        }
3151
                }
3152
                janus_mutex_unlock(&audiobridge->rtp_mutex);
3153
        }
3154
        if(audiobridge->recording) {
3155
                /* Update the length in the header */
3156
                fseek(audiobridge->recording, 0, SEEK_END);
3157
                long int size = ftell(audiobridge->recording);
3158
                if(size >= 8) {
3159
                        size -= 8;
3160
                        fseek(audiobridge->recording, 4, SEEK_SET);
3161
                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3162
                        size += 8;
3163
                        fseek(audiobridge->recording, 40, SEEK_SET);
3164
                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3165
                        fflush(audiobridge->recording);
3166
                        fclose(audiobridge->recording);
3167
                }
3168
        }
3169
        JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %"SCNu64" (%s)...\n", audiobridge->room_id, audiobridge->room_name);
3170

    
3171
        /* We'll let the watchdog worry about free resources */
3172
        old_rooms = g_list_append(old_rooms, audiobridge);
3173

    
3174
        return NULL;
3175
}
3176

    
3177
/* Thread to encode a mixed frame and send it to a specific participant */
3178
static void *janus_audiobridge_participant_thread(void *data) {
3179
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread starting...\n");
3180
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)data;
3181
        if(!participant) {
3182
                JANUS_LOG(LOG_ERR, "Invalid participant!\n");
3183
                g_thread_unref(g_thread_self());
3184
                return NULL;
3185
        }
3186
        JANUS_LOG(LOG_VERB, "Thread is for participant %"SCNu64" (%s)\n", participant->user_id, participant->display ? participant->display : "??");
3187
        janus_audiobridge_session *session = participant->session;
3188

    
3189
        /* Output buffer */
3190
        janus_audiobridge_rtp_relay_packet *outpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
3191
        outpkt->data = (rtp_header *)g_malloc0(1500);
3192
        outpkt->ssrc = 0;
3193
        outpkt->timestamp = 0;
3194
        outpkt->seq_number = 0;
3195
        unsigned char *payload = (unsigned char *)outpkt->data;
3196
        memset(payload, 0, 1500);
3197

    
3198
        janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
3199

    
3200
        /* Start working: check the outgoing queue for packets, then encode and send them */
3201
        while(!g_atomic_int_get(&stopping) && session->destroyed == 0) {
3202
                if(!participant->active || !participant->encoder) {
3203
                        /* Wait until the participant is in a room */
3204
                        g_usleep(10000);
3205
                        continue;
3206
                }
3207
                if(g_async_queue_length(participant->outbuf) == 0) {
3208
                        /* Nothing to do */
3209
                        g_usleep(5000);
3210
                        continue;
3211
                }
3212
                mixedpkt = g_async_queue_pop(participant->outbuf);
3213
                if(mixedpkt != NULL && session->destroyed == 0) {
3214
                        /* Encode raw frame to Opus */
3215
                        if(participant->active && participant->encoder) {
3216
                                participant->working = TRUE;
3217
                                opus_int16 *outBuffer = (opus_int16 *)mixedpkt->data;
3218
                                outpkt->length = opus_encode(participant->encoder, outBuffer, mixedpkt->length, payload+12, BUFFER_SAMPLES-12);
3219
                                participant->working = FALSE;
3220
                                if(outpkt->length < 0) {
3221
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", outpkt->length, opus_strerror(outpkt->length));
3222
                                } else {
3223
                                        outpkt->length += 12;        /* Take the RTP header into consideration */
3224
                                        /* Update RTP header */
3225
                                        outpkt->data->version = 2;
3226
                                        outpkt->data->markerbit = 0;        /* FIXME Should be 1 for the first packet */
3227
                                        outpkt->data->seq_number = htons(mixedpkt->seq_number);
3228
                                        outpkt->data->timestamp = htonl(mixedpkt->timestamp);
3229
                                        outpkt->data->ssrc = htonl(mixedpkt->ssrc);        /* The gateway will fix this anyway */
3230
                                        /* Backup the actual timestamp and sequence number set by the audiobridge, in case a room is changed */
3231
                                        outpkt->ssrc = mixedpkt->ssrc;
3232
                                        outpkt->timestamp = mixedpkt->timestamp;
3233
                                        outpkt->seq_number = mixedpkt->seq_number;
3234
                                        janus_audiobridge_relay_rtp_packet(participant->session, outpkt);
3235
                                }
3236
                        }
3237
                        if(mixedpkt) {
3238
                                if(mixedpkt->data)
3239
                                        g_free(mixedpkt->data);
3240
                                mixedpkt->data = NULL;
3241
                                g_free(mixedpkt);
3242
                                mixedpkt = NULL;
3243
                        }
3244
                }
3245
        }
3246
        /* We're done, get rid of the resources */
3247
        if(outpkt != NULL) {
3248
                if(outpkt->data != NULL) {
3249
                        g_free(outpkt->data);
3250
                        outpkt->data = NULL;
3251
                }
3252
                g_free(outpkt);
3253
                outpkt = NULL;
3254
        }
3255
        /* Empty the outgoing queue if there was something still in */
3256
        while(g_async_queue_length(participant->outbuf) > 0) {
3257
                janus_audiobridge_rtp_relay_packet *pkt = g_async_queue_pop(participant->outbuf);
3258
                if(pkt == NULL)
3259
                        continue;
3260
                if(pkt->data)
3261
                        g_free(pkt->data);
3262
                pkt->data = NULL;
3263
                g_free(pkt);
3264
                pkt = NULL;
3265
        }
3266
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread leaving...\n");
3267
        return NULL;
3268
}
3269

    
3270
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data) {
3271
        janus_audiobridge_rtp_relay_packet *packet = (janus_audiobridge_rtp_relay_packet *)user_data;
3272
        if(!packet || !packet->data || packet->length < 1) {
3273
                JANUS_LOG(LOG_ERR, "Invalid packet...\n");
3274
                return;
3275
        }
3276
        janus_audiobridge_session *session = (janus_audiobridge_session *)data;
3277
        if(!session || !session->handle) {
3278
                // JANUS_LOG(LOG_ERR, "Invalid session...\n");
3279
                return;
3280
        }
3281
        if(!session->started) {
3282
                // JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
3283
                return;
3284
        }
3285
        janus_audiobridge_participant *participant = session->participant;
3286
        /* Set the payload type */
3287
        packet->data->type = participant->opus_pt;
3288
        /* Fix sequence number and timestamp (room switching may be involved) */
3289
        if(ntohl(packet->data->ssrc) != participant->context.a_last_ssrc) {
3290
                participant->context.a_last_ssrc = ntohl(packet->data->ssrc);
3291
                participant->context.a_base_ts_prev = participant->context.a_last_ts;
3292
                participant->context.a_base_ts = packet->timestamp;
3293
                participant->context.a_base_seq_prev = participant->context.a_last_seq;
3294
                participant->context.a_base_seq = packet->seq_number;
3295
        }
3296
        /* Compute a coherent timestamp and sequence number */
3297
        participant->context.a_last_ts = (packet->timestamp-participant->context.a_base_ts)
3298
                + participant->context.a_base_ts_prev+960;        /* FIXME When switching, we assume Opus and so a 960 ts step */
3299
        participant->context.a_last_seq = (packet->seq_number-participant->context.a_base_seq)+participant->context.a_base_seq_prev+1;
3300
        /* Update the timestamp and sequence number in the RTP packet, and send it */
3301
        packet->data->timestamp = htonl(participant->context.a_last_ts);
3302
        packet->data->seq_number = htons(participant->context.a_last_seq);
3303
        if(gateway != NULL)
3304
                gateway->relay_rtp(session->handle, 0, (char *)packet->data, packet->length);
3305
        /* Restore the timestamp and sequence number to what the publisher set them to */
3306
        packet->data->timestamp = htonl(packet->timestamp);
3307
        packet->data->seq_number = htons(packet->seq_number);
3308
}