Statistics
| Branch: | Revision:

janus-gateway / plugins / janus_audiobridge.c @ 8241c758

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

    
531
#include "plugin.h"
532

    
533
#include <jansson.h>
534
#include <opus/opus.h>
535
#include <sys/time.h>
536

    
537
#include "../debug.h"
538
#include "../apierror.h"
539
#include "../config.h"
540
#include "../mutex.h"
541
#include "../rtp.h"
542
#include "../rtcp.h"
543
#include "../record.h"
544
#include "../utils.h"
545

    
546

    
547
/* Plugin information */
548
#define JANUS_AUDIOBRIDGE_VERSION                        10
549
#define JANUS_AUDIOBRIDGE_VERSION_STRING        "0.0.10"
550
#define JANUS_AUDIOBRIDGE_DESCRIPTION                "This is a plugin implementing an audio conference bridge for Janus, mixing Opus streams."
551
#define JANUS_AUDIOBRIDGE_NAME                                "JANUS AudioBridge plugin"
552
#define JANUS_AUDIOBRIDGE_AUTHOR                        "Meetecho s.r.l."
553
#define JANUS_AUDIOBRIDGE_PACKAGE                        "janus.plugin.audiobridge"
554

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

    
575
/* Plugin setup */
576
static janus_plugin janus_audiobridge_plugin =
577
        JANUS_PLUGIN_INIT (
578
                .init = janus_audiobridge_init,
579
                .destroy = janus_audiobridge_destroy,
580

    
581
                .get_api_compatibility = janus_audiobridge_get_api_compatibility,
582
                .get_version = janus_audiobridge_get_version,
583
                .get_version_string = janus_audiobridge_get_version_string,
584
                .get_description = janus_audiobridge_get_description,
585
                .get_name = janus_audiobridge_get_name,
586
                .get_author = janus_audiobridge_get_author,
587
                .get_package = janus_audiobridge_get_package,
588
                
589
                .create_session = janus_audiobridge_create_session,
590
                .handle_message = janus_audiobridge_handle_message,
591
                .setup_media = janus_audiobridge_setup_media,
592
                .incoming_rtp = janus_audiobridge_incoming_rtp,
593
                .incoming_rtcp = janus_audiobridge_incoming_rtcp,
594
                .hangup_media = janus_audiobridge_hangup_media,
595
                .destroy_session = janus_audiobridge_destroy_session,
596
                .query_session = janus_audiobridge_query_session,
597
        );
598

    
599
/* Plugin creator */
600
janus_plugin *create(void) {
601
        JANUS_LOG(LOG_VERB, "%s created!\n", JANUS_AUDIOBRIDGE_NAME);
602
        return &janus_audiobridge_plugin;
603
}
604

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

    
672
/* Static configuration instance */
673
static janus_config *config = NULL;
674
static const char *config_folder = NULL;
675
static janus_mutex config_mutex;
676

    
677
/* Useful stuff */
678
static volatile gint initialized = 0, stopping = 0;
679
static gboolean notify_events = TRUE;
680
static janus_callbacks *gateway = NULL;
681
static GThread *handler_thread;
682
static GThread *watchdog;
683
static void *janus_audiobridge_handler(void *data);
684
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data);
685
static void *janus_audiobridge_mixer_thread(void *data);
686
static void *janus_audiobridge_participant_thread(void *data);
687

    
688
typedef struct janus_audiobridge_message {
689
        janus_plugin_session *handle;
690
        char *transaction;
691
        json_t *message;
692
        json_t *jsep;
693
} janus_audiobridge_message;
694
static GAsyncQueue *messages = NULL;
695
static janus_audiobridge_message exit_message;
696

    
697
static void janus_audiobridge_message_free(janus_audiobridge_message *msg) {
698
        if(!msg || msg == &exit_message)
699
                return;
700

    
701
        msg->handle = NULL;
702

    
703
        g_free(msg->transaction);
704
        msg->transaction = NULL;
705
        if(msg->message)
706
                json_decref(msg->message);
707
        msg->message = NULL;
708
        if(msg->jsep)
709
                json_decref(msg->jsep);
710
        msg->jsep = NULL;
711

    
712
        g_free(msg);
713
}
714

    
715

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

    
746
typedef struct janus_audiobridge_session {
747
        janus_plugin_session *handle;
748
        gpointer participant;
749
        gboolean started;
750
        gboolean stopping;
751
        volatile gint hangingup;
752
        gint64 destroyed;        /* Time at which this session was marked as destroyed */
753
} janus_audiobridge_session;
754
static GHashTable *sessions;
755
static GList *old_sessions;
756
static janus_mutex sessions_mutex;
757

    
758
typedef struct janus_audiobridge_rtp_context {
759
        /* Needed to fix seq and ts in case of publisher switching */
760
        uint32_t a_last_ssrc, a_last_ts, a_base_ts, a_base_ts_prev;
761
        uint16_t a_last_seq, a_base_seq, a_base_seq_prev;
762
} janus_audiobridge_rtp_context;
763

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

    
794
/* Packets we get from gstreamer and relay */
795
typedef struct janus_audiobridge_rtp_relay_packet {
796
        rtp_header *data;
797
        gint length;
798
        uint32_t ssrc;
799
        uint32_t timestamp;
800
        uint16_t seq_number;
801
        gboolean silence;
802
} janus_audiobridge_rtp_relay_packet;
803

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

    
839

    
840
/* Helper to sort incoming RTP packets by sequence numbers */
841
static gint janus_audiobridge_rtp_sort(gconstpointer a, gconstpointer b) {
842
        janus_audiobridge_rtp_relay_packet *pkt1 = (janus_audiobridge_rtp_relay_packet *)a;
843
        janus_audiobridge_rtp_relay_packet *pkt2 = (janus_audiobridge_rtp_relay_packet *)b;
844
        if(pkt1->seq_number < 100 && pkt2->seq_number > 65000) {
845
                /* Sequence number was probably reset, pkt2 is older */
846
                return 1;
847
        } else if(pkt2->seq_number < 100 && pkt1->seq_number > 65000) {
848
                /* Sequence number was probably reset, pkt1 is older */
849
                return -1;
850
        }
851
        /* Simply compare timestamps */
852
        if(pkt1->seq_number < pkt2->seq_number)
853
                return -1;
854
        else if(pkt1->seq_number > pkt2->seq_number)
855
                return 1;
856
        return 0;
857
}
858

    
859
/* SDP offer/answer template */
860
#define sdp_template \
861
                "v=0\r\n" \
862
                "o=- %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n"        /* We need current time here */ \
863
                "s=%s\r\n"                                                        /* Audio bridge name */ \
864
                "t=0 0\r\n" \
865
                "m=audio 1 RTP/SAVPF %d\r\n"                /* Opus payload type */ \
866
                "c=IN IP4 1.1.1.1\r\n" \
867
                "a=rtpmap:%d opus/48000/2\r\n"                /* Opus payload type */ \
868
                "a=fmtp:%d maxplaybackrate=%"SCNu32"; stereo=0; sprop-stereo=0; useinbandfec=0\r\n" /* Opus payload type and room sampling rate */ \
869
                "%s"                                                                /* extmap(s), if any */
870

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

    
888

    
889
/* Mixer settings */
890
#define DEFAULT_PREBUFFERING        6
891

    
892

    
893
/* Opus settings */                
894
#define        BUFFER_SAMPLES        8000
895
#define        OPUS_SAMPLES        160
896
#define USE_FEC                        0
897
#define DEFAULT_COMPLEXITY        4
898

    
899

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

    
916

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

    
996

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

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

    
1026
        /* Parse configuration to populate the rooms list */
