Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_audiobridge.c @ 5de69b28

History | View | Annotate | Download (159 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
audiolevel_ext = yes|no (whether the ssrc-audio-level RTP extension must be
30
        negotiated/used or not for new joins, default=yes)
31
record = true|false (whether this room should be recorded, default=false)
32
record_file =        /path/to/recording.wav (where to save the recording)
33
\endverbatim
34
 *
35
 * \section bridgeapi Audio Bridge API
36
 * 
37
 * The Audio Bridge API supports several requests, some of which are
38
 * synchronous and some asynchronous. There are some situations, though,
39
 * (invalid JSON, invalid request) which will always result in a
40
 * synchronous error response even for asynchronous requests. 
41
 * 
42
 * \c create , \c destroy , \c exists, \c allowed, \c kick, \c list,
43
 * \c listparticipants and \c resetdecoder are synchronous requests,
44
 * which means you'll get a response directly within the context of the
45
 * transaction. \c create allows you to create a new audio conference bridge
46
 * dynamically, as an alternative to using the configuration file;
47
 * \c destroy removes an audio conference bridge and destroys it, kicking
48
 * all the users out as part of the process; \c exists allows you to
49
 * check whether a specific audio conference exists; \c allowed allows
50
 * you to edit who's allowed to join a room via ad-hoc tokens; \c list
51
 * lists all the available rooms, while \c listparticipants lists all
52
 * the participants of a specific room and their details; finally,
53
 * \c resetdecoder marks the Opus decoder for the participant as invalid,
54
 * and forces it to be recreated (which might be needed if the audio
55
 * for generated by the participant becomes garbled). 
56
 * 
57
 * The \c join , \c configure , \c changeroom and \c leave requests
58
 * instead are all asynchronous, which means you'll get a notification
59
 * about their success or failure in an event. \c join allows you to
60
 * join a specific audio conference bridge; \c configure can be used
61
 * to modify some of the participation settings (e.g., mute/unmute);
62
 * \c changeroom can be used to leave the current room and move to a
63
 * different one without having to tear down the PeerConnection and
64
 * recreate it again (useful for sidebars and "waiting rooms"); finally,
65
 * \c leave allows you to leave an audio conference bridge for good.
66
 * 
67
 * The AudioBridge plugin also allows you to forward the mix to an
68
 * external listener, e.g., a gstreamer/ffmpeg pipeline waiting to
69
 * process the mixer audio stream. You can add new RTP forwarders with
70
 * the \c rtp_forward request; a \c stop_rtp_forward request removes an
71
 * existing RTP forwarder; \c listforwarders lists all the current RTP
72
 * forwarders on a specific AudioBridge room instance.
73
 *
74
 * \c create can be used to create a new audio room, and has to be
75
 * formatted as follows:
76
 * 
77
\verbatim
78
{
79
        "request" : "create",
80
        "room" : <unique numeric ID, optional, chosen by plugin if missing>,
81
        "permanent" : <true|false, whether the room should be saved in the config file, default false>,
82
        "description" : "<pretty name of the room, optional>",
83
        "secret" : "<password required to edit/destroy the room, optional>",
84
        "pin" : "<password required to join the room, optional>",
85
        "is_private" : <true|false, whether the room should appear in a list request>,
86
        "allowed" : [ array of string tokens users can use to join this room, optional],
87
        "sampling" : <sampling rate of the room, optional, 16000 by default>,
88
        "audiolevel_ext" : <true|false, whether the ssrc-audio-level RTP extension must be negotiated for new joins, default true>,
89
        "audiolevel_event" : yes|no (whether to emit event to other users or not),
90
        "audio_active_packets" : 100 (number of packets with audio level, default=100, 2 seconds),
91
        "audio_level_average" : 25 (average value of audio level, 127=muted, 0='too loud', default=25),
92
        "record" : <true|false, whether to record the room or not, default false>,
93
        "record_file" : "</path/to/the/recording.wav, optional>",
94
}
95
\endverbatim
96
 *
97
 * A successful creation procedure will result in a \c created response:
98
 * 
99
\verbatim
100
{
101
        "audiobridge" : "created",
102
        "room" : <unique numeric ID>,
103
        "permanent" : <true if saved to config file, false if not>
104
}
105
\endverbatim
106
 *
107
 * If you requested a permanent room but a \c false value is returned
108
 * instead, good chances are that there are permission problems.
109
 *
110
 * An error instead (and the same applies to all other requests, so this
111
 * won't be repeated) would provide both an error code and a more verbose
112
 * description of the cause of the issue:
113
 * 
114
\verbatim
115
{
116
        "audiobridge" : "event",
117
        "error_code" : <numeric ID, check Macros below>,
118
        "error" : "<error description as a string>"
119
}
120
\endverbatim
121
 * 
122
 * Notice that, in general, all users can create rooms. If you want to
123
 * limit this functionality, you can configure an admin \c admin_key in
124
 * the plugin settings. When configured, only "create" requests that
125
 * include the correct \c admin_key value in an "admin_key" property
126
 * will succeed, and will be rejected otherwise.
127
 * 
128
 * On the other hand, \c destroy can be used to destroy an existing audio
129
 * room, whether created dynamically or statically, and has to be
130
 * formatted as follows:
131
 * 
132
\verbatim
133
{
134
        "request" : "destroy",
135
        "room" : <unique numeric ID of the room to destroy>,
136
        "secret" : "<room secret, mandatory if configured>",
137
        "permanent" : <true|false, whether the room should be also removed from the config file, default false>
138
}
139
\endverbatim
140
 *
141
 * A successful destruction procedure will result in a \c destroyed response:
142
 * 
143
\verbatim
144
{
145
        "audiobridge" : "created",
146
        "room" : <unique numeric ID>
147
}
148
\endverbatim
149
 *
150
 * You can check whether a room exists using the \c exists request,
151
 * which has to be formatted as follows:
152
 * 
153
\verbatim
154
{
155
        "request" : "exists",
156
        "room" : <unique numeric ID of the room to check>
157
}
158
\endverbatim
159
 *
160
 * A successful request will result in a \c success response:
161
 * 
162
\verbatim
163
{
164
        "audiobridge" : "success",
165
        "room" : <unique numeric ID>,
166
        "exists" : <true|false>
167
}
168
\endverbatim
169
 * 
170
 * You can configure whether to check tokens or add/remove people who can join
171
 * a room using the \c allowed request, which has to be formatted as follows:
172
 *
173
\verbatim
174
{
175
        "request" : "allowed",
176
        "secret" : "<room secret, mandatory if configured>",
177
        "action" : "enable|disable|add|remove",
178
        "room" : <unique numeric ID of the room to update>,
179
        "allowed" : [
180
                // Array of strings (tokens users might pass in "join", only for add|remove)
181
        ]
182
}
183
\endverbatim
184
 *
185
 * A successful request will result in a \c success response:
186
 *
187
\verbatim
188
{
189
        "audiobridge" : "success",
190
        "room" : <unique numeric ID>,
191
        "allowed" : [
192
                // Updated, complete, list of allowed tokens (only for enable|add|remove)
193
        ]
194
}
195
\endverbatim
196
 *
197
 * If you're the administrator of a room (that is, you created it and have access
198
 * to the secret) you can kick participants using the \c kick request. Notice
199
 * that this only kicks the user out of the room, but does not prevent them from
200
 * re-joining: to ban them, you need to first remove them from the list of
201
 * authorized users (see \c allowed request) and then \c kick them. The \c kick
202
 * request has to be formatted as follows:
203
 *
204
\verbatim
205
{
206
        "request" : "kick",
207
        "secret" : "<room secret, mandatory if configured>",
208
        "room" : <unique numeric ID of the room>,
209
        "id" : <unique numeric ID of the participant to kick>
210
}
211
\endverbatim
212
 *
213
 * A successful request will result in a \c success response:
214
 *
215
\verbatim
216
{
217
        "audiobridge" : "success",
218
}
219
\endverbatim
220
 *
221
 * To get a list of the available rooms (excluded those configured or
222
 * created as private rooms) you can make use of the \c list request,
223
 * which has to be formatted as follows:
224
 * 
225
\verbatim
226
{
227
        "request" : "list"
228
}
229
\endverbatim
230
 *
231
 * A successful request will produce a list of rooms in a \c success response:
232
 * 
233
\verbatim
234
{
235
        "audiobridge" : "success",
236
        "rooms" : [                // Array of room objects
237
                {        // Room #1
238
                        "room" : <unique numeric ID>,
239
                        "description" : "<Name of the room>",
240
                        "sampling_rate" : <sampling rate of the mixer>,
241
                        "record" : <true|false, whether the room is being recorded>,
242
                        "num_participants" : <count of the participants>
243
                },
244
                // Other rooms
245
        ]
246
}
247
\endverbatim
248
 *
249
 * To get a list of the participants in a specific room, instead, you
250
 * can make use of the \c listparticipants request, which has to be
251
 * formatted as follows:
252
 * 
253
\verbatim
254
{
255
        "request" : "listparticipants",
256
        "room" : <unique numeric ID of the room>
257
}
258
\endverbatim
259
 *
260
 * A successful request will produce a list of participants in a
261
 * \c participants response:
262
 * 
263
\verbatim
264
{
265
        "audiobridge" : "participants",
266
        "room" : <unique numeric ID of the room>,
267
        "participants" : [                // Array of participant objects
268
                {        // Participant #1
269
                        "id" : <unique numeric ID of the participant>,
270
                        "display" : "<display name of the participant, if any; optional>",
271
                        "muted" : <true|false, whether user is muted or not>
272
                },
273
                // Other participants
274
        ]
275
}
276
\endverbatim
277
 * 
278
 * To mark the Opus decoder context for the current participant as
279
 * invalid and force it to be recreated, use the \c resetdecoder request:
280
 * 
281
\verbatim
282
{
283
        "request" : "resetdecoder"
284
}
285
\endverbatim
286
 *
287
 * A successful request will produce a \c success response:
288
 * 
289
\verbatim
290
{
291
        "audiobridge" : "success"
292
}
293
\endverbatim
294
 * 
295
 * You can add a new RTP forwarder for an existing room exists using the
296
 * \c rtp_forward request, which has to be formatted as follows:
297
 *
298
\verbatim
299
{
300
        "request" : "rtp_forward",
301
        "room" : <unique numeric ID of the room to add the forwarder to>,
302
        "ssrc" : <SSRC to use to use when streaming (optional: stream_id used if missing)>,
303
        "ptype" : <payload type to use when streaming (optional: 100 used if missing)>,
304
        "host" : "<host address to forward the RTP packets to>",
305
        "port" : <port to forward the RTP packets to>,
306
        "always_on" : <true|false, whether silence should be forwarded when the room is empty>
307
}
308
\endverbatim
309
 *
310
 * A successful request will result in a \c success response:
311
 *
312
\verbatim
313
{
314
        "audiobridge" : "success",
315
        "room" : <unique numeric ID, same as request>,
316
        "stream_id" : <unique numeric ID assigned to the new RTP forwarder>
317
}
318
\endverbatim
319
 *
320
 * To stop a previously created RTP forwarder and stop it, you can use
321
 * the \c stop_rtp_forward request, which has to be formatted as follows:
322
 *
323
\verbatim
324
{
325
        "request" : "stop_rtp_forward",
326
        "room" : <unique numeric ID of the room to remove the forwarder from>,
327
        "stream_id" : <unique numeric ID of the RTP forwarder>
328
}
329
\endverbatim
330
 *
331
 * A successful request will result in a \c success response:
332
 *
333
\verbatim
334
{
335
        "audiobridge" : "success",
336
        "room" : <unique numeric ID, same as request>,
337
        "stream_id" : <unique numeric ID, same as request>
338
}
339
\endverbatim
340
 *
341
 * To get a list of the forwarders in a specific room, instead, you
342
 * can make use of the \c listforwarders request, which has to be
343
 * formatted as follows:
344
 *
345
\verbatim
346
{
347
        "request" : "listforwarders",
348
        "room" : <unique numeric ID of the room>
349
}
350
\endverbatim
351
 *
352
 * A successful request will produce a list of RTP forwarders in a
353
 * \c forwarders response:
354
 *
355
\verbatim
356
{
357
        "audiobridge" : "forwarders",
358
        "room" : <unique numeric ID of the room>,
359
        "rtp_forwarders" : [                // Array of RTP forwarder objects
360
                {        // RTP forwarder #1
361
                        "stream_id" : <unique numeric ID of the forwarder>,
362
                        "ip" : "<IP this forwarder is streaming to>",
363
                        "port" : <port this forwarder is streaming to>,
364
                        "ssrc" : <SSRC this forwarder is using, if any>,
365
                        "ptype" : <payload type this forwarder is using, if any>
366
                },
367
                // Other forwarders
368
        ]
369
}
370
\endverbatim
371
 *
372
 * That completes the list of synchronous requests you can send to the
373
 * AudioBridge plugin. As anticipated, though, there are also several
374
 * asynchronous requests you can send, specifically those related to
375
 * joining and updating one's presence as a participant in an audio room.
376
 * 
377
 * The way you'd interact with the plugin is usually as follows:
378
 * 
379
 * -# you use a \c join request to join an audio room, and wait for the
380
 * \c joined event; this event will also include a list of the other
381
 * participants, if any;
382
 * -# you send a \c configure request attached to an audio-only JSEP offer
383
 * to start configuring your participation in the room (e.g., join unmuted
384
 * or muted), and wait for a \c configured event, which will be attached
385
 * to a JSEP answer by the plugin to complete the setup of the WebRTC
386
 * PeerConnection;
387
 * -# you send other \c configure requests (without any JSEP-related
388
 * attachment) to mute/unmute yourself during the audio conference;
389
 * -# you intercept events originated by the plugin (\c joined , \c leaving )
390
 * to notify you about users joining/leaving/muting/unmuting;
391
 * -# you eventually send a \c leave request to leave a room; if you leave the
392
 * PeerConnection instance intact, you can subsequently join a different
393
 * room without requiring a new negotiation (and so just use a \c join + JSEP-less \c configure to join).
394
 * 
395
 * Notice that there's also a \c changeroom request available: you can use
396
 * this request to immediately leave the room you're in and join a different
397
 * one, without requiring you to do a \c leave + \c join + \c configure
398
 * round. Of course remember not to pass any JSEP-related payload when
399
 * doing a \c changeroom as the same pre-existing PeerConnection will be
400
 * re-used for the purpose.
401
 * 
402
 * About the syntax of all the above mentioned requests, \c join has
403
 * to be formatted as follows:
404
 * 
405
\verbatim
406
{
407
        "request" : "join",
408
        "room" : <numeric ID of the room to join>,
409
        "id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
410
        "pin" : "<password required to join the room, if any; optional>",
411
        "display" : "<display name to have in the room; optional>",
412
        "token" : "<invitation token, in case the room has an ACL; optional>",
413
        "muted" : <true|false, whether to start unmuted or muted>,
414
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>,
415
        "volume" : <percent value, <100 reduces volume, >100 increases volume; optional, default is 100 (no volume change)>
416
}
417
\endverbatim
418
 *
419
 * A successful request will produce a \c joined event:
420
 * 
421
\verbatim
422
{
423
        "audiobridge" : "joined",
424
        "room" : <numeric ID of the room>,
425
        "id" : <unique ID assigned to the participant>,
426
        "display" : "<display name of the new participant>",
427
        "participants" : [
428
                // Array of existing participants in the room
429
        ]
430
}
431
\endverbatim
432
 * 
433
 * The other participants in the room will be notified about the new
434
 * participant by means of a different \c joined event, which will only
435
 * include the \c room and the new participant as the only object in
436
 * a \c participants array.
437
 *
438
 * At this point, the media-related settings of the participant can be
439
 * modified by means of a \c configure request. The \c configure request
440
 * has to be formatted as follows (notice that all parameters except
441
 * \c request are optional, depending on what you want to change):
442
 *
443
\verbatim
444
{
445
        "request" : "configure",
446
        "muted" : <true|false, whether to unmute or mute>,
447
        "display" : "<new display name to have in the room>",
448
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>,
449
        "volume" : <percent value, <100 reduces volume, >100 increases volume; optional, default is 100 (no volume change)>,
450
        "record": <true|false, whether to record this user's contribution to a .mjr file (mixer not involved),
451
        "filename": "<basename of the file to record to, -audio.mjr will be added by the plugin>"
452
}
453
\endverbatim
454
 *
455
 * \c muted instructs the plugin to mute or unmute the participant;
456
 * \c quality changes the complexity of the Opus encoder for the
457
 * participant; \c record can be used to record this participant's contribution
458
 * to a Janus .mjr file, and \c filename to provide a basename for the path to
459
 * save the file to (notice that this is different from the recording of a whole
460
 * room: this feature only records the packets this user is sending, and is not
461
 * related to the mixer stuff). A successful request will result in a \c ok event:
462
 * 
463
\verbatim
464
{
465
        "audiobridge" : "event",
466
        "room" : <numeric ID of the room>,
467
        "result" : "ok"
468
}
469
\endverbatim
470
 *
471
 * In case the \c muted property was modified, the other participants in
472
 * the room will be notified about this by means of a \c event notification,
473
 * which will only include the \c room and the updated participant as the
474
 * only object in a \c participants array.
475
 *
476
 * As anticipated, you can leave an audio room using the \c leave request,
477
 * which has to be formatted as follows:
478
 * 
479
\verbatim
480
{
481
        "request" : "leave"
482
}
483
\endverbatim
484
 * 
485
 * All the participants will receive an \c event notification with the
486
 * ID of the participant who just left:
487
 * 
488
\verbatim
489
{
490
        "audiobridge" : "event",
491
        "room" : <numeric ID of the room>,
492
        "leaving" : <numeric ID of the participant who left>
493
}
494
\endverbatim
495
 *
496
 * For what concerns the \c changeroom request, instead, it's pretty much
497
 * the same as a \c join request and as such has to be formatted as follows:
498
 * 
499
\verbatim
500
{
501
        "request" : "changeroom",
502
        "room" : <numeric ID of the room to move to>,
503
        "id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
504
        "display" : "<display name to have in the room; optional>",
505
        "token" : "<invitation token, in case the new room has an ACL; optional>",
506
        "muted" : <true|false, whether to start unmuted or muted>,
507
        "quality" : <0-10, Opus-related complexity to use, lower is higher quality; optional, default is 4>
508
}
509
\endverbatim
510
 * 
511
 * Such a request will trigger all the above-described leaving/joined
512
 * events to the other participants, as it is indeed wrapping a \c leave
513
 * followed by a \c join and as such the other participants in both rooms
514
 * need to be updated accordingly. The participant who switched room
515
 * instead will be sent a \c roomchanged event which is pretty similar
516
 * to what \c joined looks like:
517
 * 
518
 * A successful request will produce a \c joined event:
519
 * 
520
\verbatim
521
{
522
        "audiobridge" : "roomchanged",
523
        "room" : <numeric ID of the new room>,
524
        "id" : <unique ID assigned to the participant in the new room>,
525
        "display" : "<display name of the new participant>",
526
        "participants" : [
527
                // Array of existing participants in the new room
528
        ]
529
}
530
\endverbatim
531
 *  
532
 * \ingroup plugins
533
 * \ref plugins
534
 */
535

    
536
#include "plugin.h"
537

    
538
#include <jansson.h>
539
#include <opus/opus.h>
540
#include <sys/time.h>
541

    
542
#include "../debug.h"
543
#include "../apierror.h"
544
#include "../config.h"
545
#include "../mutex.h"
546
#include "../rtp.h"
547
#include "../rtcp.h"
548
#include "../record.h"
549
#include "../sdp-utils.h"
550
#include "../utils.h"
551

    
552

    
553
/* Plugin information */
554
#define JANUS_AUDIOBRIDGE_VERSION                        10
555
#define JANUS_AUDIOBRIDGE_VERSION_STRING        "0.0.10"
556
#define JANUS_AUDIOBRIDGE_DESCRIPTION                "This is a plugin implementing an audio conference bridge for Janus, mixing Opus streams."
557
#define JANUS_AUDIOBRIDGE_NAME                                "JANUS AudioBridge plugin"
558
#define JANUS_AUDIOBRIDGE_AUTHOR                        "Meetecho s.r.l."
559
#define JANUS_AUDIOBRIDGE_PACKAGE                        "janus.plugin.audiobridge"
560

    
561
/* Plugin methods */
562
janus_plugin *create(void);
563
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path);
564
void janus_audiobridge_destroy(void);
565
int janus_audiobridge_get_api_compatibility(void);
566
int janus_audiobridge_get_version(void);
567
const char *janus_audiobridge_get_version_string(void);
568
const char *janus_audiobridge_get_description(void);
569
const char *janus_audiobridge_get_name(void);
570
const char *janus_audiobridge_get_author(void);
571
const char *janus_audiobridge_get_package(void);
572
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error);
573
struct janus_plugin_result *janus_audiobridge_handle_message(janus_plugin_session *handle, char *transaction, json_t *message, json_t *jsep);
574
void janus_audiobridge_setup_media(janus_plugin_session *handle);
575
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len);
576
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len);
577
void janus_audiobridge_hangup_media(janus_plugin_session *handle);
578
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error);
579
json_t *janus_audiobridge_query_session(janus_plugin_session *handle);
580

    
581
/* Plugin setup */
582
static janus_plugin janus_audiobridge_plugin =
583
        JANUS_PLUGIN_INIT (
584
                .init = janus_audiobridge_init,
585
                .destroy = janus_audiobridge_destroy,
586

    
587
                .get_api_compatibility = janus_audiobridge_get_api_compatibility,
588
                .get_version = janus_audiobridge_get_version,
589
                .get_version_string = janus_audiobridge_get_version_string,
590
                .get_description = janus_audiobridge_get_description,
591
                .get_name = janus_audiobridge_get_name,
592
                .get_author = janus_audiobridge_get_author,
593
                .get_package = janus_audiobridge_get_package,
594
                
595
                .create_session = janus_audiobridge_create_session,
596
                .handle_message = janus_audiobridge_handle_message,
597
                .setup_media = janus_audiobridge_setup_media,
598
                .incoming_rtp = janus_audiobridge_incoming_rtp,
599
                .incoming_rtcp = janus_audiobridge_incoming_rtcp,
600
                .hangup_media = janus_audiobridge_hangup_media,
601
                .destroy_session = janus_audiobridge_destroy_session,
602
                .query_session = janus_audiobridge_query_session,
603
        );
