-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
Copy pathjanus_audiobridge.c
8882 lines (8690 loc) · 373 KB
/
janus_audiobridge.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*! \file janus_audiobridge.c
* \author Lorenzo Miniero <lorenzo@meetecho.com>
* \copyright GNU General Public License v3
* \brief Janus AudioBridge plugin
* \details Check the \ref audiobridge for more details.
*
* \ingroup plugins
* \ref plugins
*
* \page audiobridge AudioBridge plugin documentation
* This is a plugin implementing an audio conference bridge for
* Janus, specifically mixing Opus streams. This means that it replies
* by providing in the SDP only support for Opus, and disabling video.
* Opus encoding and decoding is implemented using libopus (http://opus.codec.org).
* The plugin provides an API to allow peers to join and leave conference
* rooms. Peers can then mute/unmute themselves by sending specific messages
* to the plugin: any way a peer mutes/unmutes, an event is triggered
* to the other participants, so that it can be rendered in the UI
* accordingly.
*
* Rooms to make available are listed in the plugin configuration file.
* A pre-filled configuration file is provided in \c conf/janus.plugin.audiobridge.jcfg
* and includes a demo room for testing.
*
* To add more rooms or modify the existing one, you can use the following
* syntax:
*
* \verbatim
room-<unique room ID>: {
description = This is my awesome room
is_private = true|false (private rooms don't appear when you do a 'list' request)
secret = <optional password needed for manipulating (e.g. destroying) the room>
pin = <optional password needed for joining the room>
sampling_rate = <sampling rate> (e.g., 16000 for wideband mixing)
spatial_audio = true|false (if true, the mix will be stereo to spatially place users, default=false)
audiolevel_ext = true|false (whether the ssrc-audio-level RTP extension must be
negotiated/used or not for new joins, default=true)
audiolevel_event = true|false (whether to emit event to other users or not, default=false)
audio_active_packets = 100 (number of packets with audio level, default=100, 2 seconds)
audio_level_average = 25 (average value of audio level, 127=muted, 0='too loud', default=25)
default_prebuffering = number of packets to buffer before decoding each participant (default=DEFAULT_PREBUFFERING)
default_expectedloss = percent of packets we expect participants may miss, to help with FEC (default=0, max=20; automatically used for forwarders too)
default_bitrate = default bitrate in bps to use for the all participants (default=0, which means libopus decides; automatically used for forwarders too)
record = true|false (whether this room should be recorded, default=false)
record_file = /path/to/recording.wav (where to save the recording)
record_dir = /path/to/ (path to save the recording to, makes record_file a relative path if provided)
mjrs = true|false (whether all participants in the room should be individually recorded to mjr files, default=false)
mjrs_dir = "/path/to/" (path to save the mjr files to)
allow_rtp_participants = true|false (whether participants should be allowed to join
via plain RTP as well, rather than just WebRTC, default=false)
groups = optional, non-hierarchical, array of groups to tag participants, for external forwarding purposes only
[The following lines are only needed if you want the mixed audio
to be automatically forwarded via plain RTP to an external component
(e.g., an ffmpeg script, or a gstreamer pipeline) for processing.
By default plain RTP is used, SRTP must be configured if needed]
rtp_forward_id = numeric RTP forwarder ID for referencing it via API (optional: random ID used if missing)
rtp_forward_host = host address to forward RTP packets of mixed audio to
rtp_forward_host_family = ipv4|ipv6; by default, first family returned by DNS request
rtp_forward_port = port to forward RTP packets of mixed audio to
rtp_forward_ssrc = SSRC to use to use when streaming (optional: stream_id used if missing)
rtp_forward_codec = opus (default), pcma (A-Law) or pcmu (mu-Law)
rtp_forward_ptype = payload type to use when streaming (optional: only read for Opus, 100 used if missing)
rtp_forward_group = group of participants to forward, if enabled in the room (optional: forwards full mix if missing)
rtp_forward_srtp_suite = length of authentication tag, if SRTP is needed (32 or 80)
rtp_forward_srtp_crypto = key to use as crypto, if SRTP is needed (base64 encoded key as in SDES)
rtp_forward_always_on = true|false, whether silence should be forwarded when the room is empty (optional: false used if missing)
}
\endverbatim
*
* \section bridgeapi Audio Bridge API
*
* The Audio Bridge API supports several requests, some of which are
* synchronous and some asynchronous. There are some situations, though,
* (invalid JSON, invalid request) which will always result in a
* synchronous error response even for asynchronous requests.
*
* \c create , \c edit , \c destroy , \c exists, \c allowed, \c kick, \c list,
* \c mute , \c unmute , \c mute_room , \c unmute_room , \c listparticipants ,
* \c resetdecoder , \c rtp_forward, \c stop_rtp_forward , \c list_forwarders ,
* \c play_file , \c is_playing and \c stop_file are synchronous requests,
* which means you'll get a response directly within the context of the
* transaction. \c create allows you to create a new audio conference bridge
* dynamically, as an alternative to using the configuration file; \c edit
* allows you to dynamically edit some room properties (e.g., the PIN);
* \c destroy removes an audio conference bridge and destroys it, kicking
* all the users out as part of the process; \c exists allows you to
* check whether a specific audio conference exists; \c allowed allows
* you to edit who's allowed to join a room via ad-hoc tokens; \c list
* lists all the available rooms, while \c listparticipants lists all
* the participants of a specific room and their details; \c resetdecoder
* marks the Opus decoder for the participant as invalid, and forces it
* to be recreated (which might be needed if the audio for generated by
* the participant becomes garbled); \c rtp_forward allows you to forward
* the mix of an AudioBridge room via RTP to a separate component (e.g.,
* for broadcasting it to a wider audience, or for processing/recording),
* whereas \c stop_rtp_forward can remove an existing forwarder; a list
* of configured forwarders for a room can be retrieved using the
* \c list_forwarders request; finally, \c play_file allows you to
* reproduce an audio .opus file in a mix (e.g., to play an announcement
* or some background music), \c is_playing checks if a specific file is
* still playing, while \c stop_file will stop such a playback instead.
*
* The \c join , \c configure , \c changeroom and \c leave requests
* instead are all asynchronous, which means you'll get a notification
* about their success or failure in an event. \c join allows you to
* join a specific audio conference bridge; \c configure can be used
* to modify some of the participation settings (e.g., mute/unmute);
* \c changeroom can be used to leave the current room and move to a
* different one without having to tear down the PeerConnection and
* recreate it again (useful for sidebars and "waiting rooms"); finally,
* \c leave allows you to leave an audio conference bridge for good.
*
* The AudioBridge plugin also allows you to forward the mix to an
* external listener, e.g., a gstreamer/ffmpeg pipeline waiting to
* process the mixer audio stream. You can add new RTP forwarders with
* the \c rtp_forward request; a \c stop_rtp_forward request removes an
* existing RTP forwarder; \c listforwarders lists all the current RTP
* forwarders on a specific AudioBridge room instance. As an alternative,
* you can configure a single static RTP forwarder in the plugin
* configuration file. A finer grained control of what to forward
* externally, in terms of participants mix, can be achieved using
* groups.
*
* \c create can be used to create a new audio room, and has to be
* formatted as follows:
*
\verbatim
{
"request" : "create",
"room" : <unique numeric ID, optional, chosen by plugin if missing>,
"permanent" : <true|false, whether the room should be saved in the config file, default=false>,
"description" : "<pretty name of the room, optional>",
"secret" : "<password required to edit/destroy the room, optional>",
"pin" : "<password required to join the room, optional>",
"is_private" : <true|false, whether the room should appear in a list request>,
"allowed" : [ array of string tokens users can use to join this room, optional],
"sampling_rate" : <sampling rate of the room, optional, 16000 by default>,
"spatial_audio" : <true|false, whether the mix should spatially place users, default=false>,
"audiolevel_ext" : <true|false, whether the ssrc-audio-level RTP extension must be negotiated for new joins, default=true>,
"audiolevel_event" : <true|false (whether to emit event to other users or not)>,
"audio_active_packets" : <number of packets with audio level (default=100, 2 seconds)>,
"audio_level_average" : <average value of audio level (127=muted, 0='too loud', default=25)>,
"default_prebuffering" : <number of packets to buffer before decoding each participant (default=DEFAULT_PREBUFFERING)>,
"default_expectedloss" : <percent of packets we expect participants may miss, to help with FEC (default=0, max=20; automatically used for forwarders too)>,
"default_bitrate" : <bitrate in bps to use for the all participants (default=0, which means libopus decides; automatically used for forwarders too)>,
"record" : <true|false, whether to record the room or not, default=false>,
"record_file" : "</path/to/the/recording.wav, optional>",
"record_dir" : "</path/to/, optional; makes record_file a relative path, if provided>",
"mjrs" : <true|false (whether all participants in the room should be individually recorded to mjr files, default=false)>,
"mjrs_dir" : "</path/to/, optional>",
"allow_rtp_participants" : <true|false, whether participants should be allowed to join via plain RTP as well, default=false>,
"groups" : [ non-hierarchical array of string group names to use to gat participants, for external forwarding purposes only, optional]
}
\endverbatim
*
* A successful creation procedure will result in a \c created response:
*
\verbatim
{
"audiobridge" : "created",
"room" : <unique numeric ID>,
"permanent" : <true if saved to config file, false if not>
}
\endverbatim
*
* If you requested a permanent room but a \c false value is returned
* instead, good chances are that there are permission problems.
*
* An error instead (and the same applies to all other requests, so this
* won't be repeated) would provide both an error code and a more verbose
* description of the cause of the issue:
*
\verbatim
{
"audiobridge" : "event",
"error_code" : <numeric ID, check Macros below>,
"error" : "<error description as a string>"
}
\endverbatim
*
* Notice that, in general, all users can create rooms. If you want to
* limit this functionality, you can configure an admin \c admin_key in
* the plugin settings. When configured, only "create" requests that
* include the correct \c admin_key value in an "admin_key" property
* will succeed, and will be rejected otherwise. Notice that you can
* optionally extend this functionality to RTP forwarding as well, in
* order to only allow trusted clients to use that feature.
*
* Once a room has been created, you can still edit some (but not all)
* of its properties using the \c edit request. This allows you to modify
* the room description, secret, pin and whether it's private or not: you
* won't be able to modify other more static properties, like the room ID,
* the sampling rate, the extensions-related stuff and so on. If you're
* interested in changing the ACL, instead, check the \c allowed message.
* An \c edit request has to be formatted as follows:
*
\verbatim
{
"request" : "edit",
"room" : <unique numeric ID of the room to edit>,
"secret" : "<room secret, mandatory if configured>",
"new_description" : "<new pretty name of the room, optional>",
"new_secret" : "<new password required to edit/destroy the room, optional>",
"new_pin" : "<new PIN required to join the room, PIN will be removed if set to an empty string, optional>",
"new_is_private" : <true|false, whether the room should appear in a list request>,
"new_record_dir" : "<new path where new recording files should be saved>",
"new_mjrs_dir" : "<new path where new MJR files should be saved>",
"permanent" : <true|false, whether the room should be also removed from the config file, default=false>
}
\endverbatim
*
* A successful edit procedure will result in an \c edited response:
*
\verbatim
{
"audiobridge" : "edited",
"room" : <unique numeric ID>
}
\endverbatim
*
* On the other hand, \c destroy can be used to destroy an existing audio
* room, whether created dynamically or statically, and has to be
* formatted as follows:
*
\verbatim
{
"request" : "destroy",
"room" : <unique numeric ID of the room to destroy>,
"secret" : "<room secret, mandatory if configured>",
"permanent" : <true|false, whether the room should be also removed from the config file, default=false>
}
\endverbatim
*
* A successful destruction procedure will result in a \c destroyed response:
*
\verbatim
{
"audiobridge" : "destroyed",
"room" : <unique numeric ID>
}
\endverbatim
*
* This will also result in a \c destroyed event being sent to all the
* participants in the audio room, which will look like this:
*
\verbatim
{
"audiobridge" : "destroyed",
"room" : <unique numeric ID of the destroyed room>
}
\endverbatim
*
* To enable or disable recording of mixed audio stream while the conference
* is in progress, you can make use of the \c enable_recording request,
* which has to be formatted as follows:
*
\verbatim
{
"request" : "enable_recording",
"room" : <unique numeric ID of the room>,
"secret" : "<room secret; mandatory if configured>"
"record" : <true|false, whether this room should be automatically recorded or not>,
"record_file" : "<file where audio recording should be saved (optional)>",
"record_dir" : "<path where audio recording file should be saved (optional)>"
}
\endverbatim
*
* A room can also be recorded by saving the individual contributions of
* participants to separate MJR files instead, in a format compatible with
* the \ref recordings. While a recording for each participant can be
* enabled or disabled separately, there also is a request to enable or
* disable them in bulk, thus implementing a feature similar to \c enable_recording
* but for MJR files, rather than for a \c .wav mix. This can be done using
* the \c enable_mjrs request, which has to be formatted as follows:
*
\verbatim
{
"request" : "enable_mjrs",
"room" : <unique numeric ID of the room>,
"secret" : "<room secret; mandatory if configured>"
"mjrs" : <true|false, whether all participants in the room should be individually recorded to mjr files or not>,
"mjrs_dir" : "<path where all MJR files should be saved to (optional)>"
}
\endverbatim
*
*
* You can check whether a room exists using the \c exists request,
* which has to be formatted as follows:
*
\verbatim
{
"request" : "exists",
"room" : <unique numeric ID of the room to check>
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID>,
"exists" : <true|false>
}
\endverbatim
*
* You can configure whether to check tokens or add/remove people who can join
* a room using the \c allowed request, which has to be formatted as follows:
*
\verbatim
{
"request" : "allowed",
"secret" : "<room secret, mandatory if configured>",
"action" : "enable|disable|add|remove",
"room" : <unique numeric ID of the room to update>,
"allowed" : [
// Array of strings (tokens users might pass in "join", only for add|remove)
]
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID>,
"allowed" : [
// Updated, complete, list of allowed tokens (only for enable|add|remove)
]
}
\endverbatim
*
* If you're the administrator of a room (that is, you created it and have access
* to the secret) you can kick participants using the \c kick request. Notice
* that this only kicks the user out of the room, but does not prevent them from
* re-joining: to ban them, you need to first remove them from the list of
* authorized users (see \c allowed request) and then \c kick them. The \c kick
* request has to be formatted as follows:
*
\verbatim
{
"request" : "kick",
"secret" : "<room secret, mandatory if configured>",
"room" : <unique numeric ID of the room>,
"id" : <unique numeric ID of the participant to kick>
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
}
\endverbatim
*
* If you're the administrator of a room (that is, you created it and have access
* to the secret) you can kick all participants using the \c kick_all request. Notice
* that this only kicks all users out of the room, but does not prevent them from
* re-joining: to ban them, you need to first remove them from the list of
* authorized users (see \c allowed request) and then perform \c kick_all.
* The \c kick_all request has to be formatted as follows:
*
\verbatim
{
"request" : "kick_all",
"secret" : "<room secret, mandatory if configured>",
"room" : <unique numeric ID of the room>
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
}
\endverbatim
*
* To get a list of the available rooms (excluded those configured or
* created as private rooms) you can make use of the \c list request,
* which has to be formatted as follows:
*
\verbatim
{
"request" : "list"
}
\endverbatim
*
* A successful request will produce a list of rooms in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"rooms" : [ // Array of room objects
{ // Room #1
"room" : <unique numeric ID>,
"description" : "<Name of the room>",
"pin_required" : <true|false, whether a PIN is required to join this room>,
"sampling_rate" : <sampling rate of the mixer>,
"spatial_audio" : <true|false, whether the mix has spatial audio (stereo)>,
"record" : <true|false, whether the room is being recorded>,
"num_participants" : <count of the participants>
},
// Other rooms
]
}
\endverbatim
*
* To get a list of the participants in a specific room, instead, you
* can make use of the \c listparticipants request, which has to be
* formatted as follows:
*
\verbatim
{
"request" : "listparticipants",
"room" : <unique numeric ID of the room>
}
\endverbatim
*
* A successful request will produce a list of participants in a
* \c participants response:
*
\verbatim
{
"audiobridge" : "participants",
"room" : <unique numeric ID of the room>,
"participants" : [ // Array of participant objects
{ // Participant #1
"id" : <unique numeric ID of the participant>,
"display" : "<display name of the participant, if any; optional>",
"setup" : <true|false, whether user successfully negotiate a WebRTC PeerConnection or not>,
"muted" : <true|false, whether user is muted or not>,
"talking" : <true|false, whether user is talking or not (only if audio levels are used)>,
"spatial_position" : <in case spatial audio is used, the panning of this participant (0=left, 50=center, 100=right)>,
},
// Other participants
]
}
\endverbatim
*
* To mark the Opus decoder context for the current participant as
* invalid and force it to be recreated, use the \c resetdecoder request:
*
\verbatim
{
"request" : "resetdecoder"
}
\endverbatim
*
* A successful request will produce a \c success response:
*
\verbatim
{
"audiobridge" : "success"
}
\endverbatim
*
* You can add a new RTP forwarder for an existing room using the
* \c rtp_forward request, which has to be formatted as follows:
*
\verbatim
{
"request" : "rtp_forward",
"room" : <unique numeric ID of the room to add the forwarder to>,
"group" : "<group to forward, if enabled in the room (forwards full mix if missing)>",
"ssrc" : <SSRC to use to use when streaming (optional: stream_id used if missing)>,
"codec" : "<opus (default), pcma (A-Law) or pcmu (mu-Law)>",
"ptype" : <payload type to use when streaming (optional: 100 used if missing)>,
"host" : "<host address to forward the RTP packets to>",
"host_family" : "<ipv4|ipv6, if we need to resolve the host address to an IP; by default, whatever we get>",
"port" : <port to forward the RTP packets to>,
"srtp_suite" : <length of authentication tag (32 or 80); optional>,
"srtp_crypto" : "<key to use as crypto (base64 encoded key as in SDES); optional>",
"always_on" : <true|false, whether silence should be forwarded when the room is empty>
}
\endverbatim
*
* The concept of "groups" is particularly important, here, in case groups were
* enabled when creating a room. By default, in fact, if a room has groups disabled,
* then an RTP forwarder will simply relay the mix of all active participants;
* sometimes, though, an external application may want to only receive the mix
* of some of the participants, and not all of them. This is what groups are
* for: if you tag participants with a specific group name, then creating a
* new forwarder that explicitly references that group name will ensure that
* only a mix of the participants tagged with that name will be forwarded.
* As such, it's important to point out groups \b only impact forwarders,
* and \c NOT participants or how they're mixed in main mix for the room itself.
* Omitting a group name when creating a forwarder for a room where groups
* are enabled will simply fall back to the default behaviour of forwarding
* the full mix.
*
* Notice that, as explained above, in case you configured an \c admin_key
* property and extended it to RTP forwarding as well, you'll need to provide
* it in the request as well or it will be rejected as unauthorized. By
* default no limitation is posed on \c rtp_forward .
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID, same as request>,
"group" : "<group to forward, same as request if provided>",
"stream_id" : <unique numeric ID assigned to the new RTP forwarder>,
"host" : "<host this forwarder is streaming to, same as request if not resolved>",
"port" : <audio port this forwarder is streaming to, same as request>
}
\endverbatim
*
* To stop a previously created RTP forwarder and stop it, you can use
* the \c stop_rtp_forward request, which has to be formatted as follows:
*
\verbatim
{
"request" : "stop_rtp_forward",
"room" : <unique numeric ID of the room to remove the forwarder from>,
"stream_id" : <unique numeric ID of the RTP forwarder>
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID, same as request>,
"stream_id" : <unique numeric ID, same as request>
}
\endverbatim
*
* To get a list of the forwarders in a specific room, instead, you
* can make use of the \c listforwarders request, which has to be
* formatted as follows:
*
\verbatim
{
"request" : "listforwarders",
"room" : <unique numeric ID of the room>
}
\endverbatim
*
* A successful request will produce a list of RTP forwarders in a
* \c forwarders response:
*
\verbatim
{
"audiobridge" : "forwarders",
"room" : <unique numeric ID of the room>,
"rtp_forwarders" : [ // Array of RTP forwarder objects
{ // RTP forwarder #1
"stream_id" : <unique numeric ID of the forwarder>,
"group" : "<group that is being forwarded, if available>",
"ip" : "<IP this forwarder is streaming to>",
"port" : <port this forwarder is streaming to>,
"ssrc" : <SSRC this forwarder is using, if any>,
"codec" : <codec this forwarder is using, if any>,
"ptype" : <payload type this forwarder is using, if any>,
"srtp" : <true|false, whether the RTP stream is encrypted>,
"always_on" : <true|false, whether this forwarder works even when no participant is in or not>
},
// Other forwarders
]
}
\endverbatim
*
* As anticipated, while the AudioBridge is mainly meant to allow real users
* to interact with each other by mixing their contributions, you can also
* start the playback of one or more pre-recorded audio files in a mix:
* this is especially useful whenever you have, for instance, to play
* an announcement of some sort, or when maybe you want to play some
* background music (e.g., some music on hold when the room is empty).
* You can start the playback of an .opus file in an existing room using
* the \c play_file request, which has to be formatted as follows:
*
\verbatim
{
"request" : "play_file",
"room" : <unique numeric ID of the room to play the file in>,
"secret" : "<room password, if configured>",
"group" : "<group to play in (for forwarding purposes only; optional, mandatory if enabled in the room)>",
"file_id": "<unique string ID of the announcement; random if not provided>",
"filename": "<path to the Opus file to play>",
"loop": <true|false, depending on whether or not the file should be played in a loop forever>
}
\endverbatim
*
* Notice that, as explained above, in case you configured an \c admin_key
* property and extended it to RTP forwarding as well, you'll need to provide
* it in the request as well or it will be rejected as unauthorized. By
* default \c play_file only requires the room secret, meaning only people
* authorized to edit the room can start an audio playback.
*
* Also notice that the only supported files are .opus files: no other
* audio format will be accepted. Besides, the file must be reachable
* and available on the file system: network addresses (e.g., HTTP URL)
* are NOT supported.
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID, same as request>,
"file_id" : "<unique string ID of the announcement, same as request if provided or randomly generated otherwise>"
}
\endverbatim
*
* As soon as the playback actually starts (usually immediately after
* the request has been sent), an event is sent to all participants so
* that they're aware something is being played back in the room besides
* themselves:
*
\verbatim
{
"audiobridge" : "announcement-started",
"room" : <unique numeric ID, same as request>,
"file_id" : "<unique string ID of the announcement>"
}
\endverbatim
*
* A similar event is also sent whenever the playback stops, whether it's
* because the file ended and \c loop was \c FALSE (which will automatically
* clear the resources) or because a \c stop_file request asked for the
* playback to be interrupted:
*
\verbatim
{
"audiobridge" : "announcement-stopped",
"room" : <unique numeric ID, same as request>,
"file_id" : "<unique string ID of the announcement>"
}
\endverbatim
*
* You can check whether a specific playback is still going on in a room,
* you can use the \c is_playing request, which has to be formatted as follows:
*
\verbatim
{
"request" : "is_playing",
"room" : <unique numeric ID of the room where the playback is taking place>,
"secret" : "<room password, if configured>",
"file_id" : "<unique string ID of the announcement>"
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID>,
"file_id" : "<unique string ID of the announcement>",
"playing" : <true|false>
}
\endverbatim
*
* As anticipated, when not looping a playback will automatically stop and
* self-destruct when it reaches the end of the audio file. In case you
* want to stop a playback sooner than that, or want to stop a looped
* playback, you can use the \c stop_file request:
*
\verbatim
{
"request" : "stop_file",
"room" : <unique numeric ID of the room where the playback is taking place>,
"secret" : "<room password, if configured>",
"file_id": "<unique string ID of the announcement>"
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID, same as request>,
"file_id" : "<unique string ID of the now interrupted announcement>"
}
\endverbatim
*
* That completes the list of synchronous requests you can send to the
* AudioBridge plugin. As anticipated, though, there are also several
* asynchronous requests you can send, specifically those related to
* joining and updating one's presence as a participant in an audio room.
*
* The way you'd interact with the plugin is usually as follows:
*
* -# you use a \c join request to join an audio room, and wait for the
* \c joined event; this event will also include a list of the other
* participants, if any;
* -# you send a \c configure request attached to an audio-only JSEP offer
* to start configuring your participation in the room (e.g., join unmuted
* or muted), and wait for the related \c event, which will be attached
* to a JSEP answer by the plugin to complete the setup of the WebRTC
* PeerConnection;
* -# you send other \c configure requests (without any JSEP-related
* attachment) to mute/unmute yourself during the audio conference;
* -# you intercept events originated by the plugin (\c joined , \c leaving )
* to notify you about users joining/leaving/muting/unmuting;
* -# you eventually send a \c leave request to leave a room; if you leave the
* PeerConnection instance intact, you can subsequently join a different
* room without requiring a new negotiation (and so just use a \c join + JSEP-less \c configure to join).
*
* Notice that there's also a \c changeroom request available: you can use
* this request to immediately leave the room you're in and join a different
* one, without requiring you to do a \c leave + \c join + \c configure
* round. Of course remember not to pass any JSEP-related payload when
* doing a \c changeroom as the same pre-existing PeerConnection will be
* re-used for the purpose.
*
* Notice that you can also ask the AudioBridge plugin to send you an offer,
* when you join, rather than providing one yourself: this means that the
* SDP offer/answer roles would be reversed, and so you'd have to provide
* an answer yourself in this case. Remember that, in case renegotiations
* or restarts take place, they MUST follow the same negotiation pattern
* as the one that originated the connection: it's an error to send an
* SDP offer to the plugin to update a PeerConnection, if the plugin sent
* you an offer originally. It's adviced to let users generate the offer,
* and let the plugin answer: this reverserd role is mostly here to
* facilitate the setup of cascaded mixers, e.g., allow one AudioBridge
* to connect to the other via WebRTC (which wouldn't be possible if
* both expected an offer from the other). Refer to the \ref aboffer
* section for more details.
*
* About the syntax of all the above mentioned requests, \c join has
* to be formatted as follows:
*
\verbatim
{
"request" : "join",
"room" : <numeric ID of the room to join>,
"id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
"group" : "<group to assign to this participant (for forwarding purposes only; optional, mandatory if enabled in the room)>",
"pin" : "<password required to join the room, if any; optional>",
"display" : "<display name to have in the room; optional>",
"token" : "<invitation token, in case the room has an ACL; optional>",
"muted" : <true|false, whether to start unmuted or muted>,
"codec" : "<codec to use, among opus (default), pcma (A-Law) or pcmu (mu-Law)>",
"prebuffer" : <number of packets to buffer before decoding this participant (default=room value, or DEFAULT_PREBUFFERING)>,
"bitrate" : <bitrate to use for the Opus stream in bps; optional, default=0 (libopus decides)>,
"quality" : <0-10, Opus-related complexity to use, the higher the value, the better the quality (but more CPU); optional, default is 4>,
"expected_loss" : <0-20, a percentage of the expected loss (capped at 20%), only needed in case FEC is used; optional, default is 0 (FEC disabled even when negotiated) or the room default>,
"volume" : <percent value, <100 reduces volume, >100 increases volume; optional, default is 100 (no volume change)>,
"spatial_position" : <in case spatial audio is enabled for the room, panning of this participant (0=left, 50=center, 100=right)>,
"secret" : "<room management password; optional, if provided the user is an admin and can't be globally muted with mute_room>",
"audio_level_average" : "<if provided, overrides the room audio_level_average for this user; optional>",
"audio_active_packets" : "<if provided, overrides the room audio_active_packets for this user; optional>",
"record": <true|false, whether to record this user's contribution to a .mjr file (mixer not involved),
"filename": "<basename of the file to record to, -audio.mjr will be added by the plugin; will be relative to mjrs_dir, if configured in the room>"
}
\endverbatim
*
* A successful request will produce a \c joined event:
*
\verbatim
{
"audiobridge" : "joined",
"room" : <numeric ID of the room>,
"id" : <unique ID assigned to the participant>,
"display" : "<display name of the new participant>",
"participants" : [
// Array of existing participants in the room
]
}
\endverbatim
*
* The other participants in the room will be notified about the new
* participant by means of a different \c joined event, which will only
* include the \c room and the new participant as the only object in
* a \c participants array.
*
* Notice that, while the AudioBridge assumes participants will exchange
* media via WebRTC, there's a less known feature that allows you to use
* plain RTP to join an AudioBridge room instead. This functionality may
* be helpful in case you want, e.g., SIP based endpoints to join an
* AudioBridge room, by crafting SDPs for the SIP dialogs yourself using
* the info exchanged with the plugin. In order to do that, you keep on
* using the API to join as a participant as explained above, but instead
* of negotiating a PeerConnection as you usually would, you add an \c rtp
* object to the \c join request, which needs to be formatted as follows:
*
\verbatim
{
"request" : "join",
[..]
"rtp" : {
"ip" : "<IP address you want media to be sent to>",
"port" : <port you want media to be sent to>,
"payload_type" : <payload type to use for RTP packets (optional; only needed in case Opus is used, automatic for G.711)>,
"audiolevel_ext" : <ID of the audiolevel RTP extension, if used (optional)>,
"fec" : <true|false, whether FEC should be enabled for the Opus stream (optional; only needed in case Opus is used)>
}
}
\endverbatim
*
* In that case, the participant will be configured to use plain RTP to
* exchange media with the room, and the \c joined event will include an
* \c rtp object as well to complete the negotiation:
*
\verbatim
{
"audiobridge" : "joined",
[..]
"rtp" : {
"ip" : "<IP address the AudioBridge will expect media to be sent to>",
"port" : <port the AudioBridge will expect media to be sent to>,
"payload_type" : <payload type to use for RTP packets (optional; only needed in case Opus is used, automatic for G.711)>
}
}
\endverbatim
*
* Notice that, after a plain RTP session has been established, the
* AudioBridge plugin will only start sending media via RTP after it
* has received at least a valid RTP packet from the remote endpoint.
*
* At this point, whether the participant will be interacting via WebRTC
* or plain RTP, the media-related settings of the participant can be
* modified by means of a \c configure request. The \c configure request
* has to be formatted as follows (notice that all parameters except
* \c request are optional, depending on what you want to change):
*
\verbatim
{
"request" : "configure",
"muted" : <true|false, whether to unmute or mute>,
"display" : "<new display name to have in the room>",
"prebuffer" : <new number of packets to buffer before decoding this participant (see "join" for more info)>,
"bitrate" : <new bitrate to use for the Opus stream (see "join" for more info)>,
"quality" : <new Opus-related complexity to use (see "join" for more info)>,
"expected_loss" : <new value for the expected loss (see "join" for more info)>
"volume" : <new volume percent value (see "join" for more info)>,
"spatial_position" : <in case spatial audio is enabled for the room, new panning of this participant (0=left, 50=center, 100=right)>,
"record": <true|false, whether to record this user's contribution to a .mjr file (mixer not involved),
"filename": "<basename of the file to record to, -audio.mjr will be added by the plugin; will be relative to mjrs_dir, if configured in the room>",
"group" : "<new group to assign to this participant, if enabled in the room (for forwarding purposes)>"
}
\endverbatim
*
* \c muted instructs the plugin to mute or unmute the participant;
* \c quality changes the complexity of the Opus encoder for the
* participant; \c record can be used to record this participant's contribution
* to a Janus .mjr file, and \c filename to provide a basename for the path to
* save the file to (notice that this is different from the recording of a whole
* room: this feature only records the packets this user is sending, and is not
* related to the mixer stuff). A successful request will result in a \c ok event:
*
\verbatim
{
"audiobridge" : "event",
"room" : <numeric ID of the room>,
"result" : "ok"
}
\endverbatim
*
* In case the \c muted property was modified, the other participants in
* the room will be notified about this by means of a \c event notification,
* which will only include the \c room and the updated participant as the
* only object in a \c participants array.
*
* If you're the administrator of a room (that is, you created it and have access to the secret)
* you can mute or unmute individual participants using the \c mute or \c unmute request
*
\verbatim
{
"request" : "<mute|unmute, whether to mute or unmute>",
"secret" : "<room secret, mandatory if configured>",
"room" : <unique numeric ID of the room>,
"id" : <unique numeric ID of the participant to mute|unmute>
}
\endverbatim
*
* A successful request will result in a success response:
*
\verbatim
{
"audiobridge" : "success",
}
\endverbatim
*
* To mute/unmute the whole room, use \c mute_room and \c unmute_room instead.
*
\verbatim
{
"request" : "<mute_room|unmute_room, whether to mute or unmute>",
"secret" : "<room secret, mandatory if configured>",
"room" : <unique numeric ID of the room>
}
\endverbatim
*
* A successful request will result in a success response:
*
\verbatim
{
"audiobridge" : "success",
}
\endverbatim
*
* As anticipated, you can leave an audio room using the \c leave request,
* which has to be formatted as follows:
*
\verbatim
{
"request" : "leave"
}
\endverbatim
*
* The leaving user will receive a \c left notification:
*
\verbatim
{
"audiobridge" : "left",
"room" : <numeric ID of the room>,
"id" : <numeric ID of the participant who left>
}
\endverbatim
*
* All the other participants will receive an \c event notification with the
* ID of the participant who just left:
*
\verbatim
{
"audiobridge" : "event",
"room" : <numeric ID of the room>,
"leaving" : <numeric ID of the participant who left>
}
\endverbatim
*
* For what concerns the \c changeroom request, instead, it's pretty much
* the same as a \c join request and as such has to be formatted as follows:
*
\verbatim
{
"request" : "changeroom",
"room" : <numeric ID of the room to move to>,
"id" : <unique ID to assign to the participant; optional, assigned by the plugin if missing>,
"group" : "<group to assign to this participant (for forwarding purposes only; optional, mandatory if enabled in the new room)>",
"display" : "<display name to have in the room; optional>",
"token" : "<invitation token, in case the new room has an ACL; optional>",
"muted" : <true|false, whether to start unmuted or muted>,
"bitrate" : <bitrate to use for the Opus stream in bps; optional, default=0 (libopus decides)>,
"quality" : <0-10, Opus-related complexity to use, higher is higher quality; optional, default is 4>,
"expected_loss" : <0-20, a percentage of the expected loss (capped at 20%), only needed in case FEC is used; optional, default is 0 (FEC disabled even when negotiated) or the room default>
}
\endverbatim
*
* Such a request will trigger all the above-described leaving/joined
* events to the other participants, as it is indeed wrapping a \c leave
* followed by a \c join and as such the other participants in both rooms
* need to be updated accordingly. The participant who switched room
* instead will be sent a \c roomchanged event which is pretty similar
* to what \c joined looks like:
*
* A successful request will produce a \c joined event:
*
\verbatim
{
"audiobridge" : "roomchanged",
"room" : <numeric ID of the new room>,
"id" : <unique ID assigned to the participant in the new room>,
"display" : "<display name of the new participant>",
"participants" : [
// Array of existing participants in the new room
]
}
\endverbatim
*
* As a last note, notice that the AudioBridge plugin does support
* renegotiations, mostly for the purpose of facilitating ICE restarts:
* in fact, there isn't much need for renegotiations outside of that
* context, as PeerConnections here will typically always contain a single
* m-line for audio, and so adding/removing streams makes no sense; besides,
* muting and unmuting is available via APIs, meaning that updating the
* media direction via SDP renegotiations would be overkill.
*
* To force a renegotiation, all you need to do is send the new JSEP
* offer together with a \c configure request: this request doesn't need
* to contain any directive at all, and can be empty. A JSEP answer will
* be sent back along the result of the request, if successful.
*
* \subsection aboffer AudioBridge-generated offers
*
* As anticipated in the previous sections, by default the AudioBridge
* plugin expects an SDP offer from users interested to join a room, and
* generates an SDP answer to complete the WebRTC negotiation process:
* this SDP offer can be provided either in a \c join request or a
* \c configure one, depending on how the app is constructed.
*
* It's worth pointing out that the AudioBridge plugin also supports
* reversed roles when it comes to negotiation: that is, a user can ask
* the plugin to generate an SDP offer first, to which they'd provide
* an SDP answer to. This slightly changes the way the negotiation works
* within the context of the AudioBridge API, as some messages may have
* to be used in a different way. More specifically, if a user wants the
* plugin to generate an offer, they'll have to include a:
*
\verbatim
[..]