1027
        if(config != NULL) {
1028
                /* Any admin key to limit who can "create"? */
1029
                janus_config_item *key = janus_config_get_item_drilldown(config, "general", "admin_key");
1030
                if(key != NULL && key->value != NULL)
1031
                        admin_key = g_strdup(key->value);
1032
                janus_config_item *events = janus_config_get_item_drilldown(config, "general", "events");
1033
                if(events != NULL && events->value != NULL)
1034
                        notify_events = janus_is_true(events->value);
1035
                if(!notify_events && callback->events_is_enabled()) {
1036
                        JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_AUDIOBRIDGE_NAME);
1037
                }
1038
                /* Iterate on all rooms */
1039
                GList *cl = janus_config_get_categories(config);
1040
                while(cl != NULL) {
1041
                        janus_config_category *cat = (janus_config_category *)cl->data;
1042
                        if(cat->name == NULL || !strcasecmp(cat->name, "general")) {
1043
                                cl = cl->next;
1044
                                continue;
1045
                        }
1046
                        JANUS_LOG(LOG_VERB, "Adding audio room '%s'\n", cat->name);
1047
                        janus_config_item *desc = janus_config_get_item(cat, "description");
1048
                        janus_config_item *priv = janus_config_get_item(cat, "is_private");
1049
                        janus_config_item *sampling = janus_config_get_item(cat, "sampling_rate");
1050
                        janus_config_item *audiolevel_ext = janus_config_get_item(cat, "audiolevel_ext");
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
                        if(secret != NULL && secret->value != NULL) {
1088
                                audiobridge->room_secret = g_strdup(secret->value);
1089
                        }
1090
                        if(pin != NULL && pin->value != NULL) {
1091
                                audiobridge->room_pin = g_strdup(pin->value);
1092
                        }
1093
                        audiobridge->record = FALSE;
1094
                        if(record && record->value && janus_is_true(record->value))
1095
                                audiobridge->record = TRUE;
1096
                        if(recfile && recfile->value)
1097
                                audiobridge->record_file = g_strdup(recfile->value);
1098
                        audiobridge->recording = NULL;
1099
                        audiobridge->destroy = 0;
1100
                        audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, NULL);
1101
                        audiobridge->check_tokens = FALSE;        /* Static rooms can't have an "allowed" list yet, no hooks to the configuration file */
1102
                        audiobridge->allowed = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
1103
                        audiobridge->destroyed = 0;
1104
                        janus_mutex_init(&audiobridge->mutex);
1105
                        audiobridge->rtp_forwarders = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)g_free);
1106
                        audiobridge->rtp_encoder = NULL;
1107
                        audiobridge->rtp_udp_sock = -1;
1108
                        janus_mutex_init(&audiobridge->rtp_mutex);
1109
                        JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n",
1110
                                audiobridge->room_id, audiobridge->room_name,
1111
                                audiobridge->is_private ? "private" : "public",
1112
                                audiobridge->room_secret ? audiobridge->room_secret : "no secret",
1113
                                audiobridge->room_pin ? audiobridge->room_pin : "no pin");
1114
                        /* We need a thread for the mix */
1115
                        GError *error = NULL;
1116
                        char tname[16];
1117
                        g_snprintf(tname, sizeof(tname), "mixer %"SCNu64, audiobridge->room_id);
1118
                        audiobridge->thread = g_thread_try_new(tname, &janus_audiobridge_mixer_thread, audiobridge, &error);
1119
                        if(error != NULL) {
1120
                                /* FIXME We should clear some resources... */
1121
                                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??");
1122
                        } else {
1123
                                janus_mutex_lock(&rooms_mutex);
1124
                                g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge);
1125
                                janus_mutex_unlock(&rooms_mutex);
1126
                        }
1127
                        cl = cl->next;
1128
                }
1129
                /* Done: we keep the configuration file open in case we get a "create" or "destroy" with permanent=true */
1130
        }
1131

    
1132
        /* Show available rooms */
1133
        janus_mutex_lock(&rooms_mutex);
1134
        GHashTableIter iter;
1135
        gpointer value;
1136
        g_hash_table_iter_init(&iter, rooms);
1137
        while (g_hash_table_iter_next(&iter, NULL, &value)) {
1138
                janus_audiobridge_room *ar = value;
1139
                JANUS_LOG(LOG_VERB, "  ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n",
1140
                        ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT");
1141
        }
1142
        janus_mutex_unlock(&rooms_mutex);
1143

    
1144
        g_atomic_int_set(&initialized, 1);
1145

    
1146
        GError *error = NULL;
1147
        /* Start the sessions watchdog */
1148
        watchdog = g_thread_try_new("audiobridge watchdog", &janus_audiobridge_watchdog, NULL, &error);
1149
        if(error != NULL) {
1150
                g_atomic_int_set(&initialized, 0);
1151
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge watchdog thread...\n", error->code, error->message ? error->message : "??");
1152
                janus_config_destroy(config);
1153
                return -1;
1154
        }
1155
        /* Launch the thread that will handle incoming messages */
1156
        handler_thread = g_thread_try_new("audiobridge handler", janus_audiobridge_handler, NULL, &error);
1157
        if(error != NULL) {
1158
                g_atomic_int_set(&initialized, 0);
1159
                JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", error->code, error->message ? error->message : "??");
1160
                janus_config_destroy(config);
1161
                return -1;
1162
        }
1163
        JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_AUDIOBRIDGE_NAME);
1164
        return 0;
1165
}
1166

    
1167
void janus_audiobridge_destroy(void) {
1168
        if(!g_atomic_int_get(&initialized))
1169
                return;
1170
        g_atomic_int_set(&stopping, 1);
1171

    
1172
        g_async_queue_push(messages, &exit_message);
1173
        if(handler_thread != NULL) {
1174
                g_thread_join(handler_thread);
1175
                handler_thread = NULL;
1176
        }
1177
        if(watchdog != NULL) {
1178
                g_thread_join(watchdog);
1179
                watchdog = NULL;
1180
        }
1181
        /* FIXME We should destroy the sessions cleanly */
1182
        janus_mutex_lock(&sessions_mutex);
1183
        g_hash_table_destroy(sessions);
1184
        janus_mutex_unlock(&sessions_mutex);
1185
        janus_mutex_lock(&rooms_mutex);
1186
        g_hash_table_destroy(rooms);
1187
        janus_mutex_unlock(&rooms_mutex);
1188
        g_async_queue_unref(messages);
1189
        messages = NULL;
1190
        sessions = NULL;
1191

    
1192
        janus_config_destroy(config);
1193
        g_free(admin_key);
1194

    
1195
        g_atomic_int_set(&initialized, 0);
1196
        g_atomic_int_set(&stopping, 0);
1197
        JANUS_LOG(LOG_INFO, "%s destroyed!\n", JANUS_AUDIOBRIDGE_NAME);
1198
}
1199

    
1200
int janus_audiobridge_get_api_compatibility(void) {
1201
        /* Important! This is what your plugin MUST always return: don't lie here or bad things will happen */
1202
        return JANUS_PLUGIN_API_VERSION;
1203
}
1204

    
1205
int janus_audiobridge_get_version(void) {
1206
        return JANUS_AUDIOBRIDGE_VERSION;
1207
}
1208

    
1209
const char *janus_audiobridge_get_version_string(void) {
1210
        return JANUS_AUDIOBRIDGE_VERSION_STRING;
1211
}
1212

    
1213
const char *janus_audiobridge_get_description(void) {
1214
        return JANUS_AUDIOBRIDGE_DESCRIPTION;
1215
}
1216

    
1217
const char *janus_audiobridge_get_name(void) {
1218
        return JANUS_AUDIOBRIDGE_NAME;
1219
}
1220

    
1221
const char *janus_audiobridge_get_author(void) {
1222
        return JANUS_AUDIOBRIDGE_AUTHOR;
1223
}
1224

    
1225
const char *janus_audiobridge_get_package(void) {
1226
        return JANUS_AUDIOBRIDGE_PACKAGE;
1227
}
1228

    
1229
void janus_audiobridge_create_session(janus_plugin_session *handle, int *error) {
1230
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1231
                *error = -1;
1232
                return;
1233
        }        