604

    
605
/* Plugin creator */
606
janus_plugin *create(void) {
607
        JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_AUDIOBRIDGE_NAME);
608
        return &janus_audiobridge_plugin;
609
}
610

    
611
/* Parameter validation */
612
static struct janus_json_parameter request_parameters[] = {
613
        {"request", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
614
};
615
static struct janus_json_parameter adminkey_parameters[] = {
616
        {"admin_key", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}
617
};
618
static struct janus_json_parameter create_parameters[] = {
619
        {"description", JSON_STRING, 0},
620
        {"secret", JSON_STRING, 0},
621
        {"pin", JSON_STRING, 0},
622
        {"is_private", JANUS_JSON_BOOL, 0},
623
        {"allowed", JSON_ARRAY, 0},
624
        {"sampling", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
625
        {"record", JANUS_JSON_BOOL, 0},
626
        {"record_file", JSON_STRING, 0},
627
        {"permanent", JANUS_JSON_BOOL, 0},
628
        {"audiolevel_ext", JANUS_JSON_BOOL, 0},
629
        {"audiolevel_event", JANUS_JSON_BOOL, 0},
630
        {"audio_active_packets", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
631
        {"audio_level_average", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
632
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
633
};
634
static struct janus_json_parameter destroy_parameters[] = {
635
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
636
        {"permanent", JANUS_JSON_BOOL, 0}
637
};
638
static struct janus_json_parameter allowed_parameters[] = {
639
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
640
        {"secret", JSON_STRING, 0},
641
        {"action", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
642
        {"allowed", JSON_ARRAY, 0}
643
};
644
static struct janus_json_parameter kick_parameters[] = {
645
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
646
        {"secret", JSON_STRING, 0},
647
        {"id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
648
};
649
static struct janus_json_parameter room_parameters[] = {
650
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
651
};
652
static struct janus_json_parameter join_parameters[] = {
653
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
654
        {"display", JSON_STRING, 0},
655
        {"token", JSON_STRING, 0},
656
        {"muted", JANUS_JSON_BOOL, 0},
657
        {"quality", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
658
        {"volume", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
659
        {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
660
};
661
static struct janus_json_parameter configure_parameters[] = {
662
        {"muted", JANUS_JSON_BOOL, 0},
663
        {"quality", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
664
        {"volume", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
665
        {"record", JANUS_JSON_BOOL, 0},
666
        {"filename", JSON_STRING, 0},
667
        {"display", JSON_STRING, 0}
668
};
669
static struct janus_json_parameter rtp_forward_parameters[] = {
670
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
671
        {"ssrc", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
672
        {"ptype", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
673
        {"port", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
674
        {"host", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
675
        {"always_on", JANUS_JSON_BOOL, 0}
676
};
677
static struct janus_json_parameter stop_rtp_forward_parameters[] = {
678
        {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
679
        {"stream_id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}
680
};
681

    
682
/* Static configuration instance */
683
static janus_config *config = NULL;
684
static const char *config_folder = NULL;
685
static janus_mutex config_mutex;
686

    
687
/* Useful stuff */
688
static volatile gint initialized = 0, stopping = 0;
689
static gboolean notify_events = TRUE;
690
static janus_callbacks *gateway = NULL;
691
static GThread *handler_thread;
692
static GThread *watchdog;
693
static void *janus_audiobridge_handler(void *data);
694
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data);
695
static void *janus_audiobridge_mixer_thread(void *data);
696
static void *janus_audiobridge_participant_thread(void *data);
697

    
698
typedef struct janus_audiobridge_message {
699
        janus_plugin_session *handle;
700
        char *transaction;
701
        json_t *message;
702
        json_t *jsep;
703
} janus_audiobridge_message;
704
static GAsyncQueue *messages = NULL;
705
static janus_audiobridge_message exit_message;
706

    
707
static void janus_audiobridge_message_free(janus_audiobridge_message *msg) {
708
        if(!msg || msg == &exit_message)
709
                return;
710

    
711
        msg->handle = NULL;
712

    
713
        g_free(msg->transaction);
714
        msg->transaction = NULL;
715
        if(msg->message)
716
                json_decref(msg->message);
717
        msg->message = NULL;
718
        if(msg->jsep)
719
                json_decref(msg->jsep);
720
        msg->jsep = NULL;
721

    
722
        g_free(msg);
723
}
724

    
725

    
726
typedef struct janus_audiobridge_room {
727
        guint64 room_id;                        /* Unique room ID */
728
        gchar *room_name;                        /* Room description */
729
        gchar *room_secret;                        /* Secret needed to manipulate (e.g., destroy) this room */
730
        gchar *room_pin;                        /* Password needed to join this room, if any */
731
        gboolean is_private;                /* Whether this room is 'private' (as in hidden) or not */
732
        uint32_t sampling_rate;                /* Sampling rate of the mix (e.g., 16000 for wideband; can be 8, 12, 16, 24 or 48kHz) */
733
        gboolean audiolevel_ext;        /* Whether the ssrc-audio-level extension must be negotiated or not for new joins */
734
        gboolean audiolevel_event;        /* Whether to emit event to other users about audiolevel */
735
        int audio_active_packets;        /* amount of packets with audio level for checkup */
736
        int audio_level_average;        /* average audio level */
737
        gboolean record;                        /* Whether this room has to be recorded or not */
738
        gchar *record_file;                        /* Path of the recording file */
739
        FILE *recording;                        /* File to record the room into */
740
        gint64 record_lastupdate;        /* Time when we last updated the wav header */
741
        gboolean destroy;                        /* Value to flag the room for destruction */
742
        GHashTable *participants;        /* Map of participants */
743
        gboolean check_tokens;                /* Whether to check tokens when participants join (see below) */
744
        GHashTable *allowed;                /* Map of participants (as tokens) allowed to join */
745
        GThread *thread;                        /* Mixer thread for this room */
746
        gint64 destroyed;                        /* When this room has been destroyed */
747
        janus_mutex mutex;                        /* Mutex to lock this room instance */
748
        /* RTP forwarders for this room's mix */
749
        GHashTable *rtp_forwarders;        /* RTP forwarders list (as a hashmap) */
750
        OpusEncoder *rtp_encoder;        /* Opus encoder instance to use for all RTP forwarders */
751
        janus_mutex rtp_mutex;                /* Mutex to lock the RTP forwarders list */
752
        int rtp_udp_sock;                        /* UDP socket to use to forward RTP packets */
753
} janus_audiobridge_room;
754
static GHashTable *rooms;
755
static janus_mutex rooms_mutex;
756
static GList *old_rooms;
757
static char *admin_key = NULL;
758

    
759
typedef struct janus_audiobridge_session {
760
        janus_plugin_session *handle;
761
        gpointer participant;
762
        gboolean started;
763
        gboolean stopping;
764
        volatile gint hangingup;
765
        gint64 destroyed;        /* Time at which this session was marked as destroyed */
766
} janus_audiobridge_session;
767
static GHashTable *sessions;
768
static GList *old_sessions;
769
static janus_mutex sessions_mutex;
770

    
771
typedef struct janus_audiobridge_participant {
772
        janus_audiobridge_session *session;
773
        janus_audiobridge_room *room;        /* Room */
774
        guint64 user_id;                /* Unique ID in the room */
775
        gchar *display;                        /* Display name (opaque value, only meaningful to application) */
776
        gboolean prebuffering;        /* Whether this participant needs pre-buffering of a few packets (just joined) */
777
        gboolean active;                /* Whether this participant can receive media at all */
778
        gboolean working;                /* Whether this participant is currently encoding/decoding */
779
        gboolean muted;                        /* Whether this participant is muted */
780
        int volume_gain;                /* Gain to apply to the input audio (in percentage) */
781
        int opus_complexity;        /* Complexity to use in the encoder (by default, DEFAULT_COMPLEXITY) */
782
        /* RTP stuff */
783
        GList *inbuf;                        /* Incoming audio from this participant, as an ordered list of packets */
784
        GAsyncQueue *outbuf;        /* Mixed audio for this participant */
785
        gint64 last_drop;                /* When we last dropped a packet because the imcoming queue was full */
786
        janus_mutex qmutex;                /* Incoming queue mutex */
787
        int opus_pt;                        /* Opus payload type */
788
        int extmap_id;                        /* Audio level RTP extension id, if any */
789
        int dBov_level;                        /* Value in dBov of the audio level (last value from extension) */
790
        int audio_active_packets;   /* participants number of audio packets to accumulate */
791
        int audio_dBov_sum;            /* participants accumulated dBov value for audio level */
792
        janus_rtp_switching_context context;        /* Needed in case the participant changes room */
793
        /* Opus stuff */
794
        OpusEncoder *encoder;                /* Opus encoder instance */
795
        OpusDecoder *decoder;                /* Opus decoder instance */
796
        gboolean reset;                                /* Whether or not the Opus context must be reset, without re-joining the room */
797
        GThread *thread;                        /* Encoding thread for this participant */
798
        janus_recorder *arc;                /* The Janus recorder instance for this user's audio, if enabled */
799
        janus_mutex rec_mutex;                /* Mutex to protect the recorder from race conditions */
800
        gint64 destroyed;                        /* When this participant has been destroyed */
801
} janus_audiobridge_participant;
802

    
803
/* Packets we get from gstreamer and relay */
804
typedef struct janus_audiobridge_rtp_relay_packet {
805
        rtp_header *data;
806
        gint length;
807
        uint32_t ssrc;
808
        uint32_t timestamp;
809
        uint16_t seq_number;
810
        gboolean silence;
811
} janus_audiobridge_rtp_relay_packet;
812

    
813
/* RTP forwarder instance: address to send to, and current RTP header info */
814
typedef struct janus_audiobridge_rtp_forwarder {
815
        struct sockaddr_in serv_addr;
816
        uint32_t ssrc;
817
        int payload_type;
818
        uint16_t seq_number;
819
        uint32_t timestamp;
820
        gboolean always_on;
821
} janus_audiobridge_rtp_forwarder;
822
static guint32 janus_audiobridge_rtp_forwarder_add_helper(janus_audiobridge_room *room, const gchar* host, uint16_t port, uint32_t ssrc, int pt, gboolean always_on) {
823
        if(room == NULL || host == NULL)
824
                return 0;
825
        janus_audiobridge_rtp_forwarder *rf = g_malloc0(sizeof(janus_audiobridge_rtp_forwarder));
826
        /* Resolve address */
827
        rf->serv_addr.sin_family = AF_INET;
828
        inet_pton(AF_INET, host, &(rf->serv_addr.sin_addr));
829
        rf->serv_addr.sin_port = htons(port);
830
        /* Setup RTP info (we'll use the stream ID as SSRC) */
831
        rf->ssrc = ssrc;
832
        rf->payload_type = pt;
833
        rf->seq_number = 0;
834
        rf->timestamp = 0;
835
        rf->always_on = always_on;
836
        janus_mutex_lock(&room->rtp_mutex);
837
        guint32 stream_id = janus_random_uint32();
838
        while(g_hash_table_lookup(room->rtp_forwarders, GUINT_TO_POINTER(stream_id)) != NULL) {
839
                stream_id = janus_random_uint32();
840
        }
841
        g_hash_table_insert(room->rtp_forwarders, GUINT_TO_POINTER(stream_id), rf);
842
        janus_mutex_unlock(&room->rtp_mutex);
843
        JANUS_LOG(LOG_VERB, "Added RTP forwarder to room %"SCNu64": %s:%d (ID: %"SCNu32")\n",
844
                room->room_id, host, port, stream_id);
845
        return stream_id;
846
}
847

    
848

    
849
/* Helper to sort incoming RTP packets by sequence numbers */
850
static gint janus_audiobridge_rtp_sort(gconstpointer a, gconstpointer b) {
851
        janus_audiobridge_rtp_relay_packet *pkt1 = (janus_audiobridge_rtp_relay_packet *)a;
852
        janus_audiobridge_rtp_relay_packet *pkt2 = (janus_audiobridge_rtp_relay_packet *)b;
853
        if(pkt1->seq_number < 100 && pkt2->seq_number > 65000) {
854
                /* Sequence number was probably reset, pkt2 is older */
855
                return 1;
856
        } else if(pkt2->seq_number < 100 && pkt1->seq_number > 65000) {
857
                /* Sequence number was probably reset, pkt1 is older */
858
                return -1;
859
        }
860
        /* Simply compare timestamps */
861
        if(pkt1->seq_number < pkt2->seq_number)
862
                return -1;
863
        else if(pkt1->seq_number > pkt2->seq_number)
864
                return 1;
865
        return 0;
866
}
867

    
868
/* Helper struct to generate and parse WAVE headers */
869
typedef struct wav_header {
870
        char riff[4];
871
        uint32_t len;
872
        char wave[4];
873
        char fmt[4];
874
        uint32_t formatsize;
875
        uint16_t format;
876
        uint16_t channels;
877
        uint32_t samplerate;
878
        uint32_t avgbyterate;
879
        uint16_t samplebytes;
880
        uint16_t channelbits;
881
        char data[4];
882
        uint32_t blocksize;
883
} wav_header;
884

    
885

    
886
/* Mixer settings */
887
#define DEFAULT_PREBUFFERING        6
888

    
889

    
890
/* Opus settings */                
891
#define        BUFFER_SAMPLES        8000
892
#define        OPUS_SAMPLES        160
893
#define USE_FEC                        0
894
#define DEFAULT_COMPLEXITY        4
895

    
896

    
897
/* Error codes */
898
#define JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR        499
899
#define JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE                480
900
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON        481
901
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST        482
902
#define JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT        483
903
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT        484
904
#define JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM        485
905
#define JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS                486
906
#define JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED                487
907
#define JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR        488
908
#define JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED        489
909
#define JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS                490
910
#define JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED        491
911
#define JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_USER        492
912
#define JANUS_AUDIOBRIDGE_ERROR_INVALID_SDP                493
913

    
914

    
915
/* AudioBridge watchdog/garbage collector (sort of) */
916
static void *janus_audiobridge_watchdog(void *data) {
917
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog started\n");
918
        gint64 now = 0;
919
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
920
                janus_mutex_lock(&sessions_mutex);
921
                /* Iterate on all the sessions */
922
                now = janus_get_monotonic_time();
923
                if(old_sessions != NULL) {
924
                        GList *sl = old_sessions;
925
                        JANUS_LOG(LOG_HUGE, "Checking %d old AudioBridge sessions...\n", g_list_length(old_sessions));
926
                        while(sl) {
927
                                janus_audiobridge_session *session = (janus_audiobridge_session *)sl->data;
928
                                if(!session) {
929
                                        sl = sl->next;
930
                                        continue;
931
                                }
932
                                if(now-session->destroyed >= 5*G_USEC_PER_SEC) {
933
                                        /* We're lazy and actually get rid of the stuff only after a few seconds */
934
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge session\n");
935
                                        GList *rm = sl->next;
936
                                        old_sessions = g_list_delete_link(old_sessions, sl);
937
                                        sl = rm;
938
                                        session->handle = NULL;
939
                                        g_free(session);
940
                                        session = NULL;
941
                                        continue;
942
                                }
943
                                sl = sl->next;
944
                        }
945
                }
946
                janus_mutex_unlock(&sessions_mutex);
947
                janus_mutex_lock(&rooms_mutex);
948
                if(old_rooms != NULL) {
949
                        GList *rl = old_rooms;
950
                        now = janus_get_monotonic_time();
951
                        while(rl) {
952
                                janus_audiobridge_room *audiobridge = (janus_audiobridge_room*)rl->data;
953
                                if(!initialized || stopping){
954
                                        break;
955
                                }
956
                                if(!audiobridge) {
957
                                        rl = rl->next;
958
                                        continue;
959
                                }
960
                                if(now - audiobridge->destroyed >= 5*G_USEC_PER_SEC) {
961
                                        /* Free resources */
962
                                        JANUS_LOG(LOG_VERB, "Freeing old AudioBridge room %"SCNu64"\n", audiobridge->room_id);
963
                                        g_free(audiobridge->room_name);
964
                                        g_free(audiobridge->room_secret);
965
                                        g_free(audiobridge->room_pin);
966
                                        g_free(audiobridge->record_file);
967
                                        g_hash_table_destroy(audiobridge->participants);
968
                                        g_hash_table_destroy(audiobridge->allowed);
969
                                        janus_mutex_lock(&audiobridge->rtp_mutex);
970
                                        if(audiobridge->rtp_udp_sock > 0)
971
                                                close(audiobridge->rtp_udp_sock);
972
                                        if(audiobridge->rtp_encoder)
973
                                                opus_encoder_destroy(audiobridge->rtp_encoder);
974
                                        g_hash_table_destroy(audiobridge->rtp_forwarders);
975
                                        janus_mutex_unlock(&audiobridge->rtp_mutex);
976
                                        g_free(audiobridge);
977
                                        /* Move on */
978
                                        GList *rm = rl->next;
979
                                        old_rooms = g_list_delete_link(old_rooms, rl);
980
                                        rl = rm;
981
                                        continue;
982
                                }
983
                                rl = rl->next;
984
                        }
985
                }
986
                janus_mutex_unlock(&rooms_mutex);
987
                g_usleep(500000);
988
        }
989
        JANUS_LOG(LOG_INFO, "AudioBridge watchdog stopped\n");
990
        return NULL;
991
}
992

    
993

    
994
/* Plugin implementation */
995
int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) {
996
        if(g_atomic_int_get(&stopping)) {
997
                /* Still stopping from before */
998
                return -1;
999
        }
1000
        if(callback == NULL || config_path == NULL) {
1001
                /* Invalid arguments */
1002
                return -1;
1003
        }
1004

    
1005
        /* Read configuration */
1006
        char filename[255];
1007
        g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_AUDIOBRIDGE_PACKAGE);
1008
        JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename);
1009
        config = janus_config_parse(filename);
1010
        config_folder = config_path;
1011
        if(config != NULL)
1012
                janus_config_print(config);
1013
        janus_mutex_init(&config_mutex);
1014
        
1015
        rooms = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
1016
        janus_mutex_init(&rooms_mutex);
1017
        sessions = g_hash_table_new(NULL, NULL);
1018
        janus_mutex_init(&sessions_mutex);
1019
        messages = g_async_queue_new_full((GDestroyNotify) janus_audiobridge_message_free);
1020
        /* This is the callback we'll need to invoke to contact the gateway */
1021
        gateway = callback;
1022

    
1023
        /* Parse configuration to populate the rooms list */
1024
        if(config != NULL) {
1025
                /* Any admin key to limit who can "create"? */
1026
                janus_config_item *key = janus_config_get_item_drilldown(config, "general", "admin_key");
1027
                if(key != NULL && key->value != NULL)
1028
                        admin_key = g_strdup(key->value);
1029
                janus_config_item *events = janus_config_get_item_drilldown(config, "general", "events");
1030
                if(events != NULL && events->value != NULL)
1031
                        notify_events = janus_is_true(events->value);
1032
                if(!notify_events && callback->events_is_enabled()) {
1033
                        JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_AUDIOBRIDGE_NAME);
1034
                }
1035
                /* Iterate on all rooms */
1036
                GList *cl = janus_config_get_categories(config);
1037
                while(cl != NULL) {
1038
                        janus_config_category *cat = (janus_config_category *)cl->data;
1039
                        if(cat->name == NULL || !strcasecmp(cat->name, "general")) {
1040
                                cl = cl->next;
1041
                                continue;
1042
                        }
1043
                        JANUS_LOG(LOG_VERB, "Adding audio room '%s'\n", cat->name);
1044
                        janus_config_item *desc = janus_config_get_item(cat, "description");
1045
                        janus_config_item *priv = janus_config_get_item(cat, "is_private");
1046
                        janus_config_item *sampling = janus_config_get_item(cat, "sampling_rate");
1047
                        janus_config_item *audiolevel_ext = janus_config_get_item(cat, "audiolevel_ext");
1048
                        janus_config_item *audiolevel_event = janus_config_get_item(cat, "audiolevel_event");
1049
                        janus_config_item *audio_active_packets = janus_config_get_item(cat, "audio_active_packets");
1050
                        janus_config_item *audio_level_average = janus_config_get_item(cat, "audio_level_average");
1051
                        janus_config_item *secret = janus_config_get_item(cat, "secret");
1052
                        janus_config_item *pin = janus_config_get_item(cat, "pin");
1053
                        janus_config_item *record = janus_config_get_item(cat, "record");
1054
                        janus_config_item *recfile = janus_config_get_item(cat, "record_file");
1055
                        if(sampling == NULL || sampling->value == NULL) {
1056
                                JANUS_LOG(LOG_ERR, "Can't add the audio room, missing mandatory information...\n");
1057
                                cl = cl->next;
1058
                                continue;
1059
                        }
1060
                        /* Create the audio bridge room */
1061
                        janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room));
1062
                        audiobridge->room_id = g_ascii_strtoull(cat->name, NULL, 0);
1063
                        char *description = NULL;
1064
                        if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0)
1065
                                description = g_strdup(desc->value);
1066
                        else
1067
                                description = g_strdup(cat->name);
1068
                        audiobridge->room_name = description;
1069
                        audiobridge->is_private = priv && priv->value && janus_is_true(priv->value);
1070
                        audiobridge->sampling_rate = atol(sampling->value);
1071
                        switch(audiobridge->sampling_rate) {
1072
                                case 8000:
1073
                                case 12000:
1074
                                case 16000:
1075
                                case 24000:
1076
                                case 48000:
1077
                                        JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
1078
                                        break;
1079
                                default:
1080
                                        JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
1081
                                        cl = cl->next;
1082
                                        continue;
1083
                        }
1084
                        audiobridge->audiolevel_ext = TRUE;
1085
                        if(audiolevel_ext != NULL && audiolevel_ext->value != NULL)
1086
                                audiobridge->audiolevel_ext = janus_is_true(audiolevel_ext->value);
1087
                        audiobridge->audiolevel_event = FALSE;
1088
                        if(audiolevel_event != NULL && audiolevel_event->value != NULL)
1089
                                audiobridge->audiolevel_event = janus_is_true(audiolevel_event->value);
1090
                        if(audiobridge->audiolevel_event) {
1091
                                audiobridge->audio_active_packets = 100;
1092
                                if(audio_active_packets != NULL && audio_active_packets->value != NULL){
1093
                                        if(atoi(audio_active_packets->value) > 0) {
1094
                                                audiobridge->audio_active_packets = atoi(audio_active_packets->value);
1095
                                        } else {
1096
                                                JANUS_LOG(LOG_WARN, "Invalid audio_active_packets value provided, using default: %d\n", audiobridge->audio_active_packets);
1097
                                        }
1098
                                }
1099
                                audiobridge->audio_level_average = 25;
1100
                                if(audio_level_average != NULL && audio_level_average->value != NULL) {
1101
                                        if(atoi(audio_level_average->value) > 0) {
1102
                                                audiobridge->audio_level_average = atoi(audio_level_average->value);
1103
                                        } else {
1104
                                                JANUS_LOG(LOG_WARN, "Invalid audio_level_average value provided, using default: %d\n", audiobridge->audio_level_average);
1105
                                        }
1106
                                }
1107
                        }
1108

    
1109
                        if(secret != NULL && secret->value != NULL) {
1110
                                audiobridge->room_secret = g_strdup(secret->value);
1111
                        }
1112
                        if(pin != NULL && pin->value != NULL) {
1113
                                audiobridge->room_pin = g_strdup(pin->value);
1114
                        }
1115
                        audiobridge->record = FALSE;
1116
                        if(record && record->value && janus_is_true(record->value))
1117
                                audiobridge->record = TRUE;
1118
                        if(recfile && recfile->value)
1119
                                audiobridge->record_file = g_strdup(recfile->value);
1120
                        audiobridge->recording = NULL;
1121
                        audiobridge->destroy = 0;
1122
                        audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
1123
                        audiobridge->check_tokens = FALSE;        /* Static rooms can't have an "allowed" list yet, no hooks to the configuration file */
1124
                        audiobridge->allowed = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
1125
                        audiobridge->destroyed = 0;
1126
                        janus_mutex_init(&audiobridge->mutex);
1127
                        audiobridge->rtp_forwarders = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_free);
1128
                        audiobridge->rtp_encoder = NULL;
1129
                        audiobridge->rtp_udp_sock = -1;
1130
                        janus_mutex_init(&audiobridge->rtp_mutex);
1131
                        JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
1132
                                audiobridge->room_id, audiobridge->room_name,
1133
                                audiobridge->is_private ? "private" : "public",
1134
                                audiobridge->room_secret ? audiobridge->room_secret : "no secret",
1135
                                audiobridge->room_pin ? audiobridge->room_pin : "no pin");
1136
                        /* We need a thread for the mix */
1137
                        GError *error = NULL;
1138
                        char tname[16];
1139
                        g_snprintf(tname, sizeof(tname), "mixer %"SCNu64, audiobridge->room_id);
1140
                        audiobridge->thread = g_thread_try_new(tname, &janus_audiobridge_mixer_thread, audiobridge, &error);
1141
                        if(error != NULL) {
1142
                                /* FIXME We should clear some resources... */
1143
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
1144
                        } else {
1145
                                janus_mutex_lock(&rooms_mutex);
1146
                                g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1147
                                janus_mutex_unlock(&rooms_mutex);
1148
                        }
1149
                        cl = cl->next;
1150
                }
1151
                /* Done: we keep the configuration file open in case we get a "create" or "destroy" with permanent=true */
1152
        }
1153

    
1154
        /* Show available rooms */
1155
        janus_mutex_lock(&rooms_mutex);
1156
        GHashTableIter iter;
1157
        gpointer value;
1158
        g_hash_table_iter_init(&iter, rooms);
1159
        while (g_hash_table_iter_next(&iter, NULL, &value)) {
1160
                janus_audiobridge_room *ar = value;
1161
                JANUS_LOG(LOG_VERB, "  ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n",
1162
                        ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT");
1163
        }
1164
        janus_mutex_unlock(&rooms_mutex);
1165

    
1166
        g_atomic_int_set(&initialized, 1);
1167

    
1168
        GError *error = NULL;
1169
        /* Start the sessions watchdog */
1170
        watchdog = g_thread_try_new("audiobridge watchdog", &janus_audiobridge_watchdog, NULL, &error);
1171
        if(error != NULL) {
1172
                g_atomic_int_set(&initialized, 0);
1173
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge watchdog thread...\n", error->code, error->message ? error->message : "??");
1174
                janus_config_destroy(config);
1175
                return -1;
1176
        }
1177
        /* Launch the thread that will handle incoming messages */
1178
        handler_thread = g_thread_try_new("audiobridge handler", janus_audiobridge_handler, NULL, &error);
1179
        if(error != NULL) {
1180
                g_atomic_int_set(&initialized, 0);
1181
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", error->code, error->message ? error->message : "??");
1182
                janus_config_destroy(config);
1183
                return -1;
1184
        }
1185
        JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_AUDIOBRIDGE_NAME);
1186
        return 0;
1187
}
1188

    
1189
void janus_audiobridge_destroy(void) {
1190
        if(!g_atomic_int_get(&initialized))
1191
                return;
1192
        g_atomic_int_set(&stopping, 1);
1193

    
1194
        g_async_queue_push(messages, &exit_message);
1195
        if(handler_thread != NULL) {
1196
                g_thread_join(handler_thread);
1197
                handler_thread = NULL;
1198
        }
1199
        if(watchdog != NULL) {
1200
                g_thread_join(watchdog);
1201
                watchdog = NULL;
1202
        }
1203
        /* FIXME We should destroy the sessions cleanly */
1204
        janus_mutex_lock(&sessions_mutex);
1205
        g_hash_table_destroy(sessions);
1206
        janus_mutex_unlock(&sessions_mutex);
1207
        janus_mutex_lock(&rooms_mutex);
1208
        g_hash_table_destroy(rooms);
1209
        janus_mutex_unlock(&rooms_mutex);
1210
        g_async_queue_unref(messages);
1211
        messages = NULL;
1212
        sessions = NULL;
1213

    
1214
        janus_config_destroy(config);
1215
        g_free(admin_key);
1216

    
1217
        g_atomic_int_set(&initialized, 0);
1218
        g_atomic_int_set(&stopping, 0);
1219
        JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_AUDIOBRIDGE_NAME);
1220
}
1221

    
1222
int janus_audiobridge_get_api_compatibility(void) {
1223
        /* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
1224
        return JANUS_PLUGIN_API_VERSION;
1225
}
1226

    
1227
int janus_audiobridge_get_version(void) {
1228
        return JANUS_AUDIOBRIDGE_VERSION;
1229
}
1230

    
1231
const char *janus_audiobridge_get_version_string(void) {
1232
        return JANUS_AUDIOBRIDGE_VERSION_STRING;
1233
}
1234

    
1235
const char *janus_audiobridge_get_description(void) {
1236
        return JANUS_AUDIOBRIDGE_DESCRIPTION;
1237
}
1238

    
1239
const char *janus_audiobridge_get_name(void) {
1240
        return JANUS_AUDIOBRIDGE_NAME;
1241
}
1242

    
1243
const char *janus_audiobridge_get_author(void) {
1244
        return JANUS_AUDIOBRIDGE_AUTHOR;
1245
}
1246

    
1247
const char *janus_audiobridge_get_package(void) {
1248
        return JANUS_AUDIOBRIDGE_PACKAGE;
1249
}
1250

    
1251
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error) {
1252
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1253
                *error = -1;
1254
                return;
1255
        }        
1256
        janus_audiobridge_session *session = (janus_audiobridge_session *)g_malloc0(sizeof(janus_audiobridge_session));
1257
        session->handle = handle;
1258
        session->started = FALSE;
1259
        session->stopping = FALSE;
1260
        session->destroyed = 0;
1261
        g_atomic_int_set(&session->hangingup, 0);
1262
        handle->plugin_handle = session;
1263
        janus_mutex_lock(&sessions_mutex);
1264
        g_hash_table_insert(sessions, handle, session);
1265
        janus_mutex_unlock(&sessions_mutex);
1266

    
1267
        return;
1268
}
1269

    
1270
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error) {
1271
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1272
                *error = -1;
1273
                return;
1274
        }        
1275
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle; 
1276
        if(!session) {
1277
                JANUS_LOG(LOG_ERR, "No AudioBridge session associated with this handle...\n");
1278
                *error = -2;
1279
                return;
1280
        }
1281
        JANUS_LOG(LOG_VERB, "Removing AudioBridge session...\n");
1282
        janus_mutex_lock(&sessions_mutex);
1283
        if(!session->destroyed) {
1284
                g_hash_table_remove(sessions, handle);
1285
                janus_audiobridge_hangup_media(handle);
1286
                session->destroyed = janus_get_monotonic_time();
1287
                /* Cleaning up and removing the session is done in a lazy way */
1288
                old_sessions = g_list_append(old_sessions, session);
1289
        }
1290
        janus_mutex_unlock(&sessions_mutex);
1291

    
1292
        return;
1293
}
1294

    
1295
static void janus_audiobridge_notify_participants(janus_audiobridge_participant *participant, json_t *msg) {
1296
        /* participant->room->participants_mutex has to be locked. */
1297
        GHashTableIter iter;
1298
        gpointer value;
1299
        g_hash_table_iter_init(&iter, participant->room->participants);
1300
        while (!participant->room->destroyed && g_hash_table_iter_next(&iter, NULL, &value)) {
1301
                janus_audiobridge_participant *p = value;
1302
                if(p && p->session && p != participant) {
1303
                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
1304
                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, msg, NULL);
1305
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1306
                }
1307
        }
1308
}
1309

    
1310
json_t *janus_audiobridge_query_session(janus_plugin_session *handle) {
1311
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1312
                return NULL;
1313
        }        
1314
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1315
        if(!session) {
1316
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1317
                return NULL;
1318
        }
1319
        /* Show the participant/room info, if any */
1320
        json_t *info = json_object();
1321
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1322
        json_object_set_new(info, "state", json_string(participant && participant->room ? "inroom" : "idle"));
1323
        if(participant) {
1324
                janus_mutex_lock(&rooms_mutex);
1325
                janus_audiobridge_room *room = participant->room;
1326
                if(room != NULL)
1327
                        json_object_set_new(info, "room", json_integer(room->room_id));
1328
                janus_mutex_unlock(&rooms_mutex);
1329
                json_object_set_new(info, "id", json_integer(participant->user_id));
1330
                if(participant->display)
1331
                        json_object_set_new(info, "display", json_string(participant->display));
1332
                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
1333
                json_object_set_new(info, "active", participant->active ? json_true() : json_false());
1334
                json_object_set_new(info, "pre-buffering", participant->prebuffering ? json_true() : json_false());
1335
                if(participant->inbuf) {
1336
                        janus_mutex_lock(&participant->qmutex);
1337
                        json_object_set_new(info, "queue-in", json_integer(g_list_length(participant->inbuf)));
1338
                        janus_mutex_unlock(&participant->qmutex);
1339
                }
1340
                if(participant->outbuf)
1341
                        json_object_set_new(info, "queue-out", json_integer(g_async_queue_length(participant->outbuf)));
1342
                if(participant->last_drop > 0)
1343
                        json_object_set_new(info, "last-drop", json_integer(participant->last_drop));
1344
                if(participant->arc && participant->arc->filename)
1345
                        json_object_set_new(info, "audio-recording", json_string(participant->arc->filename));
1346
                if(participant->extmap_id > 0)
1347
                        json_object_set_new(info, "audio-level-dBov", json_integer(participant->dBov_level));
1348
        }
1349
        json_object_set_new(info, "started", session->started ? json_true() : json_false());
1350
        json_object_set_new(info, "destroyed", json_integer(session->destroyed));
1351
        return info;
1352
}
1353

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

    
1358
        /* Pre-parse the message */
1359
        int error_code = 0;
1360
        char error_cause[512];
1361
        json_t *root = message;
1362
        json_t *response = NULL;
1363
        
1364
        if(message == NULL) {
1365
                JANUS_LOG(LOG_ERR, "No message??\n");
1366
                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
1367
                g_snprintf(error_cause, 512, "%s", "No message??");
1368
                goto plugin_response;
1369
        }
1370

    
1371
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
1372
        if(!session) {
1373
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1374
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1375
                g_snprintf(error_cause, 512, "%s", "session associated with this handle...");
1376
                goto plugin_response;
1377
        }
1378
        if(session->destroyed) {
1379
                JANUS_LOG(LOG_ERR, "Session has already been marked as destroyed...\n");
1380
                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1381
                g_snprintf(error_cause, 512, "%s", "Session has already been marked as destroyed...");
1382
                goto plugin_response;
1383
        }
1384
        if(!json_is_object(root)) {
1385
                JANUS_LOG(LOG_ERR, "JSON error: not an object\n");
1386
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_JSON;
1387
                g_snprintf(error_cause, 512, "JSON error: not an object");
1388
                goto plugin_response;
1389
        }
1390
        /* Get the request first */
1391
        JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
1392
                error_code, error_cause, TRUE,
1393
                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1394
        if(error_code != 0)
1395
                goto plugin_response;
1396
        json_t *request = json_object_get(root, "request");
1397
        /* Some requests ('create', 'destroy', 'exists', 'list') can be handled synchronously */
1398
        const char *request_text = json_string_value(request);
1399
        if(!strcasecmp(request_text, "create")) {
1400
                /* Create a new audiobridge */
1401
                JANUS_LOG(LOG_VERB, "Creating a new audiobridge\n");
1402
                JANUS_VALIDATE_JSON_OBJECT(root, create_parameters,
1403
                        error_code, error_cause, TRUE,
1404
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1405
                if(error_code != 0)
1406
                        goto plugin_response;
1407
                if(admin_key != NULL) {
1408
                        /* An admin key was specified: make sure it was provided, and that it's valid */
1409
                        JANUS_VALIDATE_JSON_OBJECT(root, adminkey_parameters,
1410
                                error_code, error_cause, TRUE,
1411
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1412
                        if(error_code != 0)
1413
                                goto plugin_response;
1414
                        JANUS_CHECK_SECRET(admin_key, root, "admin_key", error_code, error_cause,
1415
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1416
                        if(error_code != 0)
1417
                                goto plugin_response;
1418
                }
1419
                json_t *desc = json_object_get(root, "description");
1420
                json_t *secret = json_object_get(root, "secret");
1421
                json_t *pin = json_object_get(root, "pin");
1422
                json_t *is_private = json_object_get(root, "is_private");
1423
                json_t *allowed = json_object_get(root, "allowed");
1424
                json_t *sampling = json_object_get(root, "sampling");
1425
                json_t *audiolevel_ext = json_object_get(root, "audiolevel_ext");
1426
                json_t *audiolevel_event = json_object_get(root, "audiolevel_event");
1427
                json_t *audio_active_packets = json_object_get(root, "audio_active_packets");
1428
                json_t *audio_level_average = json_object_get(root, "audio_level_average");
1429
                json_t *record = json_object_get(root, "record");
1430
                json_t *recfile = json_object_get(root, "record_file");
1431
                json_t *permanent = json_object_get(root, "permanent");
1432
                if(allowed) {
1433
                        /* Make sure the "allowed" array only contains strings */
1434
                        gboolean ok = TRUE;
1435
                        if(json_array_size(allowed) > 0) {
1436
                                size_t i = 0;
1437
                                for(i=0; i<json_array_size(allowed); i++) {
1438
                                        json_t *a = json_array_get(allowed, i);
1439
                                        if(!a || !json_is_string(a)) {
1440
                                                ok = FALSE;
1441
                                                break;
1442
                                        }
1443
                                }
1444
                        }
1445
                        if(!ok) {
1446
                                JANUS_LOG(LOG_ERR, "Invalid element in the allowed array (not a string)\n");
1447
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1448
                                g_snprintf(error_cause, 512, "Invalid element in the allowed array (not a string)");
1449
                                goto plugin_response;
1450
                        }
1451
                }
1452
                gboolean save = permanent ? json_is_true(permanent) : FALSE;
1453
                if(save && config == NULL) {
1454
                        JANUS_LOG(LOG_ERR, "No configuration file, can't create permanent room\n");
1455
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1456
                        g_snprintf(error_cause, 512, "No configuration file, can't create permanent room");
1457
                        goto plugin_response;
1458
                }
1459
                guint64 room_id = 0;
1460
                json_t *room = json_object_get(root, "room");
1461
                room_id = json_integer_value(room);
1462
                if(room_id == 0) {
1463
                        JANUS_LOG(LOG_WARN, "Desired room ID is 0, which is not allowed... picking random ID instead\n");
1464
                }
1465
                janus_mutex_lock(&rooms_mutex);
1466
                if(room_id > 0) {
1467
                        /* Let's make sure the room doesn't exist already */
1468
                        if(g_hash_table_lookup(rooms, &room_id) != NULL) {
1469
                                /* It does... */
1470
                                janus_mutex_unlock(&rooms_mutex);
1471
                                JANUS_LOG(LOG_ERR, "Room %"SCNu64" already exists!\n", room_id);
1472
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS;
1473
                                g_snprintf(error_cause, 512, "Room %"SCNu64" already exists", room_id);
1474
                                goto plugin_response;
1475
                        }
1476
                }
1477
                /* Create the audio bridge room */
1478
                janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room));
1479
                /* Generate a random ID */
1480
                if(room_id == 0) {
1481
                        while(room_id == 0) {
1482
                                room_id = janus_random_uint64();
1483
                                if(g_hash_table_lookup(rooms, &room_id) != NULL) {
1484
                                        /* Room ID already taken, try another one */
1485
                                        room_id = 0;
1486
                                }
1487
                        }
1488
                }
1489
                audiobridge->room_id = room_id;
1490
                char *description = NULL;
1491
                if(desc != NULL && strlen(json_string_value(desc)) > 0) {
1492
                        description = g_strdup(json_string_value(desc));
1493
                } else {
1494
                        char roomname[255];
1495
                        g_snprintf(roomname, 255, "Room %"SCNu64"", audiobridge->room_id);
1496
                        description = g_strdup(roomname);
1497
                }
1498
                audiobridge->room_name = description;
1499
                audiobridge->is_private = is_private ? json_is_true(is_private) : FALSE;
1500
                if(secret)
1501
                        audiobridge->room_secret = g_strdup(json_string_value(secret));
1502
                if(pin)
1503
                        audiobridge->room_pin = g_strdup(json_string_value(pin));
1504
                if(sampling)
1505
                        audiobridge->sampling_rate = json_integer_value(sampling);
1506
                else
1507
                        audiobridge->sampling_rate = 16000;
1508
                audiobridge->audiolevel_ext = audiolevel_ext ? json_is_true(audiolevel_ext) : TRUE;
1509
                audiobridge->audiolevel_event = audiolevel_event ? json_is_true(audiolevel_event) : FALSE;
1510
                if(audiobridge->audiolevel_event) {
1511
                        audiobridge->audio_active_packets = 100;
1512
                        if(json_integer_value(audio_active_packets) > 0) {
1513
                                audiobridge->audio_active_packets = json_integer_value(audio_active_packets);
1514
                        } else {
1515
                                JANUS_LOG(LOG_WARN, "Invalid audio_active_packets value provided, using default: %d\n", audiobridge->audio_active_packets);
1516
                        }
1517
                        audiobridge->audio_level_average = 25;
1518
                        if(json_integer_value(audio_level_average) > 0) {
1519
                                audiobridge->audio_level_average = json_integer_value(audio_level_average);
1520
                        } else {
1521
                                JANUS_LOG(LOG_WARN, "Invalid audio_level_average value provided, using default: %d\n", audiobridge->audio_level_average);
1522
                        }
1523
                }
1524
                switch(audiobridge->sampling_rate) {
1525
                        case 8000:
1526
                        case 12000:
1527
                        case 16000:
1528
                        case 24000:
1529
                        case 48000:
1530
                                JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate);
1531
                                break;
1532
                        default:
1533
                                janus_mutex_unlock(&rooms_mutex);
1534
                                JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate);
1535
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1536
                                g_snprintf(error_cause, 512, "We currently only support 16kHz (wideband) as a sampling rate for audio rooms, %"SCNu32" TBD...", audiobridge->sampling_rate);
1537
                                goto plugin_response;
1538
                }
1539
                audiobridge->record = FALSE;
1540
                if(record && json_is_true(record))
1541
                        audiobridge->record = TRUE;
1542
                if(recfile)
1543
                        audiobridge->record_file = g_strdup(json_string_value(recfile));
1544
                audiobridge->recording = NULL;
1545
                audiobridge->destroy = 0;
1546
                audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
1547
                audiobridge->allowed = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
1548
                if(allowed != NULL) {
1549
                        /* Populate the "allowed" list as an ACL for people trying to join */
1550
                        if(json_array_size(allowed) > 0) {
1551
                                size_t i = 0;
1552
                                for(i=0; i<json_array_size(allowed); i++) {
1553
                                        const char *token = json_string_value(json_array_get(allowed, i));
1554
                                        if(!g_hash_table_lookup(audiobridge->allowed, token))
1555
                                                g_hash_table_insert(audiobridge->allowed, g_strdup(token), GINT_TO_POINTER(TRUE));
1556
                                }
1557
                        }
1558
                        audiobridge->check_tokens = TRUE;
1559
                }
1560
                audiobridge->destroyed = 0;
1561
                janus_mutex_init(&audiobridge->mutex);
1562
                audiobridge->rtp_forwarders = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_free);
1563
                audiobridge->rtp_encoder = NULL;
1564
                audiobridge->rtp_udp_sock = -1;
1565
                janus_mutex_init(&audiobridge->rtp_mutex);
1566
                g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1567
                JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
1568
                        audiobridge->room_id, audiobridge->room_name,
1569
                        audiobridge->is_private ? "private" : "public",
1570
                        audiobridge->room_secret ? audiobridge->room_secret : "no secret",
1571
                        audiobridge->room_pin ? audiobridge->room_pin : "no pin");