1234
        janus_audiobridge_session *session = (janus_audiobridge_session *)g_malloc0(sizeof(janus_audiobridge_session));
1235
        session->handle = handle;
1236
        session->started = FALSE;
1237
        session->stopping = FALSE;
1238
        session->destroyed = 0;
1239
        g_atomic_int_set(&session->hangingup, 0);
1240
        handle->plugin_handle = session;
1241
        janus_mutex_lock(&sessions_mutex);
1242
        g_hash_table_insert(sessions, handle, session);
1243
        janus_mutex_unlock(&sessions_mutex);
1244

    
1245
        return;
1246
}
1247

    
1248
void janus_audiobridge_destroy_session(janus_plugin_session *handle, int *error) {
1249
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1250
                *error = -1;
1251
                return;
1252
        }        
1253
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle; 
1254
        if(!session) {
1255
                JANUS_LOG(LOG_ERR, "No AudioBridge session associated with this handle...\n");
1256
                *error = -2;
1257
                return;
1258
        }
1259
        JANUS_LOG(LOG_VERB, "Removing AudioBridge session...\n");
1260
        janus_mutex_lock(&sessions_mutex);
1261
        if(!session->destroyed) {
1262
                g_hash_table_remove(sessions, handle);
1263
                janus_audiobridge_hangup_media(handle);
1264
                session->destroyed = janus_get_monotonic_time();
1265
                /* Cleaning up and removing the session is done in a lazy way */
1266
                old_sessions = g_list_append(old_sessions, session);
1267
        }
1268
        janus_mutex_unlock(&sessions_mutex);
1269

    
1270
        return;
1271
}
1272

    
1273
json_t *janus_audiobridge_query_session(janus_plugin_session *handle) {
1274
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized)) {
1275
                return NULL;
1276
        }        
1277
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
1278
        if(!session) {
1279
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
1280
                return NULL;
1281
        }
1282
        /* Show the participant/room info, if any */
1283
        json_t *info = json_object();
1284
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
1285
        json_object_set_new(info, "state", json_string(participant && participant->room ? "inroom" : "idle"));
1286
        if(participant) {
1287
                janus_mutex_lock(&rooms_mutex);
1288
                janus_audiobridge_room *room = participant->room;
1289
                if(room != NULL)
1290
                        json_object_set_new(info, "room", json_integer(room->room_id));
1291
                janus_mutex_unlock(&rooms_mutex);
1292
                json_object_set_new(info, "id", json_integer(participant->user_id));
1293
                if(participant->display)
1294
                        json_object_set_new(info, "display", json_string(participant->display));
1295
                json_object_set_new(info, "muted", participant->muted ? json_true() : json_false());
1296
                json_object_set_new(info, "active", participant->active ? json_true() : json_false());
1297
                json_object_set_new(info, "pre-buffering", participant->prebuffering ? json_true() : json_false());
1298
                if(participant->inbuf) {
1299
                        janus_mutex_lock(&participant->qmutex);
1300
                        json_object_set_new(info, "queue-in", json_integer(g_list_length(participant->inbuf)));
1301
                        janus_mutex_unlock(&participant->qmutex);
1302
                }
1303
                if(participant->outbuf)
1304
                        json_object_set_new(info, "queue-out", json_integer(g_async_queue_length(participant->outbuf)));
1305
                if(participant->last_drop > 0)
1306
                        json_object_set_new(info, "last-drop", json_integer(participant->last_drop));
1307
                if(participant->arc && participant->arc->filename)
1308
                        json_object_set_new(info, "audio-recording", json_string(participant->arc->filename));
1309
                if(participant->extmap_id > 0)
1310
                        json_object_set_new(info, "audio-level-dBov", json_integer(participant->dBov_level));
1311
        }
1312
        json_object_set_new(info, "started", session->started ? json_true() : json_false());
1313
        json_object_set_new(info, "destroyed", json_integer(session->destroyed));
1314
        return info;
1315
}
1316

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

    
1321
        /* Pre-parse the message */
1322
        int error_code = 0;
1323
        char error_cause[512];
1324
        json_t *root = message;
1325
        json_t *response = NULL;
1326
        
1327
        if(message == NULL) {
1328
                JANUS_LOG(LOG_ERR, "No message??\n");
1329
                error_code = JANUS_AUDIOBRIDGE_ERROR_NO_MESSAGE;
1330
                g_snprintf(error_cause, 512, "%s", "No message??");
1331
                goto plugin_response;
1332
        }
1333

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

    
2146
                g_async_queue_push(messages, msg);
2147

    
2148
                return janus_plugin_result_new(JANUS_PLUGIN_OK_WAIT, NULL, NULL);
2149
        } else {
2150
                JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
2151
                error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
2152
                g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
2153
        }
2154

    
2155
plugin_response:
2156
                {
2157
                        if(error_code == 0 && !response) {
2158
                                error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR;
2159
                                g_snprintf(error_cause, 512, "Invalid response");
2160
                        }
2161
                        if(error_code != 0) {
2162
                                /* Prepare JSON error event */
2163
                                json_t *event = json_object();
2164
                                json_object_set_new(event, "audiobridge", json_string("event"));
2165
                                json_object_set_new(event, "error_code", json_integer(error_code));
2166
                                json_object_set_new(event, "error", json_string(error_cause));
2167
                                response = event;
2168
                        }
2169
                        if(root != NULL)
2170
                                json_decref(root);
2171
                        if(jsep != NULL)
2172
                                json_decref(jsep);
2173
                        g_free(transaction);
2174

    
2175
                        return janus_plugin_result_new(JANUS_PLUGIN_OK, NULL, response);
2176
                }