1572
                /* We need a thread for the mix */
1573
                GError *error = NULL;
1574
                char tname[16];
1575
                g_snprintf(tname, sizeof(tname), "mixer %"SCNu64, audiobridge->room_id);
1576
                audiobridge->thread = g_thread_try_new(tname, &janus_audiobridge_mixer_thread, audiobridge, &error);
1577
                if(error != NULL) {
1578
                        janus_mutex_unlock(&rooms_mutex);
1579
                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
1580
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1581
                        g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the mixer thread", error->code, error->message ? error->message : "??");
1582
                        g_free(audiobridge->room_name);
1583
                        g_free(audiobridge->room_secret);
1584
                        g_free(audiobridge->record_file);
1585
                        g_hash_table_destroy(audiobridge->participants);
1586
                        g_hash_table_destroy(audiobridge->allowed);
1587
                        g_free(audiobridge);
1588
                        goto plugin_response;
1589
                } else {
1590
                        g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1591
                }
1592
                if(save) {
1593
                        /* This room is permanent: save to the configuration file too
1594
                         * FIXME: We should check if anything fails... */
1595
                        JANUS_LOG(LOG_VERB, "Saving room %"SCNu64" permanently in config file\n", audiobridge->room_id);
1596
                        janus_mutex_lock(&config_mutex);
1597
                        char cat[BUFSIZ], value[BUFSIZ];
1598
                        /* The room ID is the category */
1599
                        g_snprintf(cat, BUFSIZ, "%"SCNu64, audiobridge->room_id);
1600
                        janus_config_add_category(config, cat);
1601
                        /* Now for the values */
1602
                        janus_config_add_item(config, cat, "description", audiobridge->room_name);
1603
                        if(audiobridge->is_private)
1604
                                janus_config_add_item(config, cat, "is_private", "yes");
1605
                        g_snprintf(value, BUFSIZ, "%"SCNu32, audiobridge->sampling_rate);
1606
                        janus_config_add_item(config, cat, "sampling_rate", value);
1607
                        if(audiobridge->room_secret)
1608
                                janus_config_add_item(config, cat, "secret", audiobridge->room_secret);
1609
                        if(audiobridge->room_pin)
1610
                                janus_config_add_item(config, cat, "pin", audiobridge->room_pin);
1611
                        if(audiobridge->record_file) {
1612
                                janus_config_add_item(config, cat, "record", "yes");
1613
                                janus_config_add_item(config, cat, "record_file", audiobridge->record_file);
1614
                        }
1615
                        /* Save modified configuration */
1616
                        if(janus_config_save(config, config_folder, JANUS_AUDIOBRIDGE_PACKAGE) < 0)
1617
                                save = FALSE;        /* This will notify the user the room is not permanent */
1618
                        janus_mutex_unlock(&config_mutex);
1619
                }