2177

    
2178
}
2179

    
2180
void janus_audiobridge_setup_media(janus_plugin_session *handle) {
2181
        JANUS_LOG(LOG_INFO, "WebRTC media is now available\n");
2182
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2183
                return;
2184
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
2185
        if(!session) {
2186
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2187
                return;
2188
        }
2189
        if(session->destroyed)
2190
                return;
2191
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2192
        if(!participant)
2193
                return;
2194
        g_atomic_int_set(&session->hangingup, 0);
2195
        /* FIXME Only send this peer the audio mix when we get this event */
2196
        session->started = TRUE;
2197
}
2198

    
2199
void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, int video, char *buf, int len) {
2200
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2201
                return;
2202
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;        
2203
        if(!session || session->destroyed || session->stopping || !session->participant)
2204
                return;
2205
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2206
        if(!participant->active || participant->muted || !participant->decoder || !participant->room)
2207
                return;
2208
        /* Save the frame if we're recording this leg */
2209
        janus_recorder_save_frame(participant->arc, buf, len);
2210
        if(participant->active && participant->decoder) {
2211
                /* First of all, check if a reset on the decoder is due */
2212
                if(participant->reset) {
2213
                        /* Create a new decoder and get rid of the old one */
2214
                        int error = 0;
2215
                        OpusDecoder *decoder = opus_decoder_create(participant->room->sampling_rate, 1, &error);
2216
                        if(error != OPUS_OK) {
2217
                                JANUS_LOG(LOG_ERR, "Error resetting Opus decoder...\n");
2218
                        } else {
2219
                                if(participant->decoder)
2220
                                        opus_decoder_destroy(participant->decoder);
2221
                                participant->decoder = decoder;
2222
                                JANUS_LOG(LOG_VERB, "Opus decoder reset\n");
2223
                        }
2224
                        participant->reset = FALSE;
2225
                }
2226
                /* Decode frame (Opus -> slinear) */
2227
                rtp_header *rtp = (rtp_header *)buf;
2228
                janus_audiobridge_rtp_relay_packet *pkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
2229
                pkt->data = g_malloc0(BUFFER_SAMPLES*sizeof(opus_int16));
2230
                pkt->ssrc = 0;
2231
                pkt->timestamp = ntohl(rtp->timestamp);
2232
                pkt->seq_number = ntohs(rtp->seq_number);
2233
                /* Any audio level extension to quickly check if this is silence? */
2234
                pkt->silence = FALSE;
2235
                if(participant->extmap_id > 0) {
2236
                        int level = 0;
2237
                        if(janus_rtp_header_extension_parse_audio_level(buf, len, participant->extmap_id, &level) == 0) {
2238
                                pkt->silence = (level == 127);
2239
                                participant->dBov_level = level;
2240
                        }
2241
                }
2242
                participant->working = TRUE;
2243
                int plen = 0;
2244
                const unsigned char *payload = (const unsigned char *)janus_rtp_payload(buf, len, &plen);
2245
                if(!payload) {
2246
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error accessing the RTP payload\n");
2247
                        g_free(pkt->data);
2248
                        g_free(pkt);
2249
                        return;
2250
                }
2251
                pkt->length = opus_decode(participant->decoder, payload, plen, (opus_int16 *)pkt->data, BUFFER_SAMPLES, USE_FEC);
2252
                participant->working = FALSE;
2253
                if(pkt->length < 0) {
2254
                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", pkt->length, opus_strerror(pkt->length));
2255
                        g_free(pkt->data);
2256
                        g_free(pkt);
2257
                        return;
2258
                }
2259
                /* Enqueue the decoded frame */
2260
                janus_mutex_lock(&participant->qmutex);
2261
                /* Insert packets sorting by sequence number */
2262
                participant->inbuf = g_list_insert_sorted(participant->inbuf, pkt, &janus_audiobridge_rtp_sort);
2263
                if(participant->prebuffering) {
2264
                        /* Still pre-buffering: do we have enough packets now? */
2265
                        if(g_list_length(participant->inbuf) == DEFAULT_PREBUFFERING) {
2266
                                participant->prebuffering = FALSE;
2267
                                JANUS_LOG(LOG_VERB, "Prebuffering done! Finally adding the user to the mix\n");
2268
                        } else {
2269
                                JANUS_LOG(LOG_VERB, "Still prebuffering (got %d packets), not adding the user to the mix yet\n", g_list_length(participant->inbuf));
2270
                        }
2271
                } else {
2272
                        /* Make sure we're not queueing too many packets: if so, get rid of the older ones */
2273
                        if(g_list_length(participant->inbuf) >= DEFAULT_PREBUFFERING*2) {
2274
                                gint64 now = janus_get_monotonic_time();
2275
                                if(now - participant->last_drop > 5*G_USEC_PER_SEC) {
2276
                                        JANUS_LOG(LOG_WARN, "Too many packets in queue (%d > %d), removing older ones\n",
2277
                                                g_list_length(participant->inbuf), DEFAULT_PREBUFFERING*2);
2278
                                        participant->last_drop = now;
2279
                                }
2280
                                while(g_list_length(participant->inbuf) > DEFAULT_PREBUFFERING*2) {
2281
                                        /* Remove this packet: it's too old */
2282
                                        GList *first = g_list_first(participant->inbuf);
2283
                                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2284
                                        participant->inbuf = g_list_remove_link(participant->inbuf, first);
2285
                                        first = NULL;
2286
                                        if(pkt == NULL)
2287
                                                continue;
2288
                                        if(pkt->data)
2289
                                                g_free(pkt->data);
2290
                                        pkt->data = NULL;
2291
                                        g_free(pkt);
2292
                                        pkt = NULL;
2293
                                }
2294
                        }
2295
                }
2296
                janus_mutex_unlock(&participant->qmutex);
2297
        }
2298
}
2299

    
2300
void janus_audiobridge_incoming_rtcp(janus_plugin_session *handle, int video, char *buf, int len) {
2301
        if(handle == NULL || handle->stopped || g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2302
                return;
2303
        /* FIXME Should we care? */
2304
}
2305

    
2306
void janus_audiobridge_hangup_media(janus_plugin_session *handle) {
2307
        JANUS_LOG(LOG_INFO, "No WebRTC media anymore\n");
2308
        if(g_atomic_int_get(&stopping) || !g_atomic_int_get(&initialized))
2309
                return;
2310
        janus_audiobridge_session *session = (janus_audiobridge_session *)handle->plugin_handle;
2311
        if(!session) {
2312
                JANUS_LOG(LOG_ERR, "No session associated with this handle...\n");
2313
                return;
2314
        }
2315
        session->started = FALSE;
2316
        if(session->destroyed || !session->participant)
2317
                return;
2318
        if(g_atomic_int_add(&session->hangingup, 1))
2319
                return;
2320
        /* Get rid of participant */
2321
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
2322
        janus_mutex_lock(&rooms_mutex);
2323
        janus_audiobridge_room *audiobridge = participant->room;
2324
        if(audiobridge != NULL) {
2325
                janus_mutex_lock(&audiobridge->mutex);
2326
                json_t *event = json_object();
2327
                json_object_set_new(event, "audiobridge", json_string("event"));
2328
                json_object_set_new(event, "room", json_integer(audiobridge->room_id));
2329
                json_object_set_new(event, "leaving", json_integer(participant->user_id));
2330
                g_hash_table_remove(audiobridge->participants, &participant->user_id);
2331
                GHashTableIter iter;
2332
                gpointer value;
2333
                g_hash_table_iter_init(&iter, audiobridge->participants);
2334
                while (g_hash_table_iter_next(&iter, NULL, &value)) {
2335
                        janus_audiobridge_participant *p = value;
2336
                        if(p == participant) {
2337
                                continue;        /* Skip the leaving participant itself */
2338
                        }
2339
                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
2340
                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL);
2341
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2342
                }
2343
                json_decref(event);
2344
                /* Also notify event handlers */
2345
                if(notify_events && gateway->events_is_enabled()) {
2346
                        json_t *info = json_object();
2347
                        json_object_set_new(info, "event", json_string("left"));
2348
                        json_object_set_new(info, "room", json_integer(audiobridge->room_id));
2349
                        json_object_set_new(info, "id", json_integer(participant->user_id));
2350
                        json_object_set_new(info, "display", json_string(participant->display));
2351
                        gateway->notify_event(&janus_audiobridge_plugin, session->handle, info);
2352
                }
2353
        }
2354
        /* Get rid of the recorders, if available */
2355
        janus_mutex_lock(&participant->rec_mutex);
2356
        if(participant->arc) {
2357
                janus_recorder_close(participant->arc);
2358
                JANUS_LOG(LOG_INFO, "Closed user's audio recording %s\n", participant->arc->filename ? participant->arc->filename : "??");
2359
                janus_recorder_free(participant->arc);
2360
        }
2361
        participant->arc = NULL;
2362
        janus_mutex_unlock(&participant->rec_mutex);
2363
        /* Free the participant resources */
2364
        janus_mutex_lock(&participant->qmutex);
2365
        participant->active = FALSE;
2366
        participant->muted = TRUE;
2367
        if(participant->display)
2368
                g_free(participant->display);
2369
        participant->display = NULL;
2370
        participant->prebuffering = TRUE;
2371
        /* Make sure we're not using the encoder/decoder right now, we're going to destroy them */
2372
        while(participant->working)
2373
                g_usleep(5000);
2374
        if(participant->encoder)
2375
                opus_encoder_destroy(participant->encoder);
2376
        participant->encoder = NULL;
2377
        if(participant->decoder)
2378
                opus_decoder_destroy(participant->decoder);
2379
        participant->decoder = NULL;
2380
        participant->reset = FALSE;
2381
        /* Get rid of queued packets */
2382
        while(participant->inbuf) {
2383
                GList *first = g_list_first(participant->inbuf);
2384
                janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)first->data;
2385
                participant->inbuf = g_list_remove_link(participant->inbuf, first);
2386
                first = NULL;
2387
                if(pkt == NULL)
2388
                        continue;
2389
                if(pkt->data)
2390
                        g_free(pkt->data);
2391
                pkt->data = NULL;
2392
                g_free(pkt);
2393
                pkt = NULL;
2394
        }