1620
                /* Send info back */
1621
                response = json_object();
1622
                json_object_set_new(response, "audiobridge", json_string("created"));
1623
                json_object_set_new(response, "room", json_integer(audiobridge->room_id));
1624
                /* Also notify event handlers */
1625
                if(notify_events && gateway->events_is_enabled()) {
1626
                        json_t *info = json_object();
1627
                        json_object_set_new(info, "event", json_string("created"));
1628
                        json_object_set_new(info, "room", json_integer(audiobridge->room_id));
1629
                        json_object_set_new(info, "permanent", save ? json_true() : json_false());
1630
                        gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
1631
                }
1632
                janus_mutex_unlock(&rooms_mutex);
1633
                goto plugin_response;
1634
        } else if(!strcasecmp(request_text, "destroy")) {
1635
                JANUS_LOG(LOG_VERB, "Attempt to destroy an existing audiobridge room\n");
1636
                JANUS_VALIDATE_JSON_OBJECT(root, destroy_parameters,
1637
                        error_code, error_cause, TRUE,
1638
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1639
                if(error_code != 0)
1640
                        goto plugin_response;
1641
                json_t *room = json_object_get(root, "room");
1642
                json_t *permanent = json_object_get(root, "permanent");
1643
                gboolean save = permanent ? json_is_true(permanent) : FALSE;
1644
                if(save && config == NULL) {
1645
                        JANUS_LOG(LOG_ERR, "No configuration file, can't destroy room permanently\n");
1646
                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
1647
                        g_snprintf(error_cause, 512, "No configuration file, can't destroy room permanently");
1648
                        goto plugin_response;
1649
                }
1650
                guint64 room_id = json_integer_value(room);
1651
                janus_mutex_lock(&rooms_mutex);
1652
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1653
                if(audiobridge == NULL) {
1654
                        janus_mutex_unlock(&rooms_mutex);
1655
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1656
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1657
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1658
                        goto plugin_response;
1659
                }
1660
                janus_mutex_lock(&audiobridge->mutex);
1661
                /* A secret may be required for this action */
1662
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1663
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1664
                if(error_code != 0) {
1665
                        janus_mutex_unlock(&audiobridge->mutex);
1666
                        janus_mutex_unlock(&rooms_mutex);
1667
                        goto plugin_response;
1668
                }
1669
                /* Remove room */
1670
                g_hash_table_remove(rooms, &room_id);
1671
                if(save) {
1672
                        /* This change is permanent: save to the configuration file too
1673
                         * FIXME: We should check if anything fails... */
1674
                        JANUS_LOG(LOG_VERB, "Destroying room %"SCNu64" permanently in config file\n", room_id);
1675
                        janus_mutex_lock(&config_mutex);
1676
                        char cat[BUFSIZ];
1677
                        /* The room ID is the category */
1678
                        g_snprintf(cat, BUFSIZ, "%"SCNu64, room_id);
1679
                        janus_config_remove_category(config, cat);
1680
                        /* Save modified configuration */
1681
                        janus_config_save(config, config_folder, JANUS_AUDIOBRIDGE_PACKAGE);
1682
                        janus_mutex_unlock(&config_mutex);
1683
                }
1684
                /* Prepare response/notification */
1685
                response = json_object();
1686
                json_object_set_new(response, "audiobridge", json_string("destroyed"));
1687
                json_object_set_new(response, "room", json_integer(room_id));
1688
                /* Notify all participants that the fun is over, and that they'll be kicked */
1689
                JANUS_LOG(LOG_VERB, "Notifying all participants\n");
1690
                GHashTableIter iter;
1691
                gpointer value;
1692
                g_hash_table_iter_init(&iter, audiobridge->participants);
1693
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
1694
                        janus_audiobridge_participant *p = value;
1695
                        if(p && p->session) {
1696
                                p->room = NULL;
1697
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, response, NULL);
1698
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
1699
                                /* Get rid of queued packets */
1700
                                janus_mutex_lock(&p->qmutex);
1701
                                p->active = FALSE;
1702
                                while(p->inbuf) {
1703
                                        GList *first = g_list_first(p->inbuf);
1704
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
1705
                                        p->inbuf = g_list_remove_link(p->inbuf, first);
1706
                                        first = NULL;
1707
                                        if(pkt == NULL)
1708
                                                continue;
1709
                                        if(pkt->data)
1710
                                                g_free(pkt->data);
1711
                                        pkt->data = NULL;
1712
                                        g_free(pkt);
1713
                                        pkt = NULL;
1714
                                }
1715
                                janus_mutex_unlock(&p->qmutex);
1716
                        }
1717
                }
1718
                /* Also notify event handlers */
1719
                if(notify_events && gateway->events_is_enabled()) {
1720
                        json_t *info = json_object();
1721
                        json_object_set_new(info, "event", json_string("destroyed"));
1722
                        json_object_set_new(info, "room", json_integer(room_id));
1723
                        gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
1724
                }
1725
                JANUS_LOG(LOG_VERB, "Waiting for the mixer thread to complete...\n");
1726
                audiobridge->destroyed = janus_get_monotonic_time();
1727
                janus_mutex_unlock(&audiobridge->mutex);
1728
                janus_mutex_unlock(&rooms_mutex);
1729
                g_thread_join(audiobridge->thread);
1730
                /* Done */
1731
                JANUS_LOG(LOG_VERB, "Audiobridge room destroyed\n");
1732
                goto plugin_response;
1733
        } else if(!strcasecmp(request_text, "list")) {
1734
                /* List all rooms (but private ones) and their details (except for the secret, of course...) */
1735
                json_t *list = json_array();
1736
                JANUS_LOG(LOG_VERB, "Request for the list for all video rooms\n");
1737
                janus_mutex_lock(&rooms_mutex);
1738
                GHashTableIter iter;
1739
                gpointer value;
1740
                g_hash_table_iter_init(&iter, rooms);
1741
                while(g_hash_table_iter_next(&iter, NULL, &value)) {
1742
                        janus_audiobridge_room *room = value;
1743
                        if(!room)
1744
                                continue;
1745
                        janus_mutex_lock(&room->mutex);
1746
                        if(room->is_private) {
1747
                                /* Skip private room */
1748
                                janus_mutex_unlock(&room->mutex);
1749
                                JANUS_LOG(LOG_VERB, "Skipping private room '%s'\n", room->room_name);
1750
                                continue;
1751
                        }
1752
                        json_t *rl = json_object();
1753
                        json_object_set_new(rl, "room", json_integer(room->room_id));
1754
                        json_object_set_new(rl, "description", json_string(room->room_name));
1755
                        json_object_set_new(rl, "sampling_rate", json_integer(room->sampling_rate));
1756
                        json_object_set_new(rl, "pin_required", room->room_pin ? json_true() : json_false());
1757
                        json_object_set_new(rl, "record", room->record ? json_true() : json_false());
1758
                        /* TODO: Possibly list participant details... or make it a separate API call for a specific room */
1759
                        json_object_set_new(rl, "num_participants", json_integer(g_hash_table_size(room->participants)));
1760
                        json_array_append_new(list, rl);
1761
                        janus_mutex_unlock(&room->mutex);
1762
                }
1763
                janus_mutex_unlock(&rooms_mutex);
1764
                response = json_object();
1765
                json_object_set_new(response, "audiobridge", json_string("success"));
1766
                json_object_set_new(response, "list", list);
1767
                goto plugin_response;
1768
        } else if(!strcasecmp(request_text, "exists")) {
1769
                /* Check whether a given room exists or not, returns true/false */        
1770
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
1771
                        error_code, error_cause, TRUE,
1772
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1773
                if(error_code != 0)
1774
                        goto plugin_response;
1775
                json_t *room = json_object_get(root, "room");
1776
                guint64 room_id = json_integer_value(room);
1777
                janus_mutex_lock(&rooms_mutex);
1778
                gboolean room_exists = g_hash_table_contains(rooms, &room_id);
1779
                janus_mutex_unlock(&rooms_mutex);
1780
                response = json_object();
1781
                json_object_set_new(response, "audiobridge", json_string("success"));
1782
                json_object_set_new(response, "room", json_integer(room_id));
1783
                json_object_set_new(response, "exists", room_exists ? json_true() : json_false());
1784
                goto plugin_response;
1785
        } else if(!strcasecmp(request_text, "allowed")) {
1786
                JANUS_LOG(LOG_VERB, "Attempt to edit the list of allowed participants in an existing audiobridge room\n");
1787
                JANUS_VALIDATE_JSON_OBJECT(root, allowed_parameters,
1788
                        error_code, error_cause, TRUE,
1789
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1790
                if(error_code != 0)
1791
                        goto plugin_response;
1792
                json_t *action = json_object_get(root, "action");
1793
                json_t *room = json_object_get(root, "room");
1794
                json_t *allowed = json_object_get(root, "allowed");
1795
                const char *action_text = json_string_value(action);
1796
                if(strcasecmp(action_text, "enable") && strcasecmp(action_text, "disable") &&
1797
                                strcasecmp(action_text, "add") && strcasecmp(action_text, "remove")) {
1798
                        JANUS_LOG(LOG_ERR, "Unsupported action '%s' (allowed)\n", action_text);
1799
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1800
                        g_snprintf(error_cause, 512, "Unsupported action '%s' (allowed)", action_text);
1801
                        goto plugin_response;
1802
                }
1803
                guint64 room_id = json_integer_value(room);
1804
                janus_mutex_lock(&rooms_mutex);
1805
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1806
                if(audiobridge == NULL) {
1807
                        janus_mutex_unlock(&rooms_mutex);
1808
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1809
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1810
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1811
                        goto plugin_response;
1812
                }
1813
                janus_mutex_lock(&audiobridge->mutex);
1814
                /* A secret may be required for this action */
1815
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1816
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1817
                if(error_code != 0) {
1818
                        janus_mutex_unlock(&audiobridge->mutex);
1819
                        janus_mutex_unlock(&rooms_mutex);
1820
                        goto plugin_response;
1821
                }
1822
                if(!strcasecmp(action_text, "enable")) {
1823
                        JANUS_LOG(LOG_VERB, "Enabling the check on allowed authorization tokens for room %"SCNu64"\n", room_id);
1824
                        audiobridge->check_tokens = TRUE;
1825
                } else if(!strcasecmp(action_text, "disable")) {
1826
                        JANUS_LOG(LOG_VERB, "Disabling the check on allowed authorization tokens for room %"SCNu64" (free entry)\n", room_id);
1827
                        audiobridge->check_tokens = FALSE;
1828
                } else {
1829
                        gboolean add = !strcasecmp(action_text, "add");
1830
                        if(allowed) {
1831
                                /* Make sure the "allowed" array only contains strings */
1832
                                gboolean ok = TRUE;
1833
                                if(json_array_size(allowed) > 0) {
1834
                                        size_t i = 0;
1835
                                        for(i=0; i<json_array_size(allowed); i++) {
1836
                                                json_t *a = json_array_get(allowed, i);
1837
                                                if(!a || !json_is_string(a)) {
1838
                                                        ok = FALSE;
1839
                                                        break;
1840
                                                }
1841
                                        }
1842
                                }
1843
                                if(!ok) {
1844
                                        JANUS_LOG(LOG_ERR, "Invalid element in the allowed array (not a string)\n");
1845
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
1846
                                        g_snprintf(error_cause, 512, "Invalid element in the allowed array (not a string)");
1847
                                        janus_mutex_unlock(&audiobridge->mutex);
1848
                                        janus_mutex_unlock(&rooms_mutex);
1849
                                        goto plugin_response;
1850
                                }
1851
                                size_t i = 0;
1852
                                for(i=0; i<json_array_size(allowed); i++) {
1853
                                        const char *token = json_string_value(json_array_get(allowed, i));
1854
                                        if(add) {
1855
                                                if(!g_hash_table_lookup(audiobridge->allowed, token))
1856
                                                        g_hash_table_insert(audiobridge->allowed, g_strdup(token), GINT_TO_POINTER(TRUE));
1857
                                        } else {
1858
                                                g_hash_table_remove(audiobridge->allowed, token);
1859
                                        }
1860
                                }
1861
                        }
1862
                }
1863
                /* Prepare response */
1864
                response = json_object();
1865
                json_object_set_new(response, "audiobridge", json_string("success"));
1866
                json_object_set_new(response, "room", json_integer(audiobridge->room_id));
1867
                json_t *list = json_array();
1868
                if(strcasecmp(action_text, "disable")) {
1869
                        if(g_hash_table_size(audiobridge->allowed) > 0) {
1870
                                GHashTableIter iter;
1871
                                gpointer key;
1872
                                g_hash_table_iter_init(&iter, audiobridge->allowed);
1873
                                while(g_hash_table_iter_next(&iter, &key, NULL)) {
1874
                                        char *token = key;
1875
                                        json_array_append_new(list, json_string(token));
1876
                                }
1877
                        }
1878
                        json_object_set_new(response, "allowed", list);
1879
                }
1880
                /* Done */
1881
                janus_mutex_unlock(&audiobridge->mutex);
1882
                janus_mutex_unlock(&rooms_mutex);
1883
                JANUS_LOG(LOG_VERB, "Audiobridge room allowed list updated\n");
1884
                goto plugin_response;
1885
        } else if(!strcasecmp(request_text, "kick")) {
1886
                JANUS_LOG(LOG_VERB, "Attempt to kick a participant from an existing audiobridge room\n");
1887
                JANUS_VALIDATE_JSON_OBJECT(root, kick_parameters,
1888
                        error_code, error_cause, TRUE,
1889
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1890
                if(error_code != 0)
1891
                        goto plugin_response;
1892
                json_t *room = json_object_get(root, "room");
1893
                json_t *id = json_object_get(root, "id");
1894
                guint64 room_id = json_integer_value(room);
1895
                janus_mutex_lock(&rooms_mutex);
1896
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1897
                if(audiobridge == NULL) {
1898
                        janus_mutex_unlock(&rooms_mutex);
1899
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1900
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1901
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1902
                        goto plugin_response;
1903
                }
1904
                janus_mutex_lock(&audiobridge->mutex);
1905
                /* A secret may be required for this action */
1906
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
1907
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
1908
                if(error_code != 0) {
1909
                        janus_mutex_unlock(&audiobridge->mutex);
1910
                        janus_mutex_unlock(&rooms_mutex);
1911
                        goto plugin_response;
1912
                }
1913
                guint64 user_id = json_integer_value(id);
1914
                janus_audiobridge_participant *participant = g_hash_table_lookup(audiobridge->participants, &user_id);
1915
                if(participant == NULL) {
1916
                        janus_mutex_unlock(&audiobridge->mutex);
1917
                        janus_mutex_unlock(&rooms_mutex);
1918
                        JANUS_LOG(LOG_ERR, "No such user %"SCNu64" in room %"SCNu64"\n", user_id, room_id);
1919
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_USER;
1920
                        g_snprintf(error_cause, 512, "No such user %"SCNu64" in room %"SCNu64, user_id, room_id);
1921
                        goto plugin_response;
1922
                }
1923
                /* Tell the core to tear down the PeerConnection, hangup_media will do the rest */
1924
                if(participant && participant->session)
1925
                        gateway->close_pc(participant->session->handle);
1926
                JANUS_LOG(LOG_VERB, "Kicked user %"SCNu64" from room %"SCNu64"\n", user_id, room_id);
1927
                /* Prepare response */
1928
                response = json_object();
1929
                json_object_set_new(response, "audiobridge", json_string("success"));
1930
                /* Done */
1931
                janus_mutex_unlock(&audiobridge->mutex);
1932
                janus_mutex_unlock(&rooms_mutex);
1933
                goto plugin_response;
1934
        } else if(!strcasecmp(request_text, "listparticipants")) {
1935
                /* List all participants in a room */        
1936
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
1937
                        error_code, error_cause, TRUE,
1938
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1939
                if(error_code != 0)
1940
                        goto plugin_response;
1941
                json_t *room = json_object_get(root, "room");
1942
                guint64 room_id = json_integer_value(room);
1943
                janus_mutex_lock(&rooms_mutex);
1944
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
1945
                if(audiobridge == NULL) {
1946
                        janus_mutex_unlock(&rooms_mutex);
1947
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1948
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1949
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1950
                        goto plugin_response;
1951
                }
1952
                janus_mutex_lock(&audiobridge->mutex);
1953
                if(audiobridge->destroyed) {
1954
                        janus_mutex_unlock(&audiobridge->mutex);
1955
                        janus_mutex_unlock(&rooms_mutex);
1956
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
1957
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
1958
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
1959
                        goto plugin_response;
1960
                }
1961
                /* Return a list of all participants */
1962
                json_t *list = json_array();
1963
                GHashTableIter iter;
1964
                gpointer value;
1965
                g_hash_table_iter_init(&iter, audiobridge->participants);
1966
                while (!audiobridge->destroyed && g_hash_table_iter_next(&iter, NULL, &value)) {
1967
                        janus_audiobridge_participant *p = value;
1968
                        json_t *pl = json_object();
1969
                        json_object_set_new(pl, "id", json_integer(p->user_id));
1970
                        if(p->display)
1971
                                json_object_set_new(pl, "display", json_string(p->display));
1972
                        json_object_set_new(pl, "muted", p->muted ? json_true() : json_false());
1973
                        json_array_append_new(list, pl);
1974
                }
1975
                janus_mutex_unlock(&audiobridge->mutex);
1976
                janus_mutex_unlock(&rooms_mutex);
1977
                response = json_object();
1978
                json_object_set_new(response, "audiobridge", json_string("participants"));
1979
                json_object_set_new(response, "room", json_integer(room_id));
1980
                json_object_set_new(response, "participants", list);
1981
                goto plugin_response;
1982
        } else if(!strcasecmp(request_text, "resetdecoder")) {
1983
                /* Mark the Opus decoder for the participant invalid and recreate it */        
1984
                janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1985
                if(participant == NULL || participant->room == NULL) {
1986
                        JANUS_LOG(LOG_ERR, "Can't reset (not in a room)\n");
1987
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
1988
                        g_snprintf(error_cause, 512, "Can't reset (not in a room)");
1989
                        goto plugin_response;
1990
                }
1991
                participant->reset = TRUE;
1992
                response = json_object();
1993
                json_object_set_new(response, "audiobridge", json_string("success"));
1994
                goto plugin_response;
1995
        } else if(!strcasecmp(request_text, "rtp_forward")) {
1996
                JANUS_VALIDATE_JSON_OBJECT(root, rtp_forward_parameters,
1997
                        error_code, error_cause, TRUE,
1998
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
1999
                if(error_code != 0)
2000
                        goto plugin_response;
2001
                /* Parse arguments */
2002
                guint64 room_id = json_integer_value(json_object_get(root, "room"));
2003
                guint32 ssrc_value = 0;
2004
                json_t *ssrc = json_object_get(root, "ssrc");
2005
                if(ssrc)
2006
                        ssrc_value = json_integer_value(ssrc);
2007
                int ptype = 100;
2008
                json_t *pt = json_object_get(root, "ptype");
2009
                if(pt)
2010
                        ptype = json_integer_value(pt);
2011
                uint16_t port = json_integer_value(json_object_get(root, "port"));
2012
                json_t *json_host = json_object_get(root, "host");
2013
                const gchar* host = json_string_value(json_host);
2014
                json_t *always = json_object_get(root, "always_on");
2015
                gboolean always_on = always ? json_is_true(always) : FALSE;
2016
                /* Update room */
2017
                janus_mutex_lock(&rooms_mutex);
2018
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2019
                if(audiobridge == NULL) {
2020
                        janus_mutex_unlock(&rooms_mutex);
2021
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2022
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2023
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2024
                        goto plugin_response;
2025
                }
2026
                /* A secret may be required for this action */
2027
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
2028
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2029
                if(error_code != 0) {
2030
                        janus_mutex_unlock(&rooms_mutex);
2031
                        goto plugin_response;
2032
                }
2033
                janus_mutex_lock(&audiobridge->mutex);
2034
                if(audiobridge->destroyed) {
2035
                        janus_mutex_unlock(&audiobridge->mutex);
2036
                        janus_mutex_unlock(&rooms_mutex);
2037
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2038
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2039
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2040
                        goto plugin_response;
2041
                }
2042
                /* Create UDP socket, if needed */
2043
                if(audiobridge->rtp_udp_sock <= 0) {
2044
                        audiobridge->rtp_udp_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
2045
                        if(audiobridge->rtp_udp_sock <= 0) {
2046
                                janus_mutex_unlock(&audiobridge->mutex);
2047
                                janus_mutex_unlock(&rooms_mutex);
2048
                                JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP forwarder (room %"SCNu64")\n", room_id);
2049
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
2050
                                g_snprintf(error_cause, 512, "Could not open UDP socket for RTP forwarder");
2051
                                goto plugin_response;
2052
                        }
2053
                }
2054
                /* Create Opus encoder, if needed */
2055
                if(audiobridge->rtp_encoder == NULL) {
2056
                        int error = 0;
2057
                        audiobridge->rtp_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
2058
                        if(error != OPUS_OK) {
2059
                                janus_mutex_unlock(&audiobridge->mutex);
2060
                                janus_mutex_unlock(&rooms_mutex);
2061
                                JANUS_LOG(LOG_ERR, "Error creating Opus encoder for RTP forwarder (room %"SCNu64")\n", room_id);
2062
                                error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2063
                                g_snprintf(error_cause, 512, "Error creating Opus decoder for RTP forwarder");
2064
                                goto plugin_response;
2065
                        }
2066
                        if(audiobridge->sampling_rate == 8000) {
2067
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
2068
                        } else if(audiobridge->sampling_rate == 12000) {
2069
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
2070
                        } else if(audiobridge->sampling_rate == 16000) {
2071
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2072
                        } else if(audiobridge->sampling_rate == 24000) {
2073
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
2074
                        } else if(audiobridge->sampling_rate == 48000) {
2075
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
2076
                        } else {
2077
                                JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
2078
                                opus_encoder_ctl(audiobridge->rtp_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2079
                        }
2080
                }
2081
                guint32 stream_id = janus_audiobridge_rtp_forwarder_add_helper(audiobridge, host, port, ssrc_value, ptype, always_on);
2082
                janus_mutex_unlock(&audiobridge->mutex);
2083
                janus_mutex_unlock(&rooms_mutex);
2084
                /* Done, prepare response */
2085
                response = json_object();
2086
                json_object_set_new(response, "audiobridge", json_string("success"));
2087
                json_object_set_new(response, "room", json_integer(room_id));
2088
                json_object_set_new(response, "stream_id", json_integer(stream_id));
2089
                goto plugin_response;
2090
        } else if(!strcasecmp(request_text, "stop_rtp_forward")) {
2091
                JANUS_VALIDATE_JSON_OBJECT(root, stop_rtp_forward_parameters,
2092
                        error_code, error_cause, TRUE,
2093
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2094
                if(error_code != 0)
2095
                        goto plugin_response;
2096
                /* Parse parameters */
2097
                guint64 room_id = json_integer_value(json_object_get(root, "room"));
2098
                guint32 stream_id = json_integer_value(json_object_get(root, "stream_id"));
2099
                /* Update room */
2100
                /* Update room */
2101
                janus_mutex_lock(&rooms_mutex);
2102
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2103
                if(audiobridge == NULL) {
2104
                        janus_mutex_unlock(&rooms_mutex);
2105
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2106
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2107
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2108
                        goto plugin_response;
2109
                }
2110
                /* A secret may be required for this action */
2111
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
2112
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2113
                if(error_code != 0) {
2114
                        janus_mutex_unlock(&rooms_mutex);
2115
                        goto plugin_response;
2116
                }
2117
                janus_mutex_lock(&audiobridge->mutex);
2118
                if(audiobridge->destroyed) {
2119
                        janus_mutex_unlock(&audiobridge->mutex);
2120
                        janus_mutex_unlock(&rooms_mutex);
2121
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2122
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2123
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2124
                        goto plugin_response;
2125
                }
2126
                janus_mutex_lock(&audiobridge->rtp_mutex);
2127
                g_hash_table_remove(audiobridge->rtp_forwarders, GUINT_TO_POINTER(stream_id));
2128
                janus_mutex_unlock(&audiobridge->rtp_mutex);
2129
                janus_mutex_unlock(&audiobridge->mutex);
2130
                janus_mutex_unlock(&rooms_mutex);
2131
                response = json_object();
2132
                json_object_set_new(response, "audiobridge", json_string("success"));
2133
                json_object_set_new(response, "room", json_integer(room_id));
2134
                json_object_set_new(response, "stream_id", json_integer(stream_id));
2135
                goto plugin_response;
2136
        } else if(!strcasecmp(request_text, "listforwarders")) {
2137
                /* List all forwarders in a room */
2138
                JANUS_VALIDATE_JSON_OBJECT(root, room_parameters,
2139
                        error_code, error_cause, TRUE,
2140
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2141
                if(error_code != 0)
2142
                        goto plugin_response;
2143
                json_t *room = json_object_get(root, "room");
2144
                guint64 room_id = json_integer_value(room);
2145
                janus_mutex_lock(&rooms_mutex);
2146
                janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2147
                if(audiobridge == NULL) {
2148
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2149
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2150
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2151
                        janus_mutex_unlock(&rooms_mutex);
2152
                        goto plugin_response;
2153
                }
2154
                if(audiobridge->destroyed) {
2155
                        JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2156
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2157
                        g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2158
                        janus_mutex_unlock(&rooms_mutex);
2159
                        goto plugin_response;
2160
                }
2161
                /* A secret may be required for this action */
2162
                JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause,
2163
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2164
                if(error_code != 0) {
2165
                        janus_mutex_unlock(&rooms_mutex);
2166
                        goto plugin_response;
2167
                }
2168
                /* Return a list of all forwarders */
2169
                json_t *list = json_array();
2170
                GHashTableIter iter;
2171
                gpointer key, value;
2172
                janus_mutex_lock(&audiobridge->rtp_mutex);
2173
                g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
2174
                while(g_hash_table_iter_next(&iter, &key, &value)) {
2175
                        guint32 stream_id = GPOINTER_TO_UINT(key);
2176
                        janus_audiobridge_rtp_forwarder *rf = (janus_audiobridge_rtp_forwarder *)value;
2177
                        json_t *fl = json_object();
2178
                        json_object_set_new(fl, "stream_id", json_integer(stream_id));
2179
                        json_object_set_new(fl, "ip", json_string(inet_ntoa(rf->serv_addr.sin_addr)));
2180
                        json_object_set_new(fl, "port", json_integer(ntohs(rf->serv_addr.sin_port)));
2181
                        json_object_set_new(fl, "ssrc", json_integer(rf->ssrc ? rf->ssrc : stream_id));
2182
                        json_object_set_new(fl, "ptype", json_integer(rf->payload_type));
2183
                        json_object_set_new(fl, "always_on", rf->always_on ? json_true() : json_false());
2184
                        json_array_append_new(list, fl);
2185
                }
2186
                janus_mutex_unlock(&audiobridge->rtp_mutex);
2187
                janus_mutex_unlock(&rooms_mutex);
2188
                response = json_object();
2189
                json_object_set_new(response, "audiobridge", json_string("forwarders"));
2190
                json_object_set_new(response, "room", json_integer(room_id));
2191
                json_object_set_new(response, "rtp_forwarders", list);
2192
                goto plugin_response;
2193
        } else if(!strcasecmp(request_text, "join") || !strcasecmp(request_text, "configure")
2194
                        || !strcasecmp(request_text, "changeroom") || !strcasecmp(request_text, "leave")) {
2195
                /* These messages are handled asynchronously */
2196
                janus_audiobridge_message *msg = g_malloc0(sizeof(janus_audiobridge_message));
2197
                msg->handle = handle;
2198
                msg->transaction = transaction;
2199
                msg->message = root;
2200
                msg->jsep = jsep;
2201

    
2202
                g_async_queue_push(messages, msg);
2203

    
2204
                return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL, NULL);
2205
        } else {
2206
                JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
2207
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
2208
                g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
2209
        }
2210

    
2211
plugin_response:
2212
                {
2213
                        if(error_code == 0 && !response) {
2214
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
2215
                                g_snprintf(error_cause, 512, "Invalid response");
2216
                        }
2217
                        if(error_code != 0) {
2218
                                /* Prepare JSON error event */
2219
                                json_t *event = json_object();
2220
                                json_object_set_new(event, "audiobridge", json_string("event"));
2221
                                json_object_set_new(event, "error_code", json_integer(error_code));
2222
                                json_object_set_new(event, "error", json_string(error_cause));
2223
                                response = event;
2224
                        }
2225
                        if(root != NULL)
2226
                                json_decref(root);
2227
                        if(jsep != NULL)
2228
                                json_decref(jsep);
2229
                        g_free(transaction);
2230

    
2231
                        return janus_plugin_result_new(JANUS_PLUGIN_OK, NULL, response);
2232
                }
2233

    
2234
}
2235

    
2236
void janus_audiobridge_setup_media(janus_plugin_session *handle) {
2237
        JANUS_LOG(LOG_INFO, "WebRTC media is now available\n");
2238
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2239
                return;
2240
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
2241
        if(!session) {
2242
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2243
                return;
2244
        }
2245
        if(session->destroyed)
2246
                return;
2247
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2248
        if(!participant)
2249
                return;
2250
        g_atomic_int_set(&session->hangingup, 0);
2251
        /* FIXME Only send this peer the audio mix when we get this event */
2252
        session->started = TRUE;
2253
}
2254

    
2255
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len) {
2256
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2257
                return;
2258
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
2259
        if(!session || session->destroyed || session->stopping || !session->participant)
2260
                return;
2261
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2262
        if(!participant->active || participant->muted || !participant->decoder || !participant->room)
2263
                return;
2264
        /* Save the frame if we're recording this leg */
2265
        janus_recorder_save_frame(participant->arc, buf, len);
2266
        if(participant->active && participant->decoder) {
2267
                /* First of all, check if a reset on the decoder is due */
2268
                if(participant->reset) {
2269
                        /* Create a new decoder and get rid of the old one */
2270
                        int error = 0;
2271
                        OpusDecoder *decoder = opus_decoder_create(participant->room->sampling_rate, 1, &error);
2272
                        if(error != OPUS_OK) {
2273
                                JANUS_LOG(LOG_ERR, "Error resetting Opus decoder...\n");
2274
                        } else {
2275
                                if(participant->decoder)
2276
                                        opus_decoder_destroy(participant->decoder);
2277
                                participant->decoder = decoder;
2278
                                JANUS_LOG(LOG_VERB, "Opus decoder reset\n");
2279
                        }
2280
                        participant->reset = FALSE;
2281
                }
2282
                /* Decode frame (Opus -> slinear) */
2283
                rtp_header *rtp = (rtp_header *)buf;
2284
                janus_audiobridge_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
2285
                pkt->data = g_malloc0(BUFFER_SAMPLES*sizeof(opus_int16));
2286
                pkt->ssrc = 0;
2287
                pkt->timestamp = ntohl(rtp->timestamp);
2288
                pkt->seq_number = ntohs(rtp->seq_number);
2289
                /* We might check the audio level extension to see if this is silence */
2290
                pkt->silence = FALSE;
2291

    
2292
                if(participant->extmap_id > 0) {
2293
                        /* Check the audio levels, in case we need to notify participants about who's talking */
2294
                        int level = 0;
2295
                        if(janus_rtp_header_extension_parse_audio_level(buf, len, participant->extmap_id, &level) == 0) {
2296
                                /* Is this silence? */
2297
                                pkt->silence = (level == 127);
2298
                                if(participant->room->audiolevel_event) {
2299
                                        /* We also need to detect who's talking: update our monitoring stuff */
2300
                                        participant->audio_dBov_sum += level;
2301
                                        participant->audio_active_packets++;
2302
                                        participant->dBov_level = level;
2303
                                        if(participant->audio_active_packets > 0 && participant->audio_active_packets == participant->room->audio_active_packets) {
2304
                                                if((float) participant->audio_dBov_sum / (float) participant->audio_active_packets <
2305
                                                                participant->room->audio_level_average) {
2306
                                                        janus_mutex_lock(&participant->room->mutex);
2307
                                                        /* Notify all participants */
2308
                                                        json_t *event = json_object();
2309
                                                        json_object_set_new(event, "audiobridge", json_string("talking"));
2310
                                                        json_object_set_new(event, "room", json_integer(participant->room->room_id));
2311
                                                        json_object_set_new(event, "id", json_integer(participant->user_id));
2312
                                                        janus_audiobridge_notify_participants(participant, event);
2313
                                                        json_decref(event);
2314
                                                        janus_mutex_unlock(&participant->room->mutex);
2315
                                                        /* Also notify event handlers */
2316
                                                        if(notify_events && gateway->events_is_enabled()) {
2317
                                                                json_t *info = json_object();
2318
                                                                json_object_set_new(info, "audiobridge", json_string("talking"));
2319
                                                                json_object_set_new(info, "room", json_integer(participant->room->room_id));
2320
                                                                json_object_set_new(info, "id", json_integer(participant->user_id));
2321
                                                                gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
2322
                                                        }
2323
                                                }
2324
                                                participant->audio_active_packets = 0;
2325
                                                participant->audio_dBov_sum = 0;
2326
                                        }
2327
                                }
2328
                        }
2329
                }
2330
                participant->working = TRUE;
2331
                int plen = 0;
2332
                const unsigned char *payload = (const unsigned char *)janus_rtp_payload(buf, len, &plen);
2333
                if(!payload) {
2334
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error accessing the RTP payload\n");
2335
                        g_free(pkt->data);
2336
                        g_free(pkt);
2337
                        return;
2338
                }
2339
                pkt->length = opus_decode(participant->decoder, payload, plen, (opus_int16 *)pkt->data, BUFFER_SAMPLES, USE_FEC);
2340
                participant->working = FALSE;
2341
                if(pkt->length < 0) {
2342
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", pkt->length, opus_strerror(pkt->length));
2343
                        g_free(pkt->data);
2344
                        g_free(pkt);
2345
                        return;
2346
                }
2347
                /* Enqueue the decoded frame */
2348
                janus_mutex_lock(&participant->qmutex);
2349
                /* Insert packets sorting by sequence number */
2350
                participant->inbuf = g_list_insert_sorted(participant->inbuf, pkt, &janus_audiobridge_rtp_sort);
2351
                if(participant->prebuffering) {
2352
                        /* Still pre-buffering: do we have enough packets now? */
2353
                        if(g_list_length(participant->inbuf) == DEFAULT_PREBUFFERING) {
2354
                                participant->prebuffering = FALSE;
2355
                                JANUS_LOG(LOG_VERB, "Prebuffering done! Finally adding the user to the mix\n");
2356
                        } else {
2357
                                JANUS_LOG(LOG_VERB, "Still prebuffering (got %d packets), not adding the user to the mix yet\n", g_list_length(participant->inbuf));
2358
                        }
2359
                } else {
2360
                        /* Make sure we're not queueing too many packets: if so, get rid of the older ones */
2361
                        if(g_list_length(participant->inbuf) >= DEFAULT_PREBUFFERING*2) {
2362
                                gint64 now = janus_get_monotonic_time();
2363
                                if(now - participant->last_drop > 5*G_USEC_PER_SEC) {
2364
                                        JANUS_LOG(LOG_WARN, "Too many packets in queue (%d > %d), removing older ones\n",
2365
                                                g_list_length(participant->inbuf), DEFAULT_PREBUFFERING*2);
2366
                                        participant->last_drop = now;
2367
                                }
2368
                                while(g_list_length(participant->inbuf) > DEFAULT_PREBUFFERING*2) {
2369
                                        /* Remove this packet: it's too old */
2370
                                        GList *first = g_list_first(participant->inbuf);
2371
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2372
                                        participant->inbuf = g_list_remove_link(participant->inbuf, first);
2373
                                        first = NULL;
2374
                                        if(pkt == NULL)
2375
                                                continue;
2376
                                        if(pkt->data)
2377
                                                g_free(pkt->data);
2378
                                        pkt->data = NULL;
2379
                                        g_free(pkt);
2380
                                        pkt = NULL;
2381
                                }
2382
                        }
2383
                }
2384
                janus_mutex_unlock(&participant->qmutex);
2385
        }
2386
}
2387

    
2388
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len) {
2389
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2390
                return;
2391
        /* FIXME Should we care? */
2392
}
2393

    
2394
void janus_audiobridge_hangup_media(janus_plugin_session *handle) {
2395
        JANUS_LOG(LOG_INFO, "No WebRTC media anymore\n");
2396
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2397
                return;
2398
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
2399
        if(!session) {
2400
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2401
                return;
2402
        }
2403
        session->started = FALSE;
2404
        if(session->destroyed || !session->participant)
2405
                return;
2406
        if(g_atomic_int_add(&session->hangingup, 1))
2407
                return;
2408
        /* Get rid of participant */
2409
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2410
        janus_mutex_lock(&rooms_mutex);
2411
        janus_audiobridge_room *audiobridge = participant->room;
2412
        if(audiobridge != NULL) {
2413
                janus_mutex_lock(&audiobridge->mutex);
2414
                json_t *event = json_object();
2415
                json_object_set_new(event, "audiobridge", json_string("event"));
2416
                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2417
                json_object_set_new(event, "leaving", json_integer(participant->user_id));
2418
                g_hash_table_remove(audiobridge->participants, &participant->user_id);
2419
                GHashTableIter iter;
2420
                gpointer value;
2421
                g_hash_table_iter_init(&iter, audiobridge->participants);
2422
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2423
                        janus_audiobridge_participant *p = value;
2424
                        if(p == participant) {
2425
                                continue;        /* Skip the leaving participant itself */
2426
                        }
2427
                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2428
                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL);
2429
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2430
                }
2431
                json_decref(event);
2432
                /* Also notify event handlers */
2433
                if(notify_events && gateway->events_is_enabled()) {
2434
                        json_t *info = json_object();
2435
                        json_object_set_new(info, "event", json_string("left"));
2436
                        json_object_set_new(info, "room", json_integer(audiobridge->room_id));
2437
                        json_object_set_new(info, "id", json_integer(participant->user_id));
2438
                        json_object_set_new(info, "display", json_string(participant->display));
2439
                        gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
2440
                }
2441
        }
2442
        /* Get rid of the recorders, if available */
2443
        janus_mutex_lock(&participant->rec_mutex);
2444
        if(participant->arc) {
2445
                janus_recorder_close(participant->arc);
2446
                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2447
                janus_recorder_free(participant->arc);
2448
        }
2449
        participant->arc = NULL;
2450
        janus_mutex_unlock(&participant->rec_mutex);
2451
        /* Free the participant resources */
2452
        janus_mutex_lock(&participant->qmutex);
2453
        participant->active = FALSE;
2454
        participant->muted = TRUE;
2455
        if(participant->display)
2456
                g_free(participant->display);
2457
        participant->display = NULL;
2458
        participant->prebuffering = TRUE;
2459
        /* Make sure we're not using the encoder/decoder right now, we're going to destroy them */
2460
        while(participant->working)
2461
                g_usleep(5000);
2462
        if(participant->encoder)
2463
                opus_encoder_destroy(participant->encoder);
2464
        participant->encoder = NULL;
2465
        if(participant->decoder)
2466
                opus_decoder_destroy(participant->decoder);
2467
        participant->decoder = NULL;
2468
        participant->reset = FALSE;
2469
        participant->audio_active_packets = 0;
2470
        participant->audio_dBov_sum = 0;
2471
        /* Get rid of queued packets */
2472
        while(participant->inbuf) {
2473
                GList *first = g_list_first(participant->inbuf);
2474
                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2475
                participant->inbuf = g_list_remove_link(participant->inbuf, first);
2476
                first = NULL;
2477
                if(pkt == NULL)
2478
                        continue;
2479
                if(pkt->data)
2480
                        g_free(pkt->data);
2481
                pkt->data = NULL;
2482
                g_free(pkt);
2483
                pkt = NULL;
2484
        }
2485
        participant->last_drop = 0;
2486
        janus_mutex_unlock(&participant->qmutex);
2487
        if(audiobridge != NULL) {
2488
                janus_mutex_unlock(&audiobridge->mutex);
2489
        }
2490
        janus_mutex_unlock(&rooms_mutex);
2491
}
2492

    
2493
/* Thread to handle incoming messages */
2494
static void *janus_audiobridge_handler(void *data) {
2495
        JANUS_LOG(LOG_VERB, "Joining AudioBridge handler thread\n");
2496
        janus_audiobridge_message *msg = NULL;
2497
        int error_code = 0;
2498
        char error_cause[512];
2499
        json_t *root = NULL;
2500
        while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) {
2501
                msg = g_async_queue_pop(messages);
2502
                if(msg == NULL)
2503
                        continue;
2504
                if(msg == &exit_message)
2505
                        break;
2506
                if(msg->handle == NULL) {
2507
                        janus_audiobridge_message_free(msg);
2508
                        continue;
2509
                }
2510
                janus_audiobridge_session *session = NULL;
2511
                janus_mutex_lock(&sessions_mutex);
2512
                if(g_hash_table_lookup(sessions, msg->handle) != NULL) {
2513
                        session = (janus_audiobridge_session *)msg->handle->plugin_handle;
2514
                }
2515
                janus_mutex_unlock(&sessions_mutex);
2516
                if(!session) {
2517
                        JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2518
                        janus_audiobridge_message_free(msg);
2519
                        continue;
2520
                }
2521
                if(session->destroyed) {
2522
                        janus_audiobridge_message_free(msg);
2523
                        continue;
2524
                }
2525
                /* Handle request */
2526
                error_code = 0;
2527
                root = NULL;
2528
                if(msg->message == NULL) {
2529
                        JANUS_LOG(LOG_ERR, "No message??\n");
2530
                        error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
2531
                        g_snprintf(error_cause, 512, "%s", "No message??");
2532
                        goto error;
2533
                }
2534
                root = msg->message;
2535
                /* Get the request first */
2536
                JANUS_VALIDATE_JSON_OBJECT(root, request_parameters,
2537
                        error_code, error_cause, TRUE,
2538
                        JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2539
                if(error_code != 0)
2540
                        goto error;
2541
                json_t *request = json_object_get(root, "request");
2542
                const char *request_text = json_string_value(request);
2543
                json_t *event = NULL;
2544
                if(!strcasecmp(request_text, "join")) {
2545
                        JANUS_LOG(LOG_VERB, "Configuring new participant\n");
2546
                        janus_audiobridge_participant *participant = session->participant;
2547
                        if(participant != NULL && participant->room != NULL) {
2548
                                JANUS_LOG(LOG_ERR, "Already in a room (use changeroom to join another one)\n");
2549
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED;
2550
                                g_snprintf(error_cause, 512, "Already in a room (use changeroom to join another one)");
2551
                                goto error;
2552
                        }
2553
                        JANUS_VALIDATE_JSON_OBJECT(root, join_parameters,
2554
                                error_code, error_cause, TRUE,
2555
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2556
                        if(error_code != 0)
2557
                                goto error;
2558
                        json_t *room = json_object_get(root, "room");
2559
                        guint64 room_id = json_integer_value(room);
2560
                        janus_mutex_lock(&rooms_mutex);
2561
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2562
                        if(audiobridge == NULL) {
2563
                                janus_mutex_unlock(&rooms_mutex);
2564
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2565
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2566
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2567
                                goto error;
2568
                        }
2569
                        janus_mutex_lock(&audiobridge->mutex);
2570
                        /* A pin may be required for this action */
2571
                        JANUS_CHECK_SECRET(audiobridge->room_pin, root, "pin", error_code, error_cause,
2572
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2573
                        if(error_code != 0) {
2574
                                janus_mutex_unlock(&audiobridge->mutex);
2575
                                janus_mutex_unlock(&rooms_mutex);
2576
                                goto error;
2577
                        }
2578
                        /* A token might be required too */
2579
                        if(audiobridge->check_tokens) {
2580
                                json_t *token = json_object_get(root, "token");
2581
                                const char *token_text = token ? json_string_value(token) : NULL;
2582
                                if(token_text == NULL || g_hash_table_lookup(audiobridge->allowed, token_text) == NULL) {
2583
                                        JANUS_LOG(LOG_ERR, "Unauthorized (not in the allowed list)\n");
2584
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED;
2585
                                        g_snprintf(error_cause, 512, "Unauthorized (not in the allowed list)");
2586
                                        janus_mutex_unlock(&audiobridge->mutex);
2587
                                        janus_mutex_unlock(&rooms_mutex);
2588
                                        goto error;
2589
                                }
2590
                        }
2591
                        json_t *display = json_object_get(root, "display");
2592
                        const char *display_text = display ? json_string_value(display) : NULL;
2593
                        json_t *muted = json_object_get(root, "muted");
2594
                        json_t *gain = json_object_get(root, "volume");
2595
                        json_t *quality = json_object_get(root, "quality");
2596
                        int volume = gain ? json_integer_value(gain) : 100;
2597
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
2598
                        if(complexity < 1 || complexity > 10) {
2599
                                janus_mutex_unlock(&audiobridge->mutex);
2600
                                janus_mutex_unlock(&rooms_mutex);
2601
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2602
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2603
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2604
                                goto error;
2605
                        }
2606
                        guint64 user_id = 0;
2607
                        json_t *id = json_object_get(root, "id");
2608
                        if(id) {
2609
                                user_id = json_integer_value(id);
2610
                                if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2611
                                        /* User ID already taken */
2612
                                        janus_mutex_unlock(&audiobridge->mutex);
2613
                                        janus_mutex_unlock(&rooms_mutex);
2614
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
2615
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
2616
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
2617
                                        goto error;
2618
                                }
2619
                        }
2620
                        if(user_id == 0) {
2621
                                /* Generate a random ID */
2622
                                while(user_id == 0) {
2623
                                        user_id = janus_random_uint64();
2624
                                        if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
2625
                                                /* User ID already taken, try another one */
2626
                                                user_id = 0;
2627
                                        }
2628
                                }
2629
                        }
2630
                        JANUS_LOG(LOG_VERB, "  -- Participant ID: %"SCNu64"\n", user_id);
2631
                        if(participant == NULL) {
2632
                                participant = g_malloc0(sizeof(janus_audiobridge_participant));
2633
                                participant->active = FALSE;
2634
                                participant->prebuffering = TRUE;
2635
                                participant->display = NULL;
2636
                                participant->inbuf = NULL;
2637
                                participant->outbuf = NULL;
2638
                                participant->last_drop = 0;
2639
                                participant->encoder = NULL;
2640
                                participant->decoder = NULL;
2641
                                participant->reset = FALSE;
2642
                                janus_mutex_init(&participant->qmutex);
2643
                                participant->arc = NULL;
2644
                                janus_mutex_init(&participant->rec_mutex);
2645
                        }
2646
                        participant->session = session;
2647
                        participant->room = audiobridge;
2648
                        participant->user_id = user_id;
2649
                        if(participant->display != NULL)
2650
                                g_free(participant->display);
2651
                        participant->display = display_text ? g_strdup(display_text) : NULL;
2652
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* By default, everyone's unmuted when joining */
2653
                        participant->volume_gain = volume;
2654
                        participant->opus_complexity = complexity;
2655
                        if(participant->outbuf == NULL)
2656
                                participant->outbuf = g_async_queue_new();
2657
                        participant->active = session->started;
2658
                        if(!session->started) {
2659
                                /* Initialize the RTP context only if we're renegotiating */
2660
                                janus_rtp_switching_context_reset(&participant->context);
2661
                                participant->opus_pt = 0;
2662
                                participant->extmap_id = 0;
2663
                                participant->dBov_level = 0;
2664
                        }
2665
                        JANUS_LOG(LOG_VERB, "Creating Opus encoder/decoder (sampling rate %d)\n", audiobridge->sampling_rate);
2666
                        /* Opus encoder */
2667
                        int error = 0;
2668
                        if(participant->encoder == NULL) {
2669
                                participant->encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
2670
                                if(error != OPUS_OK) {
2671
                                        janus_mutex_unlock(&audiobridge->mutex);
2672
                                        janus_mutex_unlock(&rooms_mutex);
2673
                                        if(participant->display)
2674
                                                g_free(participant->display);
2675
                                        g_free(participant);
2676
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2677
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2678
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2679
                                        goto error;
2680
                                }
2681
                                if(audiobridge->sampling_rate == 8000) {
2682
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
2683
                                } else if(audiobridge->sampling_rate == 12000) {
2684
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
2685
                                } else if(audiobridge->sampling_rate == 16000) {
2686
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2687
                                } else if(audiobridge->sampling_rate == 24000) {
2688
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
2689
                                } else if(audiobridge->sampling_rate == 48000) {
2690
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
2691
                                } else {
2692
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
2693
                                        audiobridge->sampling_rate = 16000;
2694
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
2695
                                }
2696
                                /* FIXME This settings should be configurable */
2697
                                opus_encoder_ctl(participant->encoder, OPUS_SET_INBAND_FEC(USE_FEC));
2698
                        }
2699
                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2700
                        if(participant->decoder == NULL) {
2701
                                /* Opus decoder */
2702
                                error = 0;
2703
                                participant->decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
2704
                                if(error != OPUS_OK) {
2705
                                        janus_mutex_unlock(&audiobridge->mutex);
2706
                                        janus_mutex_unlock(&rooms_mutex);
2707
                                        if(participant->display)
2708
                                                g_free(participant->display);
2709
                                        if(participant->encoder)
2710
                                                opus_encoder_destroy(participant->encoder);
2711
                                        participant->encoder = NULL;
2712
                                        if(participant->decoder)
2713
                                                opus_decoder_destroy(participant->decoder);
2714
                                        participant->decoder = NULL;
2715
                                        g_free(participant);
2716
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
2717
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
2718
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
2719
                                        goto error;
2720
                                }
2721
                        }
2722
                        participant->reset = FALSE;
2723
                        /* Finally, start the encoding thread if it hasn't already */
2724
                        if(participant->thread == NULL) {
2725
                                GError *error = NULL;
2726
                                char roomtrunc[5], parttrunc[5];
2727
                                g_snprintf(roomtrunc, sizeof(roomtrunc), "%"SCNu64, audiobridge->room_id);
2728
                                g_snprintf(parttrunc, sizeof(parttrunc), "%"SCNu64, participant->user_id);
2729
                                char tname[16];
2730
                                g_snprintf(tname, sizeof(tname), "mixer %s %s", roomtrunc, parttrunc);
2731
                                participant->thread = g_thread_try_new(tname, &janus_audiobridge_participant_thread, participant, &error);
2732
                                if(error != NULL) {
2733
                                        /* FIXME We should fail here... */
2734
                                        JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the participant thread...\n", error->code, error->message ? error->message : "??");
2735
                                }
2736
                        }
2737
                        
2738
                        /* Done */
2739
                        session->participant = participant;
2740
                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
2741
                        /* Notify the other participants */
2742
                        json_t *newuser = json_object();
2743
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
2744
                        json_object_set_new(newuser, "room", json_integer(room_id));
2745
                        json_t *newuserlist = json_array();
2746
                        json_t *pl = json_object();
2747
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2748
                        if(participant->display)
2749
                                json_object_set_new(pl, "display", json_string(participant->display));
2750
                        json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
2751
                        json_array_append_new(newuserlist, pl);
2752
                        json_object_set_new(newuser, "participants", newuserlist);
2753
                        GHashTableIter iter;
2754
                        gpointer value;
2755
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2756
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2757
                                janus_audiobridge_participant *p = value;
2758
                                if(p == participant) {
2759
                                        continue;
2760
                                }
2761
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2762
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser, NULL);
2763
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2764
                        }
2765
                        json_decref(newuser);
2766
                        /* Return a list of all available participants for the new participant now */
2767
                        json_t *list = json_array();
2768
                        g_hash_table_iter_init(&iter, audiobridge->participants);
2769
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2770
                                janus_audiobridge_participant *p = value;
2771
                                if(p == participant) {
2772
                                        continue;
2773
                                }
2774
                                json_t *pl = json_object();
2775
                                json_object_set_new(pl, "id", json_integer(p->user_id));
2776
                                if(p->display)
2777
                                        json_object_set_new(pl, "display", json_string(p->display));
2778
                                json_object_set_new(pl, "muted", p->muted ? json_true() : json_false());
2779
                                json_array_append_new(list, pl);
2780
                        }