2395
        participant->last_drop = 0;
2396
        janus_mutex_unlock(&participant->qmutex);
2397
        if(audiobridge != NULL) {
2398
                janus_mutex_unlock(&audiobridge->mutex);
2399
        }
2400
        janus_mutex_unlock(&rooms_mutex);
2401
}
2402

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

    
3217
                /* Prepare JSON event */
3218
                JANUS_LOG(LOG_VERB, "Preparing JSON event as a reply\n");
3219
                /* Any SDP to handle? */
3220
                const char *msg_sdp_type = json_string_value(json_object_get(msg->jsep, "type"));
3221
                const char *msg_sdp = json_string_value(json_object_get(msg->jsep, "sdp"));
3222
                if(!msg_sdp) {
3223
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, NULL);
3224
                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
3225
                        json_decref(event);
3226
                } else {
3227
                        JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg_sdp_type, msg_sdp);
3228
                        const char *type = NULL;
3229
                        if(!strcasecmp(msg_sdp_type, "offer"))
3230
                                type = "answer";
3231
                        if(!strcasecmp(msg_sdp_type, "answer"))
3232
                                type = "offer";
3233
                        /* Fill the SDP template and use that as our answer */
3234
                        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant;
3235
                        char sdp[1024];
3236
                        /* What is the Opus payload type? */
3237
                        participant->opus_pt = janus_get_codec_pt(msg_sdp, "opus");
3238
                        JANUS_LOG(LOG_VERB, "Opus payload type is %d\n", participant->opus_pt);
3239
                        /* Is the audio level extension negotiated? */
3240
                        participant->extmap_id = 0;
3241
                        participant->dBov_level = 0;
3242
                        int extmap_id = -1;
3243
                        char audio_level_extmap[100];
3244
                        if(participant->room && participant->room->audiolevel_ext)
3245
                                extmap_id = janus_rtp_header_extension_get_id(msg_sdp, JANUS_RTP_EXTMAP_AUDIO_LEVEL);
3246
                        if(extmap_id > -1) {
3247
                                participant->extmap_id = extmap_id;
3248
                                g_snprintf(audio_level_extmap, sizeof(audio_level_extmap),
3249
                                        "a=extmap:%d %s\r\n", extmap_id, JANUS_RTP_EXTMAP_AUDIO_LEVEL);
3250
                        }
3251
                        /* Prepare the response */
3252
                        g_snprintf(sdp, 1024, sdp_template,
3253
                                janus_get_real_time(),                        /* We need current time here */
3254
                                janus_get_real_time(),                        /* We need current time here */
3255
                                participant->room->room_name,        /* Audio bridge name */
3256
                                participant->opus_pt,                        /* Opus payload type */
3257
                                participant->opus_pt,                        /* Opus payload type */
3258
                                participant->opus_pt,                         /* Opus payload type and room sampling rate */
3259
                                participant->room->sampling_rate,
3260
                                extmap_id > -1 ? audio_level_extmap : "");
3261
                        /* Is the peer recvonly? */
3262
                        if(strstr(msg_sdp, "a=recvonly") != NULL) {
3263
                                /* If so, use sendonly here */
3264
                                g_strlcat(sdp, "a=sendonly\r\n", 1024);
3265
                        }
3266
                        /* Did the peer negotiate video? */
3267
                        if(strstr(msg_sdp, "m=video") != NULL) {
3268
                                /* If so, reject it */
3269
                                g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", 1024);                                
3270
                        }
3271
                        /* Did the peer negotiate data channels? */
3272
                        if(strstr(msg_sdp, "DTLS/SCTP") != NULL) {
3273
                                /* If so, reject them */
3274
                                g_strlcat(sdp, "m=application 0 DTLS/SCTP 0\r\n", 1024);
3275
                        }
3276
                        json_t *jsep = json_pack("{ssss}", "type", type, "sdp", sdp);
3277
                        /* How long will the gateway take to push the event? */
3278
                        g_atomic_int_set(&session->hangingup, 0);
3279
                        gint64 start = janus_get_monotonic_time();
3280
                        int res = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, jsep);
3281
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (took %"SCNu64" us)\n", res, janus_get_monotonic_time()-start);
3282
                        json_decref(event);
3283
                        json_decref(jsep);
3284
                        if(res != JANUS_OK) {
3285
                                /* TODO Failed to negotiate? We should remove this participant */
3286
                        } else {
3287
                                /* Notify all other participants that there's a new boy in town */
3288
                                janus_mutex_lock(&rooms_mutex);
3289
                                janus_audiobridge_room *audiobridge = participant->room;
3290
                                janus_mutex_lock(&audiobridge->mutex);
3291
                                json_t *list = json_array();
3292
                                json_t *pl = json_object();
3293
                                json_object_set_new(pl, "id", json_integer(participant->user_id));
3294
                                if(participant->display)
3295
                                        json_object_set_new(pl, "display", json_string(participant->display));
3296
                                json_object_set_new(pl, "muted", participant->muted ? json_true() : json_false());
3297
                                json_array_append_new(list, pl);
3298
                                json_t *pub = json_object();
3299
                                json_object_set_new(pub, "audiobridge", json_string("event"));
3300
                                json_object_set_new(pub, "room", json_integer(participant->room->room_id));
3301
                                json_object_set_new(pub, "participants", list);
3302
                                GHashTableIter iter;
3303
                                gpointer value;
3304
                                g_hash_table_iter_init(&iter, audiobridge->participants);
3305
                                while (g_hash_table_iter_next(&iter, NULL, &value)) {
3306
                                        janus_audiobridge_participant *p = value;
3307
                                        if(p == participant) {
3308
                                                continue;        /* Skip the new participant itself */
3309
                                        }
3310
                                        JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??");
3311
                                        int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL);
3312
                                        JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
3313
                                }
3314
                                json_decref(pub);
3315
                                participant->active = TRUE;
3316
                                janus_mutex_unlock(&audiobridge->mutex);
3317
                                janus_mutex_unlock(&rooms_mutex);
3318
                        }
3319
                }
3320
                if(msg)
3321
                        janus_audiobridge_message_free(msg);
3322
                msg = NULL;
3323

    
3324
                continue;
3325
                