2781
                        janus_mutex_unlock(&audiobridge->mutex);
2782
                        janus_mutex_unlock(&rooms_mutex);
2783
                        event = json_object();
2784
                        json_object_set_new(event, "audiobridge", json_string("joined"));
2785
                        json_object_set_new(event, "room", json_integer(room_id));
2786
                        json_object_set_new(event, "id", json_integer(user_id));
2787
                        json_object_set_new(event, "participants", list);
2788
                        /* Also notify event handlers */
2789
                        if(notify_events && gateway->events_is_enabled()) {
2790
                                json_t *info = json_object();
2791
                                json_object_set_new(info, "event", json_string("joined"));
2792
                                json_object_set_new(info, "room", json_integer(room_id));
2793
                                json_object_set_new(info, "id", json_integer(user_id));
2794
                                json_object_set_new(info, "display", json_string(participant->display));
2795
                                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
2796
                                gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
2797
                        }
2798
                } else if(!strcasecmp(request_text, "configure")) {
2799
                        /* Handle this participant */
2800
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2801
                        if(participant == NULL || participant->room == NULL) {
2802
                                JANUS_LOG(LOG_ERR, "Can't configure (not in a room)\n");
2803
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2804
                                g_snprintf(error_cause, 512, "Can't configure (not in a room)");
2805
                                goto error;
2806
                        }
2807
                        /* Configure settings for this participant */
2808
                        JANUS_VALIDATE_JSON_OBJECT(root, configure_parameters,
2809
                                error_code, error_cause, TRUE,
2810
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2811
                        if(error_code != 0)
2812
                                goto error;
2813
                        json_t *muted = json_object_get(root, "muted");
2814
                        json_t *quality = json_object_get(root, "quality");
2815
                        json_t *gain = json_object_get(root, "volume");
2816
                        json_t *record = json_object_get(root, "record");
2817
                        json_t *recfile = json_object_get(root, "filename");
2818
                        json_t *display = json_object_get(root, "display");
2819
                        if(gain)
2820
                                participant->volume_gain = json_integer_value(gain);
2821
                        if(quality) {
2822
                                int complexity = json_integer_value(quality);
2823
                                if(complexity < 1 || complexity > 10) {
2824
                                        JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
2825
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
2826
                                        g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
2827
                                        goto error;
2828
                                }
2829
                                participant->opus_complexity = complexity;
2830
                                if(participant->encoder)
2831
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
2832
                        }
2833
                        if(muted || display) {
2834
                                if (muted) {
2835
                                        participant->muted = json_is_true(muted);
2836
                                        JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %"SCNu64", user %"SCNu64")\n", participant->muted ? "true" : "false", participant->room->room_id, participant->user_id);
2837
                                        if(participant->muted) {
2838
                                                /* Clear the queued packets waiting to be handled */
2839
                                                janus_mutex_lock(&participant->qmutex);
2840
                                                while(participant->inbuf) {
2841
                                                        GList *first = g_list_first(participant->inbuf);
2842
                                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2843
                                                        participant->inbuf = g_list_remove_link(participant->inbuf, first);
2844
                                                        first = NULL;
2845
                                                        if(pkt == NULL)
2846
                                                                continue;
2847
                                                        if(pkt->data)
2848
                                                                g_free(pkt->data);
2849
                                                        pkt->data = NULL;
2850
                                                        g_free(pkt);
2851
                                                        pkt = NULL;
2852
                                                }
2853
                                                janus_mutex_unlock(&participant->qmutex);
2854
                                        }
2855
                                }
2856
                                if(display) {
2857
                                        char *old_display = participant->display;
2858
                                        char *new_display = g_strdup(json_string_value(display));
2859
                                        participant->display = new_display;
2860
                                        g_free(old_display);
2861
                                        JANUS_LOG(LOG_VERB, "Setting display property: %s (room %"SCNu64", user %"SCNu64")\n", participant->display, participant->room->room_id, participant->user_id);
2862
                                }
2863
                                /* Notify all other participants about the mute/unmute */
2864
                                janus_mutex_lock(&rooms_mutex);
2865
                                janus_audiobridge_room *audiobridge = participant->room;
2866
                                if(audiobridge != NULL) {
2867
                                        janus_mutex_lock(&audiobridge->mutex);
2868
                                        json_t *list = json_array();
2869
                                        json_t *pl = json_object();
2870
                                        json_object_set_new(pl, "id", json_integer(participant->user_id));
2871
                                        if(participant->display)
2872
                                                json_object_set_new(pl, "display", json_string(participant->display));
2873
                                        json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
2874
                                        json_array_append_new(list, pl);
2875
                                        json_t *pub = json_object();
2876
                                        json_object_set_new(pub, "audiobridge", json_string("event"));
2877
                                        json_object_set_new(pub, "room", json_integer(participant->room->room_id));
2878
                                        json_object_set_new(pub, "participants", list);
2879
                                        GHashTableIter iter;
2880
                                        gpointer value;
2881
                                        g_hash_table_iter_init(&iter, audiobridge->participants);
2882
                                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
2883
                                                janus_audiobridge_participant *p = value;
2884
                                                if(p == participant) {
2885
                                                        continue;        /* Skip the new participant itself */
2886
                                                }
2887
                                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2888
                                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL);
2889
                                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2890
                                        }
2891
                                        json_decref(pub);
2892
                                        janus_mutex_unlock(&audiobridge->mutex);
2893
                                }
2894
                                janus_mutex_unlock(&rooms_mutex);
2895
                        }
2896
                        if(record) {
2897
                                janus_mutex_lock(&participant->rec_mutex);
2898
                                if(json_is_true(record)) {
2899
                                        /* Start recording (ignore if recording already) */
2900
                                        if(participant->arc != NULL) {
2901
                                                JANUS_LOG(LOG_WARN, "Already recording participant's audio (room %"SCNu64", user %"SCNu64")\n",
2902
                                                        participant->user_id, participant->room->room_id);
2903
                                        } else {
2904
                                                JANUS_LOG(LOG_INFO, "Starting recording of participant's audio (room %"SCNu64", user %"SCNu64")\n",
2905
                                                        participant->user_id, participant->room->room_id);
2906
                                                char filename[255];
2907
                                                gint64 now = janus_get_real_time();
2908
                                                memset(filename, 0, 255);
2909
                                                const char *recording_base = json_string_value(recfile);
2910
                                                if(recording_base) {
2911
                                                        /* Use the filename and path we have been provided */
2912
                                                        g_snprintf(filename, 255, "%s-audio", recording_base);
2913
                                                        participant->arc = janus_recorder_create(NULL, "opus", filename);
2914
                                                        if(participant->arc == NULL) {
2915
                                                                /* FIXME We should notify the fact the recorder could not be created */
2916
                                                                JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this participant!\n");
2917
                                                        }
2918
                                                } else {
2919
                                                        /* Build a filename */
2920
                                                        g_snprintf(filename, 255, "audiobridge-%"SCNu64"-%"SCNu64"-%"SCNi64"-audio",
2921
                                                                participant->user_id, participant->room->room_id, now);
2922
                                                        participant->arc = janus_recorder_create(NULL, "opus", filename);
2923
                                                        if(participant->arc == NULL) {
2924
                                                                /* FIXME We should notify the fact the recorder could not be created */
2925
                                                                JANUS_LOG(LOG_ERR, "Couldn't open an audio recording file for this participant!\n");
2926
                                                        }
2927
                                                }
2928
                                        }
2929
                                } else {
2930
                                        /* Stop recording (ignore if not recording) */
2931
                                        if(participant->arc) {
2932
                                                janus_recorder_close(participant->arc);
2933
                                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2934
                                                janus_recorder_free(participant->arc);
2935
                                        }
2936
                                        participant->arc = NULL;
2937
                                }
2938
                                janus_mutex_unlock(&participant->rec_mutex);
2939
                        }
2940
                        /* Done */
2941
                        event = json_object();
2942
                        json_object_set_new(event, "audiobridge", json_string("event"));
2943
                        json_object_set_new(event, "result", json_string("ok"));
2944
                        /* Also notify event handlers */
2945
                        if(notify_events && gateway->events_is_enabled()) {
2946
                                janus_audiobridge_room *audiobridge = participant->room;
2947
                                json_t *info = json_object();
2948
                                json_object_set_new(info, "event", json_string("configured"));
2949
                                json_object_set_new(info, "room", json_integer(audiobridge->room_id));
2950
                                json_object_set_new(info, "id", json_integer(participant->user_id));
2951
                                json_object_set_new(info, "display", json_string(participant->display));
2952
                                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
2953
                                json_object_set_new(info, "quality", json_integer(participant->opus_complexity));
2954
                                gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
2955
                        }
2956
                } else if(!strcasecmp(request_text, "changeroom")) {
2957
                        /* The participant wants to leave the current room and join another one without reconnecting (e.g., a sidebar) */
2958
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2959
                        if(participant == NULL || participant->room == NULL) {
2960
                                JANUS_LOG(LOG_ERR, "Can't change room (not in a room in the first place)\n");
2961
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
2962
                                g_snprintf(error_cause, 512, "Can't change room (not in a room in the first place)");
2963
                                goto error;
2964
                        }
2965
                        JANUS_VALIDATE_JSON_OBJECT(root, join_parameters,
2966
                                error_code, error_cause, TRUE,
2967
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
2968
                        if(error_code != 0)
2969
                                goto error;
2970
                        json_t *room = json_object_get(root, "room");
2971
                        guint64 room_id = json_integer_value(room);
2972
                        janus_mutex_lock(&rooms_mutex);
2973
                        /* Is this the same room we're in? */
2974
                        if(participant->room && participant->room->room_id == room_id) {
2975
                                janus_mutex_unlock(&rooms_mutex);
2976
                                JANUS_LOG(LOG_ERR, "Already in this room\n");
2977
                                error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED;
2978
                                g_snprintf(error_cause, 512, "Already in this room");
2979
                                goto error;
2980
                        }
2981
                        janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id);
2982
                        if(audiobridge == NULL) {
2983
                                janus_mutex_unlock(&rooms_mutex);
2984
                                JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id);
2985
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM;
2986
                                g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id);