3326
error:
3327
                {
3328
                        /* Prepare JSON error event */
3329
                        json_t *event = json_object();
3330
                        json_object_set_new(event, "audiobridge", json_string("event"));
3331
                        json_object_set_new(event, "error_code", json_integer(error_code));
3332
                        json_object_set_new(event, "error", json_string(error_cause));
3333
                        int ret = gateway->push_event(msg->handle, &janus_audiobridge_plugin, msg->transaction, event, NULL);
3334
                        JANUS_LOG(LOG_VERB, "  >> Pushing event: %d (%s)\n", ret, janus_get_api_error(ret));
3335
                        json_decref(event);
3336
                        janus_audiobridge_message_free(msg);
3337
                }
3338
        }
3339
        JANUS_LOG(LOG_VERB, "Leaving AudioBridge handler thread\n");
3340
        return NULL;
3341
}
3342

    
3343
/* Thread to mix the contributions from all participants */
3344
static void *janus_audiobridge_mixer_thread(void *data) {
3345
        JANUS_LOG(LOG_VERB, "Audio bridge thread starting...\n");
3346
        janus_audiobridge_room *audiobridge = (janus_audiobridge_room *)data;
3347
        if(!audiobridge) {
3348
                JANUS_LOG(LOG_ERR, "Invalid room!\n");
3349
                return NULL;
3350
        }
3351
        JANUS_LOG(LOG_VERB, "Thread is for mixing room %"SCNu64" (%s) at rate %"SCNu32"...\n", audiobridge->room_id, audiobridge->room_name, audiobridge->sampling_rate);
3352

    
3353
        /* Do we need to record the mix? */
3354
        if(audiobridge->record) {
3355
                char filename[255];
3356
                if(audiobridge->record_file)
3357
                        g_snprintf(filename, 255, "%s", audiobridge->record_file);
3358
                else
3359
                        g_snprintf(filename, 255, "/tmp/janus-audioroom-%"SCNu64".wav", audiobridge->room_id);
3360
                audiobridge->recording = fopen(filename, "wb");
3361
                if(audiobridge->recording == NULL) {
3362
                        JANUS_LOG(LOG_WARN, "Recording requested, but could NOT open file %s for writing...\n", filename);
3363
                } else {
3364
                        JANUS_LOG(LOG_VERB, "Recording requested, opened file %s for writing\n", filename);
3365
                        /* Write WAV header */
3366
                        wav_header header = {
3367
                                {'R', 'I', 'F', 'F'},
3368
                                0,
3369
                                {'W', 'A', 'V', 'E'},
3370
                                {'f', 'm', 't', ' '},
3371
                                16,
3372
                                1,
3373
                                1,
3374
                                audiobridge->sampling_rate,
3375
                                audiobridge->sampling_rate * 2,
3376
                                2,
3377
                                16,
3378
                                {'d', 'a', 't', 'a'},
3379
                                0
3380
                        };
3381
                        if(fwrite(&header, 1, sizeof(header), audiobridge->recording) != sizeof(header)) {
3382
                                JANUS_LOG(LOG_ERR, "Error writing WAV header...\n");
3383
                        }
3384
                        fflush(audiobridge->recording);
3385
                        audiobridge->record_lastupdate = janus_get_monotonic_time();
3386
                }
3387
        }
3388

    
3389
        /* Buffer (we allocate assuming 48kHz, although we'll likely use less than that) */
3390
        int samples = audiobridge->sampling_rate/50;
3391
        opus_int32 buffer[960], sumBuffer[960];
3392
        opus_int16 outBuffer[960], *curBuffer = NULL;
3393
        memset(buffer, 0, 960*4);
3394
        memset(sumBuffer, 0, 960*4);
3395
        memset(outBuffer, 0, 960*2);
3396

    
3397
        /* Base RTP packet, in case there are forwarders involved */
3398
        unsigned char *rtpbuffer = g_malloc0(1500);
3399
        rtp_header *rtph = (rtp_header *)rtpbuffer;
3400
        rtph->version = 2;
3401

    
3402
        /* Timer */
3403
        struct timeval now, before;
3404
        gettimeofday(&before, NULL);
3405
        now.tv_sec = before.tv_sec;
3406
        now.tv_usec = before.tv_usec;
3407
        time_t passed, d_s, d_us;
3408

    
3409
        /* RTP */
3410
        gint16 seq = 0;
3411
        gint32 ts = 0;
3412

    
3413
        /* Loop */
3414
        int i=0;
3415
        int count = 0, rf_count = 0, prev_count = 0;
3416
        while(!g_atomic_int_get(&stopping) && audiobridge->destroyed == 0) {        /* FIXME We need a per-room watchdog as well */
3417
                /* See if it's time to prepare a frame */
3418
                gettimeofday(&now, NULL);
3419
                d_s = now.tv_sec - before.tv_sec;
3420
                d_us = now.tv_usec - before.tv_usec;
3421
                if(d_us < 0) {
3422
                        d_us += 1000000;
3423
                        --d_s;
3424
                }
3425
                passed = d_s*1000000 + d_us;
3426
                if(passed < 15000) {        /* Let's wait about 15ms at max */
3427
                        usleep(1000);
3428
                        continue;
3429
                }
3430
                /* Update the reference time */
3431
                before.tv_usec += 20000;
3432
                if(before.tv_usec > 1000000) {
3433
                        before.tv_sec++;
3434
                        before.tv_usec -= 1000000;
3435
                }
3436
                /* Do we need to mix at all? */
3437
                janus_mutex_lock_nodebug(&audiobridge->mutex);
3438
                count = g_hash_table_size(audiobridge->participants);
3439
                rf_count = g_hash_table_size(audiobridge->rtp_forwarders);
3440
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
3441
                if((count+rf_count) == 0) {
3442
                        /* No participant and RTP forwarders, do nothing */
3443
                        if(prev_count > 0) {
3444
                                JANUS_LOG(LOG_VERB, "Last user/forwarder just left room %"SCNu64", going idle...\n", audiobridge->room_id);
3445
                                prev_count = 0;
3446
                        }
3447
                        continue;
3448
                }
3449
                if(prev_count == 0) {
3450
                        JANUS_LOG(LOG_VERB, "First user/forwarder just joined room %"SCNu64", waking it up...\n", audiobridge->room_id);
3451
                }
3452
                prev_count = count+rf_count;
3453
                /* Update RTP header information */
3454
                seq++;
3455
                ts += 960;
3456
                /* Mix all contributions */
3457
                janus_mutex_lock_nodebug(&audiobridge->mutex);
3458
                GList *participants_list = g_hash_table_get_values(audiobridge->participants);
3459
                janus_mutex_unlock_nodebug(&audiobridge->mutex);
3460
                for(i=0; i<samples; i++)
3461
                        buffer[i] = 0;
3462
                GList *ps = participants_list;
3463
                while(ps) {
3464
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
3465
                        janus_mutex_lock(&p->qmutex);
3466
                        if(!p->active || p->muted || p->prebuffering || !p->inbuf) {
3467
                                janus_mutex_unlock(&p->qmutex);
3468
                                ps = ps->next;
3469
                                continue;
3470
                        }
3471
                        GList *peek = g_list_first(p->inbuf);
3472
                        janus_audiobridge_rtp_relay_packet *pkt = (janus_audiobridge_rtp_relay_packet *)(peek ? peek->data : NULL);
3473
                        if(pkt != NULL && !pkt->silence) {
3474
                                curBuffer = (opus_int16 *)pkt->data;
3475
                                for(i=0; i<samples; i++) {
3476
                                        if(p->volume_gain == 100) {
3477
                                                buffer[i] += curBuffer[i];
3478
                                        } else {
3479
                                                buffer[i] += (curBuffer[i]*p->volume_gain)/100;
3480
                                        }
3481
                                }
3482
                        }
3483
                        janus_mutex_unlock(&p->qmutex);
3484
                        ps = ps->next;
3485
                }
3486
                /* Are we recording the mix? (only do it if there's someone in, though...) */
3487
                if(audiobridge->recording != NULL && g_list_length(participants_list) > 0) {
3488
                        for(i=0; i<samples; i++) {
3489
                                /* FIXME Smoothen/Normalize instead of truncating? */
3490
                                outBuffer[i] = buffer[i];
3491
                        }
3492
                        fwrite(outBuffer, sizeof(opus_int16), samples, audiobridge->recording);
3493
                        /* Every 5 seconds we update the wav header */
3494
                        gint64 now = janus_get_monotonic_time();
3495
                        if(now - audiobridge->record_lastupdate >= 5*G_USEC_PER_SEC) {
3496
                                audiobridge->record_lastupdate = now;
3497
                                /* Update the length in the header */
3498
                                fseek(audiobridge->recording, 0, SEEK_END);
3499
                                long int size = ftell(audiobridge->recording);
3500
                                if(size >= 8) {
3501
                                        size -= 8;
3502
                                        fseek(audiobridge->recording, 4, SEEK_SET);
3503
                                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3504
                                        size += 8;
3505
                                        fseek(audiobridge->recording, 40, SEEK_SET);
3506
                                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3507
                                        fflush(audiobridge->recording);
3508
                                        fseek(audiobridge->recording, 0, SEEK_END);
3509
                                }
3510
                        }
3511
                }
3512
                /* Send proper packet to each participant (remove own contribution) */
3513
                ps = participants_list;
3514
                while(ps) {
3515
                        janus_audiobridge_participant *p = (janus_audiobridge_participant *)ps->data;
3516
                        janus_audiobridge_rtp_relay_packet *pkt = NULL;
3517
                        janus_mutex_lock(&p->qmutex);
3518
                        if(p->active && !p->muted && !p->prebuffering && p->inbuf) {
3519
                                GList *first = g_list_first(p->inbuf);
3520
                                pkt = (janus_audiobridge_rtp_relay_packet *)(first ? first->data : NULL);
3521
                                p->inbuf = g_list_delete_link(p->inbuf, first);
3522
                        }
3523
                        janus_mutex_unlock(&p->qmutex);
3524
                        curBuffer = (opus_int16 *)((pkt && !pkt->silence) ? pkt->data : NULL);
3525
                        for(i=0; i<samples; i++) {
3526
                                if(p->volume_gain == 100)
3527
                                        sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]) : 0);
3528
                                else
3529
                                        sumBuffer[i] = buffer[i] - (curBuffer ? (curBuffer[i]*p->volume_gain)/100 : 0);
3530
                        }