2987
                                goto error;
2988
                        }
2989
                        janus_mutex_lock(&audiobridge->mutex);
2990
                        /* A pin may be required for this action */
2991
                        JANUS_CHECK_SECRET(audiobridge->room_pin, root, "pin", error_code, error_cause,
2992
                                JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
2993
                        if(error_code != 0) {
2994
                                janus_mutex_unlock(&audiobridge->mutex);
2995
                                janus_mutex_unlock(&rooms_mutex);
2996
                                goto error;
2997
                        }
2998
                        /* A token might be required too */
2999
                        if(audiobridge->check_tokens) {
3000
                                json_t *token = json_object_get(root, "token");
3001
                                const char *token_text = token ? json_string_value(token) : NULL;
3002
                                if(token_text == NULL || g_hash_table_lookup(audiobridge->allowed, token_text) == NULL) {
3003
                                        JANUS_LOG(LOG_ERR, "Unauthorized (not in the allowed list)\n");
3004
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED;
3005
                                        g_snprintf(error_cause, 512, "Unauthorized (not in the allowed list)");
3006
                                        janus_mutex_unlock(&audiobridge->mutex);
3007
                                        janus_mutex_unlock(&rooms_mutex);
3008
                                        goto error;
3009
                                }
3010
                        }
3011
                        json_t *display = json_object_get(root, "display");
3012
                        const char *display_text = display ? json_string_value(display) : NULL;
3013
                        json_t *muted = json_object_get(root, "muted");
3014
                        json_t *gain = json_object_get(root, "volume");
3015
                        json_t *quality = json_object_get(root, "quality");
3016
                        int volume = gain ? json_integer_value(gain) : 100;
3017
                        int complexity = quality ? json_integer_value(quality) : DEFAULT_COMPLEXITY;
3018
                        if(complexity < 1 || complexity > 10) {
3019
                                janus_mutex_unlock(&audiobridge->mutex);
3020
                                janus_mutex_unlock(&rooms_mutex);
3021
                                JANUS_LOG(LOG_ERR, "Invalid element (quality should be a positive integer between 1 and 10)\n");
3022
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT;
3023
                                g_snprintf(error_cause, 512, "Invalid element (quality should be a positive integer between 1 and 10)");
3024
                                goto error;
3025
                        }
3026
                        guint64 user_id = 0;
3027
                        json_t *id = json_object_get(root, "id");
3028
                        if(id) {
3029
                                user_id = json_integer_value(id);
3030
                                if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
3031
                                        /* User ID already taken */
3032
                                        janus_mutex_unlock(&audiobridge->mutex);
3033
                                        janus_mutex_unlock(&rooms_mutex);
3034
                                        JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id);
3035
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS;
3036
                                        g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id);
3037
                                        goto error;
3038
                                }
3039
                        }
3040
                        if(user_id == 0) {
3041
                                /* Generate a random ID */
3042
                                while(user_id == 0) {
3043
                                        user_id = janus_random_uint64();
3044
                                        if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) {
3045
                                                /* User ID already taken, try another one */
3046
                                                user_id = 0;
3047
                                        }
3048
                                }
3049
                        }
3050
                        JANUS_LOG(LOG_VERB, "  -- Participant ID in new room %"SCNu64": %"SCNu64"\n", room_id, user_id);
3051
                        participant->prebuffering = TRUE;
3052
                        participant->audio_active_packets = 0;
3053
                        participant->audio_dBov_sum = 0;
3054
                        /* Is the sampling rate of the new room the same as the one in the old room, or should we update the decoder/encoder? */
3055
                        janus_audiobridge_room *old_audiobridge = participant->room;
3056
                        /* Leave the old room first... */
3057
                        janus_mutex_lock(&old_audiobridge->mutex);
3058
                        g_hash_table_remove(old_audiobridge->participants, &participant->user_id);
3059
                        if(old_audiobridge->sampling_rate != audiobridge->sampling_rate) {
3060
                                /* Create a new one that takes into account the sampling rate we want now */
3061
                                int error = 0;
3062
                                OpusEncoder *new_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error);
3063
                                if(error != OPUS_OK) {
3064
                                        if(new_encoder)
3065
                                                opus_encoder_destroy(new_encoder);
3066
                                        new_encoder = NULL;
3067
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
3068
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
3069
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
3070
                                        /* Join the old room again... */
3071
                                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
3072
                                        janus_mutex_unlock(&old_audiobridge->mutex);
3073
                                        janus_mutex_unlock(&audiobridge->mutex);
3074
                                        janus_mutex_unlock(&rooms_mutex);
3075
                                        goto error;
3076
                                }
3077
                                if(audiobridge->sampling_rate == 8000) {
3078
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
3079
                                } else if(audiobridge->sampling_rate == 12000) {
3080
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
3081
                                } else if(audiobridge->sampling_rate == 16000) {
3082
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
3083
                                } else if(audiobridge->sampling_rate == 24000) {
3084
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
3085
                                } else if(audiobridge->sampling_rate == 48000) {
3086
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
3087
                                } else {
3088
                                        JANUS_LOG(LOG_WARN, "Unsupported sampling rate %d, setting 16kHz\n", audiobridge->sampling_rate);
3089
                                        audiobridge->sampling_rate = 16000;
3090
                                        opus_encoder_ctl(new_encoder, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
3091
                                }
3092
                                /* FIXME This settings should be configurable */
3093
                                opus_encoder_ctl(new_encoder, OPUS_SET_INBAND_FEC(USE_FEC));
3094
                                opus_encoder_ctl(new_encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
3095
                                /* Opus decoder */
3096
                                error = 0;
3097
                                OpusDecoder *new_decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error);
3098
                                if(error != OPUS_OK) {
3099
                                        if(new_encoder)
3100
                                                opus_encoder_destroy(new_encoder);
3101
                                        new_encoder = NULL;
3102
                                        if(new_decoder)
3103
                                                opus_decoder_destroy(new_decoder);
3104
                                        new_decoder = NULL;
3105
                                        JANUS_LOG(LOG_ERR, "Error creating Opus encoder\n");
3106
                                        error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR;
3107
                                        g_snprintf(error_cause, 512, "Error creating Opus decoder");
3108
                                        /* Join the old room again... */
3109
                                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
3110
                                        janus_mutex_unlock(&old_audiobridge->mutex);
3111
                                        janus_mutex_unlock(&audiobridge->mutex);
3112
                                        janus_mutex_unlock(&rooms_mutex);
3113
                                        goto error;
3114
                                }
3115
                                participant->reset = FALSE;
3116
                                /* Destroy the previous encoder/decoder and update the references */
3117
                                if(participant->encoder)
3118
                                        opus_encoder_destroy(participant->encoder);
3119
                                participant->encoder = new_encoder;
3120
                                if(participant->decoder)
3121
                                        opus_decoder_destroy(participant->decoder);
3122
                                participant->decoder = new_decoder;
3123
                        }
3124
                        /* Everything looks fine, start by telling the folks in the old room this participant is going away */
3125
                        event = json_object();
3126
                        json_object_set_new(event, "audiobridge", json_string("event"));
3127
                        json_object_set_new(event, "room", json_integer(old_audiobridge->room_id));
3128
                        json_object_set_new(event, "leaving", json_integer(participant->user_id));
3129
                        GHashTableIter iter;
3130
                        gpointer value;
3131
                        g_hash_table_iter_init(&iter, old_audiobridge->participants);
3132
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
3133
                                janus_audiobridge_participant *p = value;
3134
                                if(p == participant) {
3135
                                        continue;        /* Skip the new participant itself */
3136
                                }
3137
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
3138
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL);
3139
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
3140
                        }
3141
                        json_decref(event);
3142
                        /* Also notify event handlers */
3143
                        if(notify_events && gateway->events_is_enabled()) {
3144
                                json_t *info = json_object();
3145
                                json_object_set_new(info, "event", json_string("left"));
3146
                                json_object_set_new(info, "room", json_integer(old_audiobridge->room_id));
3147
                                json_object_set_new(info, "id", json_integer(participant->user_id));
3148
                                json_object_set_new(info, "display", json_string(participant->display));
3149
                                gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
3150
                        }
3151
                        janus_mutex_unlock(&old_audiobridge->mutex);
3152
                        /* Stop recording, if we were (since this is a new room, a new recording would be required, so a new configure) */
3153
                        janus_mutex_lock(&participant->rec_mutex);
3154
                        if(participant->arc) {
3155
                                janus_recorder_close(participant->arc);
3156
                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
3157
                                janus_recorder_free(participant->arc);
3158
                        }
3159
                        participant->arc = NULL;
3160
                        janus_mutex_unlock(&participant->rec_mutex);
3161
                        /* Done, join the new one */
3162
                        participant->user_id = user_id;
3163
                        if(display_text) {
3164
                                g_free(participant->display);
3165
                                participant->display = display_text ? g_strdup(display_text) : NULL;
3166
                        }
3167
                        participant->room = audiobridge;
3168
                        participant->muted = muted ? json_is_true(muted) : FALSE;        /* When switching to a new room, you're unmuted by default */
3169
                        participant->audio_active_packets = 0;
3170
                        participant->audio_dBov_sum = 0;
3171
                        participant->volume_gain = volume;
3172
                        if(quality) {
3173
                                participant->opus_complexity = complexity;
3174
                                if(participant->encoder)
3175
                                        opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity));
3176
                        }
3177
                        g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant);
3178
                        /* Notify the other participants */
3179
                        json_t *newuser = json_object();
3180
                        json_object_set_new(newuser, "audiobridge", json_string("joined"));
3181
                        json_object_set_new(newuser, "room", json_integer(audiobridge->room_id));
3182
                        json_t *newuserlist = json_array();
3183
                        json_t *pl = json_object();
3184
                        json_object_set_new(pl, "id", json_integer(participant->user_id));
3185
                        if(participant->display)
3186
                                json_object_set_new(pl, "display", json_string(participant->display));
3187
                        json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
3188
                        json_array_append_new(newuserlist, pl);
3189
                        json_object_set_new(newuser, "participants", newuserlist);
3190
                        g_hash_table_iter_init(&iter, audiobridge->participants);
3191
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
3192
                                janus_audiobridge_participant *p = value;
3193
                                if(p == participant) {
3194
                                        continue;
3195
                                }
3196
                                JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
3197
                                int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser, NULL);
3198
                                JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
3199
                        }
3200
                        json_decref(newuser);
3201
                        /* Return a list of all available participants for the new participant now */
3202
                        json_t *list = json_array();
3203
                        g_hash_table_iter_init(&iter, audiobridge->participants);
3204
                        while (g_hash_table_iter_next(&iter, NULL, &value)) {
3205
                                janus_audiobridge_participant *p = value;
3206
                                if(p == participant) {
3207
                                        continue;
3208
                                }
3209
                                json_t *pl = json_object();
3210
                                json_object_set_new(pl, "id", json_integer(p->user_id));
3211
                                if(p->display)
3212
                                        json_object_set_new(pl, "display", json_string(p->display));
3213
                                json_object_set_new(pl, "muted", p->muted ? json_true() : json_false());
3214
                                json_array_append_new(list, pl);
3215
                        }
3216
                        event = json_object();
3217
                        json_object_set_new(event, "audiobridge", json_string("roomchanged"));
3218
                        json_object_set_new(event, "room", json_integer(audiobridge->room_id));
3219
                        json_object_set_new(event, "id", json_integer(user_id));
3220
                        json_object_set_new(event, "participants", list);
3221
                        /* Also notify event handlers */
3222
                        if(notify_events && gateway->events_is_enabled()) {
3223
                                json_t *info = json_object();
3224
                                json_object_set_new(info, "event", json_string("joined"));
3225
                                json_object_set_new(info, "room", json_integer(audiobridge->room_id));
3226
                                json_object_set_new(info, "id", json_integer(participant->user_id));
3227
                                json_object_set_new(info, "display", json_string(participant->display));
3228
                                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
3229
                                gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
3230
                        }
3231
                        janus_mutex_unlock(&audiobridge->mutex);
3232
                        janus_mutex_unlock(&rooms_mutex);
3233
                } else if(!strcasecmp(request_text, "leave")) {
3234
                        /* This participant is leaving */
3235
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
3236
                        if(participant == NULL || participant->room == NULL) {
3237
                                JANUS_LOG(LOG_ERR, "Can't leave (not in a room)\n");
3238
                                error_code = JANUS_AUDIOBRIDGE_ERROR_NOT_JOINED;
3239
                                g_snprintf(error_cause, 512, "Can't leave (not in a room)");
3240
                                goto error;
3241
                        }
3242
                        /* Tell everybody */
3243
                        janus_mutex_lock(&rooms_mutex);
3244
                        janus_audiobridge_room *audiobridge = participant->room;
3245
                        if(audiobridge != NULL) {
3246
                                janus_mutex_lock(&audiobridge->mutex);
3247
                                event = json_object();
3248
                                json_object_set_new(event, "audiobridge", json_string("event"));
3249
                                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
3250
                                json_object_set_new(event, "leaving", json_integer(participant->user_id));
3251
                                GHashTableIter iter;
3252
                                gpointer value;
3253
                                g_hash_table_iter_init(&iter, audiobridge->participants);
3254
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
3255
                                        janus_audiobridge_participant *p = value;
3256
                                        if(p == participant) {
3257
                                                continue;        /* Skip the new participant itself */
3258
                                        }
3259
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
3260
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL);
3261
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
3262
                                }
3263
                                json_decref(event);
3264
                                /* Actually leave the room... */
3265
                                g_hash_table_remove(audiobridge->participants, &participant->user_id);
3266
                                participant->room = NULL;
3267
                        }
3268
                        /* Get rid of queued packets */
3269
                        janus_mutex_lock(&participant->qmutex);
3270
                        participant->active = FALSE;
3271
                        participant->prebuffering = TRUE;
3272
                        while(participant->inbuf) {
3273
                                GList *first = g_list_first(participant->inbuf);
3274
                                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
3275
                                participant->inbuf = g_list_remove_link(participant->inbuf, first);
3276
                                first = NULL;
3277
                                if(pkt == NULL)
3278
                                        continue;
3279
                                if(pkt->data)
3280
                                        g_free(pkt->data);
3281
                                pkt->data = NULL;
3282
                                g_free(pkt);
3283
                                pkt = NULL;
3284
                        }
3285
                        janus_mutex_unlock(&participant->qmutex);
3286
                        /* Stop recording, if we were */
3287
                        janus_mutex_lock(&participant->rec_mutex);
3288
                        if(participant->arc) {
3289
                                janus_recorder_close(participant->arc);
3290
                                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
3291
                                janus_recorder_free(participant->arc);
3292
                        }
3293
                        participant->arc = NULL;
3294
                        janus_mutex_unlock(&participant->rec_mutex);
3295
                        /* Also notify event handlers */
3296
                        if(notify_events && gateway->events_is_enabled()) {
3297
                                json_t *info = json_object();
3298
                                json_object_set_new(info, "event", json_string("left"));
3299
                                json_object_set_new(info, "room", json_integer(audiobridge->room_id));
3300
                                json_object_set_new(info, "id", json_integer(participant->user_id));
3301
                                json_object_set_new(info, "display", json_string(participant->display));
3302
                                gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
3303
                        }
3304
                        /* Done */
3305
                        event = json_object();
3306
                        json_object_set_new(event, "audiobridge", json_string("left"));
3307
                        if(audiobridge != NULL) {
3308
                                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
3309
                                janus_mutex_unlock(&audiobridge->mutex);
3310
                        }
3311
                        json_object_set_new(event, "id", json_integer(participant->user_id));
3312
                        janus_mutex_unlock(&rooms_mutex);
3313
                } else {
3314
                        JANUS_LOG(LOG_ERR, "Unknown request '%s'\n", request_text);
3315
                        error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
3316
                        g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
3317
                        goto error;
3318
                }
3319

    
3320
                /* Prepare JSON event */
3321
                JANUS_LOG(LOG_VERB, "Preparing JSON event as a reply\n");
3322
                /* Any SDP to handle? */
3323
                const char *msg_sdp_type = json_string_value(json_object_get(msg->jsep, "type"));
3324
                const char *msg_sdp = json_string_value(json_object_get(msg->jsep, "sdp"));
3325
                if(!msg_sdp) {
3326
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, NULL);
3327
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
3328
                        json_decref(event);
3329
                } else {
3330
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg_sdp_type, msg_sdp);
3331
                        /* Prepare an SDP answer */
3332
                        const char *type = "answer";
3333
                        char error_str[512];
3334
                        janus_sdp *offer = janus_sdp_parse(msg_sdp, error_str, sizeof(error_str));
3335
                        if(offer == NULL) {
3336
                                json_decref(event);
3337
                                JANUS_LOG(LOG_ERR, "Error parsing offer: %s\n", error_str);
3338
                                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_SDP;
3339
                                g_snprintf(error_cause, 512, "Error parsing offer: %s", error_str);
3340
                                goto error;
3341
                        }
3342
                        /* What is the Opus payload type? */
3343
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
3344
                        participant->opus_pt = janus_sdp_get_codec_pt(offer, "opus");
3345
                        if(participant->opus_pt < 0) {
3346
                                /* TODO Handle this case */
3347
                                JANUS_LOG(LOG_ERR, "Offer doesn't contain Opus..?\n");
3348
                        }
3349
                        JANUS_LOG(LOG_VERB, "Opus payload type is %d\n", participant->opus_pt);
3350
                        /* Check if the audio level extension was offered */
3351
                        int extmap_id = -1;
3352
                        janus_sdp_mdirection extmap_mdir = JANUS_SDP_SENDRECV;
3353
                        GList *temp = offer->m_lines;
3354
                        while(temp) {
3355
                                janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
3356
                                if(m->type == JANUS_SDP_AUDIO) {
3357
                                        GList *ma = m->attributes;
3358
                                        while(ma) {
3359
                                                janus_sdp_attribute *a = (janus_sdp_attribute *)ma->data;
3360
                                                if(a->value) {
3361
                                                        if(strstr(a->value, JANUS_RTP_EXTMAP_AUDIO_LEVEL)) {
3362
                                                                extmap_id = atoi(a->value);
3363
                                                                extmap_mdir = a->direction;
3364
                                                        }
3365
                                                }
3366
                                                ma = ma->next;
3367
                                        }
3368
                                }
3369
                                temp = temp->next;
3370
                        }
3371
                        janus_sdp *answer = janus_sdp_generate_answer(offer,
3372
                                /* Reject video and data channels, if offered */
3373
                                JANUS_SDP_OA_VIDEO, FALSE,
3374
                                JANUS_SDP_OA_DATA, FALSE,
3375
                                JANUS_SDP_OA_DONE);
3376
                        /* Replace the session name */
3377
                        g_free(answer->s_name);
3378
                        answer->s_name = g_strdup(participant->room->room_name);
3379
                        /* Add a fmtp attribute */
3380
                        janus_sdp_attribute *a = janus_sdp_attribute_create("fmtp",
3381
                                "%d maxplaybackrate=%"SCNu32"; stereo=0; sprop-stereo=0; useinbandfec=0\r\n",
3382
                                        participant->opus_pt, participant->room->sampling_rate);
3383
                        janus_sdp_attribute_add_to_mline(janus_sdp_mline_find(answer, JANUS_SDP_AUDIO), a);
3384
                        /* Is the audio level extension negotiated? */
3385
                        participant->extmap_id = 0;
3386
                        participant->dBov_level = 0;
3387
                        if(extmap_id > -1 && participant->room && participant->room->audiolevel_ext) {
3388
                                /* Add an extmap attribute too */
3389
                                participant->extmap_id = extmap_id;
3390
                                /* Let's check if the extmap attribute had a direction */
3391
                                const char *direction = NULL;
3392
                                switch(extmap_mdir) {
3393
                                        case JANUS_SDP_SENDONLY:
3394
                                                direction = "/recvonly";
3395
                                                break;
3396
                                        case JANUS_SDP_RECVONLY:
3397
                                        case JANUS_SDP_INACTIVE:
3398
                                                direction = "/inactive";
3399
                                                break;
3400
                                        default:
3401
                                                direction = "";
3402
                                                break;
3403
                                }
3404
                                janus_sdp_attribute *a = janus_sdp_attribute_create("extmap",
3405
                                        "%d%s %s\r\n", extmap_id, direction, JANUS_RTP_EXTMAP_AUDIO_LEVEL);
3406
                                janus_sdp_attribute_add_to_mline(janus_sdp_mline_find(answer, JANUS_SDP_AUDIO), a);
3407
                        }
3408
                        /* Prepare the response */
3409
                        char *sdp = janus_sdp_write(answer);
3410
                        janus_sdp_free(offer);
3411
                        janus_sdp_free(answer);
3412
                        json_t *jsep = json_pack("{ssss}", "type", type, "sdp", sdp);
3413
                        /* How long will the gateway take to push the event? */
3414
                        g_atomic_int_set(&session->hangingup, 0);
3415
                        gint64 start = janus_get_monotonic_time();
3416
                        int res = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, jsep);
3417
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (took %"SCNu64" us)\n", res, janus_get_monotonic_time()-start);
3418
                        json_decref(event);
3419
                        json_decref(jsep);
3420
                        g_free(sdp);
3421
                        if(res != JANUS_OK) {
3422
                                /* TODO Failed to negotiate? We should remove this participant */
3423
                        } else {
3424
                                /* Notify all other participants that there's a new boy in town */
3425
                                janus_mutex_lock(&rooms_mutex);
3426
                                janus_audiobridge_room *audiobridge = participant->room;
3427
                                janus_mutex_lock(&audiobridge->mutex);
3428
                                json_t *list = json_array();
3429
                                json_t *pl = json_object();
3430
                                json_object_set_new(pl, "id", json_integer(participant->user_id));
3431
                                if(participant->display)
3432
                                        json_object_set_new(pl, "display", json_string(participant->display));
3433
                                json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
3434
                                json_array_append_new(list, pl);
3435
                                json_t *pub = json_object();
3436
                                json_object_set_new(pub, "audiobridge", json_string("event"));
3437
                                json_object_set_new(pub, "room", json_integer(participant->room->room_id));
3438
                                json_object_set_new(pub, "participants", list);
3439
                                GHashTableIter iter;
3440
                                gpointer value;
3441
                                g_hash_table_iter_init(&iter, audiobridge->participants);
3442
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
3443
                                        janus_audiobridge_participant *p = value;
3444
                                        if(p == participant) {
3445
                                                continue;        /* Skip the new participant itself */
3446
                                        }
3447
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
3448
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL);
3449
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
3450
                                }
3451
                                json_decref(pub);
3452
                                participant->active = TRUE;
3453
                                janus_mutex_unlock(&audiobridge->mutex);
3454
                                janus_mutex_unlock(&rooms_mutex);
3455
                        }
3456
                }
3457
                if(msg)
3458
                        janus_audiobridge_message_free(msg);
3459
                msg = NULL;
3460

    
3461
                continue;
3462
                
3463
error:
3464
                {
3465
                        /* Prepare JSON error event */
3466
                        json_t *event = json_object();
3467
                        json_object_set_new(event, "audiobridge", json_string("event"));
3468
                        json_object_set_new(event, "error_code", json_integer(error_code));
3469
                        json_object_set_new(event, "error", json_string(error_cause));
3470
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, NULL);
3471
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
3472
                        json_decref(event);
3473
                        janus_audiobridge_message_free(msg);
3474
                }
3475
        }
3476
        JANUS_LOG(LOG_VERB, "Leaving AudioBridge handler thread\n");
3477
        return NULL;
3478
}
3479

    
3480
/* Thread to mix the contributions from all participants */
3481
static void *janus_audiobridge_mixer_thread(void *data) {
3482
        JANUS_LOG(LOG_VERB, "Audio bridge thread starting...\n");
3483
        janus_audiobridge_room *audiobridge = (janus_audiobridge_room *)data;
3484
        if(!audiobridge) {
3485
                JANUS_LOG(LOG_ERR, "Invalid room!\n");
3486
                return NULL;
3487
        }
3488
        JANUS_LOG(LOG_VERB, "Thread is for mixing room %"SCNu64" (%s) at rate %"SCNu32"...\n", audiobridge->room_id, audiobridge->room_name, audiobridge->sampling_rate);
3489

    
3490
        /* Do we need to record the mix? */
3491
        if(audiobridge->record) {
3492
                char filename[255];
3493
                if(audiobridge->record_file) {
3494
                        g_snprintf(filename, 255, "%s", audiobridge->record_file);
3495
                } else {
3496
                        g_snprintf(filename, 255, "janus-audioroom-%"SCNu64".wav", audiobridge->room_id);
3497
                }
3498
                audiobridge->recording = fopen(filename, "wb");
3499
                if(audiobridge->recording == NULL) {
3500
                        JANUS_LOG(LOG_WARN, "Recording requested, but could NOT open file %s for writing...\n", filename);
3501
                } else {
3502
                        JANUS_LOG(LOG_VERB, "Recording requested, opened file %s for writing\n", filename);
3503
                        /* Write WAV header */
3504
                        wav_header header = {
3505
                                {'R', 'I', 'F', 'F'},
3506
                                0,
3507
                                {'W', 'A', 'V', 'E'},
3508
                                {'f', 'm', 't', ' '},
3509
                                16,
3510
                                1,
3511
                                1,
3512
                                audiobridge->sampling_rate,
3513
                                audiobridge->sampling_rate * 2,
3514
                                2,
3515
                                16,
3516
                                {'d', 'a', 't', 'a'},
3517
                                0
3518
                        };
3519
                        if(fwrite(&header, 1, sizeof(header), audiobridge->recording) != sizeof(header)) {
3520
                                JANUS_LOG(LOG_ERR, "Error writing WAV header...\n");
3521
                        }
3522
                        fflush(audiobridge->recording);
3523
                        audiobridge->record_lastupdate = janus_get_monotonic_time();
3524
                }
3525
        }
3526

    
3527
        /* Buffer (we allocate assuming 48kHz, although we'll likely use less than that) */
3528
        int samples = audiobridge->sampling_rate/50;
3529
        opus_int32 buffer[960], sumBuffer[960];
3530
        opus_int16 outBuffer[960], *curBuffer = NULL;
3531
        memset(buffer, 0, 960*4);
3532
        memset(sumBuffer, 0, 960*4);
3533
        memset(outBuffer, 0, 960*2);
3534

    
3535
        /* Base RTP packet, in case there are forwarders involved */
3536
        unsigned char *rtpbuffer = g_malloc0(1500);
3537
        rtp_header *rtph = (rtp_header *)rtpbuffer;
3538
        rtph->version = 2;
3539

    
3540
        /* Timer */
3541
        struct timeval now, before;
3542
        gettimeofday(&before, NULL);
3543
        now.tv_sec = before.tv_sec;
3544
        now.tv_usec = before.tv_usec;
3545
        time_t passed, d_s, d_us;
3546

    
3547
        /* RTP */
3548
        gint16 seq = 0;
3549
        gint32 ts = 0;
3550

    
3551
        /* Loop */
3552
        int i=0;
3553
        int count = 0, rf_count = 0, prev_count = 0;
3554
        while(!g_atomic_int_get(&stopping) && audiobridge->destroyed == 0) {        /* FIXME We need a per-room watchdog as well */
3555
                /* See if it's time to prepare a frame */
3556
                gettimeofday(&now, NULL);
3557
                d_s = now.tv_sec - before.tv_sec;
3558
                d_us = now.tv_usec - before.tv_usec;
3559
                if(d_us < 0) {
3560
                        d_us += 1000000;
3561
                        --d_s;
3562
                }
3563
                passed = d_s*1000000 + d_us;
3564
                if(passed < 15000) {        /* Let's wait about 15ms at max */
3565
                        usleep(1000);
3566
                        continue;
3567
                }
3568
                /* Update the reference time */
3569
                before.tv_usec += 20000;
3570
                if(before.tv_usec > 1000000) {
3571
                        before.tv_sec++;
3572
                        before.tv_usec -= 1000000;
3573
                }
3574
                /* Do we need to mix at all? */
3575
                janus_mutex_lock_nodebug(&audiobridge->mutex);
3576
                count = g_hash_table_size(audiobridge->participants);
3577
                rf_count = g_hash_table_size(audiobridge->rtp_forwarders);
3578
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
3579
                if((count+rf_count) == 0) {
3580
                        /* No participant and RTP forwarders, do nothing */
3581
                        if(prev_count > 0) {
3582
                                JANUS_LOG(LOG_VERB, "Last user/forwarder just left room %"SCNu64", going idle...\n", audiobridge->room_id);
3583
                                prev_count = 0;
3584
                        }
3585
                        continue;
3586
                }
3587
                if(prev_count == 0) {
3588
                        JANUS_LOG(LOG_VERB, "First user/forwarder just joined room %"SCNu64", waking it up...\n", audiobridge->room_id);
3589
                }
3590
                prev_count = count+rf_count;
3591
                /* Update RTP header information */
3592
                seq++;
3593
                ts += 960;
3594
                /* Mix all contributions */
3595
                janus_mutex_lock_nodebug(&audiobridge->mutex);
3596
                GList *participants_list = g_hash_table_get_values(audiobridge->participants);
3597
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
3598
                for(i=0; i<samples; i++)
3599
                        buffer[i] = 0;
3600
                GList *ps = participants_list;
3601
                while(ps) {
3602
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
3603
                        janus_mutex_lock(&p->qmutex);
3604
                        if(!p->active || p->muted || p->prebuffering || !p->inbuf) {
3605
                                janus_mutex_unlock(&p->qmutex);
3606
                                ps = ps->next;
3607
                                continue;
3608
                        }
3609
                        GList *peek = g_list_first(p->inbuf);
3610
                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)(peek ? peek->data : NULL);
3611
                        if(pkt != NULL && !pkt->silence) {
3612
                                curBuffer = (opus_int16 *)pkt->data;
3613
                                for(i=0; i<samples; i++) {
3614
                                        if(p->volume_gain == 100) {
3615
                                                buffer[i] += curBuffer[i];
3616
                                        } else {
3617
                                                buffer[i] += (curBuffer[i]*p->volume_gain)/100;
3618
                                        }
3619
                                }
3620
                        }
3621
                        janus_mutex_unlock(&p->qmutex);
3622
                        ps = ps->next;
3623
                }
3624
                /* Are we recording the mix? (only do it if there's someone in, though...) */
3625
                if(audiobridge->recording != NULL && g_list_length(participants_list) > 0) {
3626
                        for(i=0; i<samples; i++) {
3627
                                /* FIXME Smoothen/Normalize instead of truncating? */
3628
                                outBuffer[i] = buffer[i];
3629
                        }
3630
                        fwrite(outBuffer, sizeof(opus_int16), samples, audiobridge->recording);
3631
                        /* Every 5 seconds we update the wav header */
3632
                        gint64 now = janus_get_monotonic_time();
3633
                        if(now - audiobridge->record_lastupdate >= 5*G_USEC_PER_SEC) {
3634
                                audiobridge->record_lastupdate = now;
3635
                                /* Update the length in the header */
3636
                                fseek(audiobridge->recording, 0, SEEK_END);
3637
                                long int size = ftell(audiobridge->recording);
3638
                                if(size >= 8) {
3639
                                        size -= 8;
3640
                                        fseek(audiobridge->recording, 4, SEEK_SET);
3641
                                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3642
                                        size += 8;
3643
                                        fseek(audiobridge->recording, 40, SEEK_SET);
3644
                                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3645
                                        fflush(audiobridge->recording);
3646
                                        fseek(audiobridge->recording, 0, SEEK_END);
3647
                                }
3648
                        }
3649
                }
3650
                /* Send proper packet to each participant (remove own contribution) */
3651
                ps = participants_list;
3652
                while(ps) {
3653
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
3654
                        janus_audiobridge_rtp_relay_packet *pkt = NULL;
3655
                        janus_mutex_lock(&p->qmutex);
3656
                        if(p->active && !p->muted && !p->prebuffering && p->inbuf) {
3657
                                GList *first = g_list_first(p->inbuf);
3658
                                pkt = (janus_audiobridge_rtp_relay_packet *)(first ? first->data : NULL);
3659
                                p->inbuf = g_list_delete_link(p->inbuf, first);
3660
                        }
3661
                        janus_mutex_unlock(&p->qmutex);
3662
                        curBuffer = (opus_int16 *)((pkt && !pkt->silence) ? pkt->data : NULL);
3663
                        for(i=0; i<samples; i++) {
3664
                                if(p->volume_gain == 100)
3665
                                        sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]) : 0);
3666
                                else
3667
                                        sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]*p->volume_gain)/100 : 0);
3668
                        }
3669
                        for(i=0; i<samples; i++)
3670
                                /* FIXME Smoothen/Normalize instead of truncating? */
3671
                                outBuffer[i] = sumBuffer[i];
3672
                        /* Enqueue this mixed frame for encoding in the participant thread */
3673
                        janus_audiobridge_rtp_relay_packet *mixedpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
3674
                        if(mixedpkt != NULL) {
3675
                                mixedpkt->data = g_malloc0(samples*2);
3676
                                memcpy(mixedpkt->data, outBuffer, samples*2);
3677
                                mixedpkt->length = samples;        /* We set the number of samples here, not the data length */
3678
                                mixedpkt->timestamp = ts;
3679
                                mixedpkt->seq_number = seq;
3680
                                mixedpkt->ssrc = audiobridge->room_id;
3681
                                g_async_queue_push(p->outbuf, mixedpkt);
3682
                        }
3683
                        if(pkt) {
3684
                                if(pkt->data)
3685
                                        g_free(pkt->data);
3686
                                pkt->data = NULL;
3687
                                g_free(pkt);
3688
                                pkt = NULL;
3689
                        }
3690
                        ps = ps->next;
3691
                }
3692
                g_list_free(participants_list);
3693
                /* Forward the mixed packet as RTP to any RTP forwarder that may be listening */
3694
                janus_mutex_lock(&audiobridge->rtp_mutex);
3695
                if(g_hash_table_size(audiobridge->rtp_forwarders) > 0 && audiobridge->rtp_encoder) {
3696
                        /* If the room is empty, check if there's any RTP forwarder with an "always on" option */
3697
                        gboolean go_on = FALSE;
3698
                        if(count == 0) {
3699
                                GHashTableIter iter;
3700
                                gpointer value;
3701
                                g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
3702
                                while(g_hash_table_iter_next(&iter, NULL, &value)) {
3703
                                        janus_audiobridge_rtp_forwarder* forwarder = (janus_audiobridge_rtp_forwarder *)value;
3704
                                        if(forwarder->always_on) {
3705
                                                go_on = TRUE;
3706
                                                break;
3707
                                        }
3708
                                }
3709
                        } else {
3710
                                go_on = TRUE;
3711
                        }
3712
                        if(go_on) {
3713
                                /* Encode the mixed frame first*/
3714
                                for(i=0; i<samples; i++)
3715
                                        outBuffer[i] = buffer[i];
3716
                                opus_int32 length = opus_encode(audiobridge->rtp_encoder, outBuffer, samples, rtpbuffer+12, 1500-12);
3717
                                if(length < 0) {
3718
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", length, opus_strerror(length));
3719
                                } else {
3720
                                        /* Then send it to everybody */
3721
                                        GHashTableIter iter;
3722
                                        gpointer key, value;
3723
                                        g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
3724
                                        while(audiobridge->rtp_udp_sock > 0 && g_hash_table_iter_next(&iter, &key, &value)) {
3725
                                                guint32 stream_id = GPOINTER_TO_UINT(key);
3726
                                                janus_audiobridge_rtp_forwarder* forwarder = (janus_audiobridge_rtp_forwarder *)value;
3727
                                                if(count == 0 && !forwarder->always_on)
3728
                                                        continue;
3729
                                                /* Update header */
3730
                                                rtph->type = forwarder->payload_type;
3731
                                                rtph->ssrc = htonl(forwarder->ssrc ? forwarder->ssrc : stream_id);
3732
                                                forwarder->seq_number++;
3733
                                                rtph->seq_number = htons(forwarder->seq_number);
3734
                                                forwarder->timestamp += 960;
3735
                                                rtph->timestamp = htonl(forwarder->timestamp);
3736
                                                /* Send RTP packet */
3737
                                                sendto(audiobridge->rtp_udp_sock, rtpbuffer, length+12, 0, (struct sockaddr*)&forwarder->serv_addr, sizeof(forwarder->serv_addr));
3738
                                        }
3739
                                }
3740
                        }
3741
                }
3742
                janus_mutex_unlock(&audiobridge->rtp_mutex);
3743
        }
3744
        if(audiobridge->recording) {
3745
                /* Update the length in the header */
3746
                fseek(audiobridge->recording, 0, SEEK_END);
3747
                long int size = ftell(audiobridge->recording);
3748
                if(size >= 8) {
3749
                        size -= 8;
3750
                        fseek(audiobridge->recording, 4, SEEK_SET);
3751
                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3752
                        size += 8;
3753
                        fseek(audiobridge->recording, 40, SEEK_SET);
3754
                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3755
                        fflush(audiobridge->recording);
3756
                        fclose(audiobridge->recording);
3757
                }
3758
        }
3759
        g_free(rtpbuffer);
3760
        JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %"SCNu64" (%s)...\n", audiobridge->room_id, audiobridge->room_name);
3761

    
3762
        /* We'll let the watchdog worry about free resources */
3763
        old_rooms = g_list_append(old_rooms, audiobridge);
3764

    
3765
        return NULL;
3766
}
3767

    
3768
/* Thread to encode a mixed frame and send it to a specific participant */
3769
static void *janus_audiobridge_participant_thread(void *data) {
3770
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread starting...\n");
3771
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)data;
3772
        if(!participant) {
3773
                JANUS_LOG(LOG_ERR, "Invalid participant!\n");
3774
                g_thread_unref(g_thread_self());
3775
                return NULL;
3776
        }
3777
        JANUS_LOG(LOG_VERB, "Thread is for participant %"SCNu64" (%s)\n", participant->user_id, participant->display ? participant->display : "??");
3778
        janus_audiobridge_session *session = participant->session;
3779

    
3780
        /* Output buffer */
3781
        janus_audiobridge_rtp_relay_packet *outpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
3782
        outpkt->data = (rtp_header *)g_malloc0(1500);
3783
        outpkt->ssrc = 0;
3784
        outpkt->timestamp = 0;
3785
        outpkt->seq_number = 0;
3786
        unsigned char *payload = (unsigned char *)outpkt->data;
3787
        memset(payload, 0, 1500);
3788

    
3789
        janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
3790

    
3791
        /* Start working: check the outgoing queue for packets, then encode and send them */
3792
        while(!g_atomic_int_get(&stopping) && session->destroyed == 0) {
3793
                if(!participant->active || !participant->encoder) {
3794
                        /* Wait until the participant is in a room */
3795
                        g_usleep(10000);
3796
                        continue;
3797
                }
3798
                if(g_async_queue_length(participant->outbuf) == 0) {
3799
                        /* Nothing to do */
3800
                        g_usleep(5000);
3801
                        continue;
3802
                }
3803
                mixedpkt = g_async_queue_pop(participant->outbuf);
3804
                if(mixedpkt != NULL && session->destroyed == 0) {
3805
                        /* Encode raw frame to Opus */
3806
                        if(participant->active && participant->encoder) {
3807
                                participant->working = TRUE;
3808
                                opus_int16 *outBuffer = (opus_int16 *)mixedpkt->data;
3809
                                outpkt->length = opus_encode(participant->encoder, outBuffer, mixedpkt->length, payload+12, BUFFER_SAMPLES-12);
3810
                                participant->working = FALSE;
3811
                                if(outpkt->length < 0) {
3812
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", outpkt->length, opus_strerror(outpkt->length));
3813
                                } else {
3814
                                        outpkt->length += 12;        /* Take the RTP header into consideration */
3815
                                        /* Update RTP header */
3816
                                        outpkt->data->version = 2;
3817
                                        outpkt->data->markerbit = 0;        /* FIXME Should be 1 for the first packet */
3818
                                        outpkt->data->seq_number = htons(mixedpkt->seq_number);
3819
                                        outpkt->data->timestamp = htonl(mixedpkt->timestamp);
3820
                                        outpkt->data->ssrc = htonl(mixedpkt->ssrc);        /* The gateway will fix this anyway */
3821
                                        /* Backup the actual timestamp and sequence number set by the audiobridge, in case a room is changed */
3822
                                        outpkt->ssrc = mixedpkt->ssrc;
3823
                                        outpkt->timestamp = mixedpkt->timestamp;
3824
                                        outpkt->seq_number = mixedpkt->seq_number;
3825
                                        janus_audiobridge_relay_rtp_packet(participant->session, outpkt);
3826
                                }
3827
                        }
3828
                        if(mixedpkt) {
3829
                                if(mixedpkt->data)
3830
                                        g_free(mixedpkt->data);
3831
                                mixedpkt->data = NULL;
3832
                                g_free(mixedpkt);
3833
                                mixedpkt = NULL;
3834
                        }
3835
                }
3836
        }
3837
        /* We're done, get rid of the resources */
3838
        if(outpkt != NULL) {
3839
                if(outpkt->data != NULL) {
3840
                        g_free(outpkt->data);
3841
                        outpkt->data = NULL;
3842
                }
3843
                g_free(outpkt);
3844
                outpkt = NULL;
3845
        }
3846
        /* Empty the outgoing queue if there was something still in */
3847
        while(g_async_queue_length(participant->outbuf) > 0) {
3848
                janus_audiobridge_rtp_relay_packet *pkt = g_async_queue_pop(participant->outbuf);
3849
                if(pkt == NULL)
3850
                        continue;
3851
                if(pkt->data)
3852
                        g_free(pkt->data);
3853
                pkt->data = NULL;
3854
                g_free(pkt);
3855
                pkt = NULL;
3856
        }
3857
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread leaving...\n");
3858
        return NULL;
3859
}
3860

    
3861
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data) {
3862
        janus_audiobridge_rtp_relay_packet *packet = (janus_audiobridge_rtp_relay_packet *)user_data;
3863
        if(!packet || !packet->data || packet->length < 1) {
3864
                JANUS_LOG(LOG_ERR, "Invalid packet...\n");
3865
                return;
3866
        }
3867
        janus_audiobridge_session *session = (janus_audiobridge_session *)data;
3868
        if(!session || !session->handle) {
3869
                // JANUS_LOG(LOG_ERR, "Invalid session...\n");
3870
                return;
3871
        }
3872
        if(!session->started) {
3873
                // JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
3874
                return;
3875
        }
3876
        janus_audiobridge_participant *participant = session->participant;
3877
        /* Set the payload type */
3878
        packet->data->type = participant->opus_pt;
3879
        /* Fix sequence number and timestamp (room switching may be involved) */
3880
        janus_rtp_header_update(packet->data, &participant->context, FALSE, 960);
3881
        if(gateway != NULL)
3882
                gateway->relay_rtp(session->handle, 0, (char *)packet->data, packet->length);
3883
        /* Restore the timestamp and sequence number to what the publisher set them to */
3884
        packet->data->timestamp = htonl(packet->timestamp);
3885
        packet->data->seq_number = htons(packet->seq_number);
3886
}