3531
                        for(i=0; i<samples; i++)
3532
                                /* FIXME Smoothen/Normalize instead of truncating? */
3533
                                outBuffer[i] = sumBuffer[i];
3534
                        /* Enqueue this mixed frame for encoding in the participant thread */
3535
                        janus_audiobridge_rtp_relay_packet *mixedpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
3536
                        if(mixedpkt != NULL) {
3537
                                mixedpkt->data = g_malloc0(samples*2);
3538
                                memcpy(mixedpkt->data, outBuffer, samples*2);
3539
                                mixedpkt->length = samples;        /* We set the number of samples here, not the data length */
3540
                                mixedpkt->timestamp = ts;
3541
                                mixedpkt->seq_number = seq;
3542
                                mixedpkt->ssrc = audiobridge->room_id;
3543
                                g_async_queue_push(p->outbuf, mixedpkt);
3544
                        }
3545
                        if(pkt) {
3546
                                if(pkt->data)
3547
                                        g_free(pkt->data);
3548
                                pkt->data = NULL;
3549
                                g_free(pkt);
3550
                                pkt = NULL;
3551
                        }
3552
                        ps = ps->next;
3553
                }
3554
                g_list_free(participants_list);
3555
                /* Forward the mixed packet as RTP to any RTP forwarder that may be listening */
3556
                janus_mutex_lock(&audiobridge->rtp_mutex);
3557
                if(g_hash_table_size(audiobridge->rtp_forwarders) > 0 && audiobridge->rtp_encoder) {
3558
                        /* If the room is empty, check if there's any RTP forwarder with an "always on" option */
3559
                        gboolean go_on = FALSE;
3560
                        if(count == 0) {
3561
                                GHashTableIter iter;
3562
                                gpointer value;
3563
                                g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
3564
                                while(g_hash_table_iter_next(&iter, NULL, &value)) {
3565
                                        janus_audiobridge_rtp_forwarder* forwarder = (janus_audiobridge_rtp_forwarder *)value;
3566
                                        if(forwarder->always_on) {
3567
                                                go_on = TRUE;
3568
                                                break;
3569
                                        }
3570
                                }
3571
                        } else {
3572
                                go_on = TRUE;
3573
                        }
3574
                        if(go_on) {
3575
                                /* Encode the mixed frame first*/
3576
                                for(i=0; i<samples; i++)
3577
                                        outBuffer[i] = buffer[i];
3578
                                opus_int32 length = opus_encode(audiobridge->rtp_encoder, outBuffer, samples, rtpbuffer+12, 1500-12);
3579
                                if(length < 0) {
3580
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", length, opus_strerror(length));
3581
                                } else {
3582
                                        /* Then send it to everybody */
3583
                                        GHashTableIter iter;
3584
                                        gpointer key, value;
3585
                                        g_hash_table_iter_init(&iter, audiobridge->rtp_forwarders);
3586
                                        while(audiobridge->rtp_udp_sock > 0 && g_hash_table_iter_next(&iter, &key, &value)) {
3587
                                                guint32 stream_id = GPOINTER_TO_UINT(key);
3588
                                                janus_audiobridge_rtp_forwarder* forwarder = (janus_audiobridge_rtp_forwarder *)value;
3589
                                                if(count == 0 && !forwarder->always_on)
3590
                                                        continue;
3591
                                                /* Update header */
3592
                                                rtph->type = forwarder->payload_type;
3593
                                                rtph->ssrc = htonl(forwarder->ssrc ? forwarder->ssrc : stream_id);
3594
                                                forwarder->seq_number++;
3595
                                                rtph->seq_number = htons(forwarder->seq_number);
3596
                                                forwarder->timestamp += 960;
3597
                                                rtph->timestamp = htonl(forwarder->timestamp);
3598
                                                /* Send RTP packet */
3599
                                                sendto(audiobridge->rtp_udp_sock, rtpbuffer, length+12, 0, (struct sockaddr*)&forwarder->serv_addr, sizeof(forwarder->serv_addr));
3600
                                        }
3601
                                }
3602
                        }
3603
                }
3604
                janus_mutex_unlock(&audiobridge->rtp_mutex);
3605
        }
3606
        if(audiobridge->recording) {
3607
                /* Update the length in the header */
3608
                fseek(audiobridge->recording, 0, SEEK_END);
3609
                long int size = ftell(audiobridge->recording);
3610
                if(size >= 8) {
3611
                        size -= 8;
3612
                        fseek(audiobridge->recording, 4, SEEK_SET);
3613
                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3614
                        size += 8;
3615
                        fseek(audiobridge->recording, 40, SEEK_SET);
3616
                        fwrite(&size, sizeof(uint32_t), 1, audiobridge->recording);
3617
                        fflush(audiobridge->recording);
3618
                        fclose(audiobridge->recording);
3619
                }
3620
        }
3621
        g_free(rtpbuffer);
3622
        JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %"SCNu64" (%s)...\n", audiobridge->room_id, audiobridge->room_name);
3623

    
3624
        /* We'll let the watchdog worry about free resources */
3625
        old_rooms = g_list_append(old_rooms, audiobridge);
3626

    
3627
        return NULL;
3628
}
3629

    
3630
/* Thread to encode a mixed frame and send it to a specific participant */
3631
static void *janus_audiobridge_participant_thread(void *data) {
3632
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread starting...\n");
3633
        janus_audiobridge_participant *participant = (janus_audiobridge_participant *)data;
3634
        if(!participant) {
3635
                JANUS_LOG(LOG_ERR, "Invalid participant!\n");
3636
                g_thread_unref(g_thread_self());
3637
                return NULL;
3638
        }
3639
        JANUS_LOG(LOG_VERB, "Thread is for participant %"SCNu64" (%s)\n", participant->user_id, participant->display ? participant->display : "??");
3640
        janus_audiobridge_session *session = participant->session;
3641

    
3642
        /* Output buffer */
3643
        janus_audiobridge_rtp_relay_packet *outpkt = g_malloc0(sizeof(janus_audiobridge_rtp_relay_packet));
3644
        outpkt->data = (rtp_header *)g_malloc0(1500);
3645
        outpkt->ssrc = 0;
3646
        outpkt->timestamp = 0;
3647
        outpkt->seq_number = 0;
3648
        unsigned char *payload = (unsigned char *)outpkt->data;
3649
        memset(payload, 0, 1500);
3650

    
3651
        janus_audiobridge_rtp_relay_packet *mixedpkt = NULL;
3652

    
3653
        /* Start working: check the outgoing queue for packets, then encode and send them */
3654
        while(!g_atomic_int_get(&stopping) && session->destroyed == 0) {
3655
                if(!participant->active || !participant->encoder) {
3656
                        /* Wait until the participant is in a room */
3657
                        g_usleep(10000);
3658
                        continue;
3659
                }
3660
                if(g_async_queue_length(participant->outbuf) == 0) {
3661
                        /* Nothing to do */
3662
                        g_usleep(5000);
3663
                        continue;
3664
                }
3665
                mixedpkt = g_async_queue_pop(participant->outbuf);
3666
                if(mixedpkt != NULL && session->destroyed == 0) {
3667
                        /* Encode raw frame to Opus */
3668
                        if(participant->active && participant->encoder) {
3669
                                participant->working = TRUE;
3670
                                opus_int16 *outBuffer = (opus_int16 *)mixedpkt->data;
3671
                                outpkt->length = opus_encode(participant->encoder, outBuffer, mixedpkt->length, payload+12, BUFFER_SAMPLES-12);
3672
                                participant->working = FALSE;
3673
                                if(outpkt->length < 0) {
3674
                                        JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error encoding the Opus frame: %d (%s)\n", outpkt->length, opus_strerror(outpkt->length));
3675
                                } else {
3676
                                        outpkt->length += 12;        /* Take the RTP header into consideration */
3677
                                        /* Update RTP header */
3678
                                        outpkt->data->version = 2;
3679
                                        outpkt->data->markerbit = 0;        /* FIXME Should be 1 for the first packet */
3680
                                        outpkt->data->seq_number = htons(mixedpkt->seq_number);
3681
                                        outpkt->data->timestamp = htonl(mixedpkt->timestamp);
3682
                                        outpkt->data->ssrc = htonl(mixedpkt->ssrc);        /* The gateway will fix this anyway */
3683
                                        /* Backup the actual timestamp and sequence number set by the audiobridge, in case a room is changed */
3684
                                        outpkt->ssrc = mixedpkt->ssrc;
3685
                                        outpkt->timestamp = mixedpkt->timestamp;
3686
                                        outpkt->seq_number = mixedpkt->seq_number;
3687
                                        janus_audiobridge_relay_rtp_packet(participant->session, outpkt);
3688
                                }
3689
                        }
3690
                        if(mixedpkt) {
3691
                                if(mixedpkt->data)
3692
                                        g_free(mixedpkt->data);
3693
                                mixedpkt->data = NULL;
3694
                                g_free(mixedpkt);
3695
                                mixedpkt = NULL;
3696
                        }
3697
                }
3698
        }
3699
        /* We're done, get rid of the resources */
3700
        if(outpkt != NULL) {
3701
                if(outpkt->data != NULL) {
3702
                        g_free(outpkt->data);
3703
                        outpkt->data = NULL;
3704
                }
3705
                g_free(outpkt);
3706
                outpkt = NULL;
3707
        }
3708
        /* Empty the outgoing queue if there was something still in */
3709
        while(g_async_queue_length(participant->outbuf) > 0) {
3710
                janus_audiobridge_rtp_relay_packet *pkt = g_async_queue_pop(participant->outbuf);
3711
                if(pkt == NULL)
3712
                        continue;
3713
                if(pkt->data)
3714
                        g_free(pkt->data);
3715
                pkt->data = NULL;
3716
                g_free(pkt);
3717
                pkt = NULL;
3718
        }
3719
        JANUS_LOG(LOG_VERB, "AudioBridge Participant thread leaving...\n");
3720
        return NULL;
3721
}
3722

    
3723
static void janus_audiobridge_relay_rtp_packet(gpointer data, gpointer user_data) {
3724
        janus_audiobridge_rtp_relay_packet *packet = (janus_audiobridge_rtp_relay_packet *)user_data;
3725
        if(!packet || !packet->data || packet->length < 1) {
3726
                JANUS_LOG(LOG_ERR, "Invalid packet...\n");
3727
                return;
3728
        }
3729
        janus_audiobridge_session *session = (janus_audiobridge_session *)data;
3730
        if(!session || !session->handle) {
3731
                // JANUS_LOG(LOG_ERR, "Invalid session...\n");
3732
                return;
3733
        }
3734
        if(!session->started) {
3735
                // JANUS_LOG(LOG_ERR, "Streaming not started yet for this session...\n");
3736
                return;
3737
        }
3738
        janus_audiobridge_participant *participant = session->participant;
3739
        /* Set the payload type */
3740
        packet->data->type = participant->opus_pt;
3741
        /* Fix sequence number and timestamp (room switching may be involved) */
3742
        if(ntohl(packet->data->ssrc) != participant->context.a_last_ssrc) {
3743
                participant->context.a_last_ssrc = ntohl(packet->data->ssrc);
3744
                participant->context.a_base_ts_prev = participant->context.a_last_ts;
3745
                participant->context.a_base_ts = packet->timestamp;
3746
                participant->context.a_base_seq_prev = participant->context.a_last_seq;
3747
                participant->context.a_base_seq = packet->seq_number;
3748
        }
3749
        /* Compute a coherent timestamp and sequence number */
3750
        participant->context.a_last_ts = (packet->timestamp-participant->context.a_base_ts)
3751
                + participant->context.a_base_ts_prev+960;        /* FIXME When switching, we assume Opus and so a 960 ts step */
3752
        participant->context.a_last_seq = (packet->seq_number-participant->context.a_base_seq)+participant->context.a_base_seq_prev+1;
3753
        /* Update the timestamp and sequence number in the RTP packet, and send it */
3754
        packet->data->timestamp = htonl(participant->context.a_last_ts);
3755
        packet->data->seq_number = htons(participant->context.a_last_seq);
3756
        if(gateway != NULL)
3757
                gateway->relay_rtp(session->handle, 0, (char *)packet->data, packet->length);
3758
        /* Restore the timestamp and sequence number to what the publisher set them to */
3759
        packet->data->timestamp = htonl(packet->timestamp);
3760
        packet->data->seq_number = htons(packet->seq_number);
3761
}